-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(opencode): advertise per-model image capabilities in the exported config #4300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,6 +72,39 @@ export function inputModalitiesForClient( | |
| return kept.length > 0 ? kept : null; | ||
| } | ||
|
|
||
| /** | ||
| * Input modalities opencode's model schema accepts (opencode.ai/config.json, both | ||
| * `modalities.input` and `modalities.output`). Wider than our internal `text | image | audio` | ||
| * vocabulary, so unlike Pi and Gajae this filter can only drop a value no current ingress | ||
| * produces: `/api/custom-models`, `ocx models add` and the catalog writer all normalize to | ||
| * the internal three. It exists so a future ingress cannot do to opencode what `audio` did | ||
| * to Gajae, whose loader rejected the whole config file over one out-of-enum value. | ||
| */ | ||
| const OPENCODE_INPUT_MODALITIES: ReadonlySet<string> = new Set(["text", "audio", "image", "video", "pdf"]); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a live or custom catalog row declares Useful? React with 👍 / 👎. |
||
|
|
||
| /** | ||
| * opencode's per-model capability fields for one catalog row, or `undefined` when the row | ||
| * declares nothing. | ||
| * | ||
| * `undefined` rather than `{ input: ["text"] }`: opencode already computes an entry without | ||
| * capabilities as text-only, and leaving the keys out keeps every model that declares | ||
| * nothing byte-identical to what shipped before. A declared list is carried across as-is, so | ||
| * an audio-only row keeps `attachment: true` instead of being rewritten to text it cannot | ||
| * read — the same call Pi's exporter makes, in the opposite direction. | ||
| */ | ||
| export function opencodeModelCapabilities( | ||
| modalities: readonly string[] | undefined, | ||
| ): { attachment: boolean; modalities: { input: string[]; output: string[] } } | undefined { | ||
| const input: string[] = []; | ||
| for (const value of modalities ?? []) { | ||
| if (OPENCODE_INPUT_MODALITIES.has(value) && !input.includes(value)) input.push(value); | ||
| } | ||
| if (input.length === 0) return undefined; | ||
| // `attachment` is what opencode's client gates pasting on; `modalities` refines it into | ||
| // which kinds. Output is always text — nothing in the catalog declares otherwise. | ||
| return { attachment: input.some(value => value !== "text"), modalities: { input, output: ["text"] } }; | ||
| } | ||
|
|
||
| /** | ||
| * Label shared by every client: `"<displayName|id> (<native|provider|routed>)"`. The | ||
| * provider suffix is what makes two same-named models from different upstreams | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes the capability contract and serialization behavior of the owned
src/clients/subsystem, whichstructure/INDEX.mdmaps tostructure/clients/integrations.md, but that document remains unchanged and therefore does not record how OpenCode modalities and attachment support are derived. Update the mapped structure document alongside this implementation so the architecture source of truth includes the new invariant.AGENTS.md reference: src/AGENTS.md:L11-L11
Useful? React with 👍 / 👎.