Skip to content

feat: add multimodal Skills for keyed Providers - #252

Merged
yujiezhang-ops merged 18 commits into
mainfrom
codex/multimodal-skills
Oct 10, 2026
Merged

yujiezhang-ops merged 18 commits into
mainfrom
codex/multimodal-skills

Conversation

@yujiezhang-ops

Copy link
Copy Markdown
Collaborator

Summary

Adds multimodal capabilities: BootAgent detects which models on keyed Providers can understand images, video or audio, or generate images, speech and video, and installs a generated Skill for each into Claude Code, Codex, OpenCode and other Agents. Agents without a Skills directory get guide files under ~/.bootagent/multimodal/. Design and credential delivery are recorded in docs/multimodal-skills-design.md.

The branch also carries a few independent changes made along the way: on-demand Profile model checks, Kimi Code Desktop as an installable Agent, ChatGPT desktop version recovery from AppX, and a fix for npm commands falsely reported as stalled.

Review fixes (last 5 commits)

The full-branch review found 3 P1 and 8 P2 issues; each is fixed with a regression test.

  • P1 Concurrent install could pair an old endpoint with a new key: install now re-checks the Provider after taking the write lock.
  • P1 Successful text responses (vision, transcription, video understanding) skipped key redaction.
  • P1 Default output inside the Skill directory changed its hash and blocked reinstall/uninstall; output now defaults to ~/.bootagent/output.
  • P2 Long transcripts were truncated at 64 KiB by process.exit.
  • P2 Concurrent video downloads in the same second shared one .part file.
  • P2 Transfer import and key-only writes (Profile, Agent activation, install) did not refresh generated Skills.
  • P2 Malformed 200 speech responses were cached as supported.
  • P2 A late model check could revert a newer Profile save.
  • P2 No install targets disabled the dialog, blocking guide-only installs.
  • P2 Manual probe results were hidden when a same-capability row existed.
  • P2 Closing the install dialog mid-install lost its result and refresh.

Tests

  • go vet ./..., go test ./..., staticcheck ./... pass; go test -race passes for internal/app, internal/skillgen, internal/provider
  • Each of the 3 Go fix commits passes internal/app, internal/skillgen, internal/provider tests on its own
  • Frontend: 70 files / 580 tests pass; pnpm run build succeeds
  • E2E: 13 passed. One run of Marketplace detail back restores the search and filter session failed once and passed on 4 reruns; unrelated to this change
  • Windows/Linux cross-compile only; not run natively on those systems

Locally, pnpm run test:e2e times out unless the Go caches are passed through, because e2e/wails-server.mjs replaces HOME:

GOMODCACHE="$(go env GOMODCACHE)" GOCACHE="$(go env GOCACHE)" GOPATH="$(go env GOPATH)" pnpm run test:e2e

🤖 Generated with Claude Code

yujiezhang-ops and others added 18 commits October 9, 2026 13:54
A command that exited 0 could still be reported as stalled: a process it
left behind kept the output pipes open, so Wait blocked until the stall
watchdog fired. Run now starts the command in its own process tree, stops
reading the pipes a few seconds after the command exits, and treats a
clean exit as success whatever the watchdog did meanwhile.

npm prints nothing while it downloads, which the watchdog also read as a
stall. Install and update now pass npm's cache and install directories as
activity paths, and growth under them counts as progress.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model the provider lists can still be refused when an Agent calls it,
and a Profile edit rewrites every Agent bound to it at once, so a single
model change could break Claude Code and Codex with nothing said.

Profile cards and the Agent's Profile page now have a 检测模型 button that
sends one live request per protocol the Agents use and reports the
verdict: available, unavailable (refused model or rejected key), or
unverified (network, rate limit, server error). A failure offers the next
step that fits its cause: switching back to the model the page just
replaced, fixing the key, or checking again.

Saving and applying a Profile never check on their own: each check is a
billed request, so the user decides when it goes out. Inline model saves
on the Agent's Profile page now also report Agents they could not
rewrite, and 应用 waits for an in-flight model save instead of applying
the stale model.

The probe result carries the provider's own error message, cleaned,
bounded and with the API key scrubbed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Opening the editor on the Providers, Profiles and Agent Profile pages
left the full list and the last save's notices rendered below the form,
which read as the previous page appended to the editor. The editor now
replaces the list until it is saved or cancelled, and opens scrolled to
the top so a card's editor is not left above the fold.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add the multimodal Skills design, ADR-011 for delivering Provider keys to
generated Skills as Agent environment variables, and trimmed public
/models snapshots of Novita, PPIO and JieKou.AI for replay tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add modalities.lock.json with the ID rules and native routes, and a
modality package that resolves each listed model's capabilities in the
order probe verdict, declared metadata, ID rule. ListModels now keeps
the declared modality lists, and the capability cache moves to schema
2 with per-model modality verdicts while still reading version 1.

A MultimodalService exposes Detect, an unbilled model listing, and
Probe, a one-token image request sent only from a button. The Skills
page gets a Multimodal capabilities section that shows each finding's
source and whether it can be installed yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Generate a Skill per capability (SKILL.md, config.json and a
dependency-free run.mjs) for image understanding, image generation,
speech-to-text and text-to-speech over the OpenAI-compatible routes,
store it as a generated variant, and publish it to the chosen Agents.

