Repository navigation
feat(ai): accept "provider/model" strings as models - #60514
rekram1-node wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
The change works as described. I ran the new model-string tests and the full packages/ai suite, and all pass. The package's typecheck script needs bun check, which wasn't available here, so I ran its tsc fallback for both configs (including the new *.types.ts) instead; it passes. I also type-checked packages/core, which uses this package, and it passes. Strings resolve lazily inside the Effect, failures come back as a typed InvalidRequest, Object.hasOwn rejects names like constructor/x, and model objects and already-built requests are passed through unchanged.
Public API (@opencode/ai, backwards compatible):
modelnow also accepts a"provider/model"string in:LLM.generate,stream,loopandgenerateObjectImage.generate,stream,startandresumeDecision.generate- the matching
ai.llm,ai.imageandai.decisionmethods
- The
Modelconstraints ofRequestInput,LoopInput,GenerateObjectOptions,GenerateObjectDynamicOptions,ImageRequestInputandDecisionRequestInputwiden fromXtoX | string. LanguageModelProviderOptions,ImageModelOptionsandDecisionModelOptionsnow mapstringto the untyped options instead ofnever.LLM.requestandcompactstill need a model object.
Existing callers that pass model objects are unaffected.
One small inline note on the type test.
| const ids = ["openai/gpt-5.4-nano", "anthropic/claude-haiku-4-5"] as const | ||
| declare const configured: string | ||
|
|
||
| LLM.generate({ model: "openai/gpt-5.4", prompt: "Hi", providerOptions: { openai: { store: false } } }) |
There was a problem hiding this comment.
providerOptions is flat everywhere else (it goes to the route as-is, e.g. request.providerOptions?.store), so { openai: { store: false } } only type-checks because string models take an untyped Record<string, unknown>. At runtime it sends an openai key that the OpenAI route ignores. Could this use the flat shape ({ store: false }), so the test doesn't suggest a namespaced form that doesn't work?
There was a problem hiding this comment.
The new commit fixes my earlier point: the string-model type test now uses flat providerOptions. The type-test config (tsconfig.types.json) still passes, and I have nothing new to flag. The public API impact is the same as before: model also accepts "provider/model" strings, and existing code that passes model objects still works.
I made
modelaccept a"provider/model"string anywhere a text, image, or decision model is accepted, in both the Promise and Effect APIs. A model object still works for anything that needs settings.The text before the first
/picks the provider and the rest is the model id, soopenrouter/openai/gpt-5.4sendsopenai/gpt-5.4to OpenRouter. The string loads that provider's defaultmodel,imageModelordecisionModelwith its env key and no settings. Each provider module is imported only when a string names it, inside the Effect, so failures are a typedAIError:/: lists the known idsProvider "anthropic" has no image modelsazure/...: the provider's own error (requires resourceName or baseURL)Provider options for a string model are untyped.
LLM.requeststill needs a model object because it builds the request synchronously, and so doescompact, which takes a built request. This is a stopgap until strings resolve through a bundled catalog.Accepted ids are each provider module's
id, plus these models.dev ids where ours differ:fireworks-aifireworksvercelvercel-ai-gatewaygoogle-vertex-anthropicgoogle-vertex(Messages API)Visual
Added by the opencode bot (AI-generated).
Public API:
modelaccepts "provider/model" strings in the LLM, Image and Decision APIs and the ai client (backwards compatible)