The Provider key reaches the script as BOOTAGENT_<PROVIDER>_API_KEY in
Claude Code's env block and Codex's shell_environment_policy.set, with
a private fallback file for other Agents (ADR-011). One reconcile keeps
those variables matching the generated Skills after install, uninstall,
Skills page changes and Provider edits; only variants rendered here
earn a key. config.toml is written as a secret once it holds one.

Add probes for transcription, speech and image generation; the image
probe needs an explicit confirmation. Models can be entered by hand and
install once their probe passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add the routes Novita, PPIO and JieKou.AI document for one shared
native API family: synchronous MiniMax Speech (novita-audio) and async
submit, poll and download (novita-async). run.mjs gains a native speak
and a video command that paces polling by the provider's eta, streams
the result to disk without the key, and exits 7 with the task ID when a
run outlasts its timeout, so video-result can collect it without paying
again.

The catalog now lists only models whose request was read from vendor
docs: MiniMax Speech on all three, GPT Image and two text-to-video
models on JieKou.AI, and ming-image on Novita. A catalog entry outranks
a declaration for the capabilities it names. PPIO and Novita no longer
document video generation, so it is marked unsupported for both and the
ppio-video adapter stays reserved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Answer questions about a local video by sampling frames with ffmpeg
and sending them to an image-understanding model, which lends the
capability its own evidence. ffmpeg runs with an argv array, a timeout
and PATH alone. Native video content parts stay probe-only: Moonshot
takes video only as an uploaded file, not a data URL.

Offer OpenCode as an install target on the private fallback key file,
since neither OpenCode nor Hermes documents a way to set its shell
tool's environment. Hermes is held back pending the decision on Node.

Agents without a Skills directory can get the same tree as a guide in
~/.bootagent/multimodal/<capability>/ with a prompt pointing at it.
The guide is found by its hash rather than registered as a target, and
follows the Skill through key changes, Provider deletes and uninstall.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
When Get-AppxPackage returns nothing or fails, look the package family up
through PackageManager.FindPackagesForUser before reporting the version as
unavailable. The family is passed through the environment, never interpolated
into the script. If metadata is still missing, the card says launch can still
be attempted and that version detection is unrelated to model API support.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model check refused over the Responses API now explains that Codex needs a
Responses model and offers a button to the API protocol adapter. Other
reasons and protocols keep their existing remedies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Below a long Skill library the section was out of sight. It now has a
sidebar entry at /multimodal, and the Skills page links to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Install reads the vendor's electron-updater feed, resolving its relative URLs
against code.kimi.com and keeping downloads on code.kimi.com or cdn.kimi.com.
On macOS it verifies the zip's SHA-512 and checks the bundle ID
com.kimi.code.desktop, the Developer ID team 2J9472RW75 and notarization
before copying the app into Applications. On Windows it verifies the
installer's digest and its Authenticode publisher, NOVASCENT PRIVATE LIMITED
(the signer of the vendor's published installer, pinned deliberately), then
starts the NSIS installer.

The app shares ~/.kimi-code/config.toml with the Kimi Code CLI, so applying a
Profile to it activates the kimi-code Agent. The card reuses the Kimi mark.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Generated images, audio and video now default to ~/.bootagent/output
instead of bootagent-output in the working directory. The Skill templates
told Agents to run from the Skill directory, so the first generation
changed the managed tree's hash and blocked later reinstall, model
switches, endpoint refreshes and uninstall.

The script also:
- redacts successful text responses (vision, transcription, video
  understanding) before printing them
- sets process.exitCode instead of calling process.exit, so long
  transcripts written to a pipe are not truncated
- writes each result to its own temporary directory and publishes it
  with a hard link, so concurrent downloads in the same second never
  share a .part file or replace each other's output

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A 200 response whose body could not be read, was not JSON, lacked
base_resp.status_code or carried no decodable audio was reported as a
supported speech route and cached. These now classify as a transient
failure, so the capability stays unverified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- InstallMultimodal re-reads the Provider after taking writeMu and
  refuses with a retryable error if it changed while models were being
  listed, so a Skill never pairs an old endpoint with a new key.
- Key writes from Profile save, Agent activation and install now refresh
  generated Skills like SaveProvider does, and report refresh failures.
- v2 transfer imports refresh generated Skills for every Provider they
  change, and roll those Skill trees and credential files back if the
  refresh fails.
- Key reconciliation never hands a new key to a Skill that still points
  at a previous endpoint, and reports registry and catalog read failures
  instead of silently succeeding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model check that resolved after a later save could still offer to
switch back, and reverting overwrote the newer model. Every save now
invalidates in-flight checks, and reverting first confirms the Profile
still holds the checked model.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- The install button opens the dialog even with no install targets, so
  users can still generate the guide files for other Agents.
- A manual probe's result or error is shown unless the same model's
  result is already shown in its capability row.
- The install dialog cannot be closed while an installation is running,
  so its result and the follow-up refresh are never lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@yujiezhang-ops
yujiezhang-ops requested a review from a team October 10, 2026 03:23
@yujiezhang-ops
yujiezhang-ops merged commit f64b6c4 into main Oct 10, 2026
4 checks passed
@yujiezhang-ops
yujiezhang-ops deleted the codex/multimodal-skills branch October 10, 2026 03:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant