refactor(llm): collapse Endpoint to path-only; require ModelRef.baseURL
Push URL host knowledge from `Endpoint` (route layer) up to `model.baseURL`
(provider helper layer). The route just composes a path onto whatever
host the model already carries.
Endpoint:
- `Endpoint<Body>` shrinks to `{ path }`. No more `default`, `baseURL`,
or `required` fallback fields.
- `Endpoint.path(value)` replaces the old `Endpoint.baseURL({...})` factory.
- `Endpoint.render()` is now sync — `${model.baseURL}${path}` plus query
params. No fallback chain, no Effect wrapper.
ModelRef:
- `ModelRef.baseURL: Schema.String` (was optional). Every materialized
model carries a host.
- `RouteModelInput.baseURL?: string` stays optional so route defaults
can supply a canonical URL; routes without a default tighten it.
Provider helpers:
- Each protocol exports a `DEFAULT_BASE_URL` constant and bakes it into
`route.defaults.baseURL`. Provider helpers don't need to set baseURL.
- Azure uses a new `AtLeastOne<T>` helper from `auth-options.ts` to
require either `resourceName` or `baseURL` at the type level.
- Bedrock provider computes baseURL from `region` at construction time.
- OpenAI-compatible profiles now have required (not optional) `baseURL`
in their type — all 9 already supplied one.
- The `defaultBaseURL: string | false` knob on protocol endpoint
factories is gone.
Effects:
- Forgetting baseURL is now caught at compile time (TS) or model
construction time (modelWithDefaults runtime check), not request time.
- `Endpoint.render` no longer needs Effect wrapping in the transport
hot path.
This commit is contained in:
@@ -179,17 +179,22 @@ const PROVIDERS: Record<string, ProviderModel> = {
|
||||
Anthropic.model(String(input.model.api.id), sharedOptions(input, options, { protocol: "anthropic-messages" })),
|
||||
"@ai-sdk/azure": (input, options) => {
|
||||
const create = options.useCompletionUrls === true ? Azure.chat : Azure.responses
|
||||
// Azure requires at least one of `resourceName` or `baseURL`. The user's
|
||||
// config supplies one of them via opencode's provider settings; if neither
|
||||
// is set we let Azure's runtime check surface a clear error.
|
||||
return create(String(input.model.api.id), {
|
||||
...sharedOptions(input, options, { protocol: azureProtocol(options), providerOptions: openAIOptions(options) }),
|
||||
resourceName: stringOption(options, "resourceName"),
|
||||
apiVersion: stringOption(options, "apiVersion"),
|
||||
})
|
||||
} as Azure.ModelOptions)
|
||||
},
|
||||
"@ai-sdk/baseten": openAICompatibleModel,
|
||||
"@ai-sdk/cerebras": openAICompatibleModel,
|
||||
"@ai-sdk/deepinfra": openAICompatibleModel,
|
||||
"@ai-sdk/fireworks": openAICompatibleModel,
|
||||
"@ai-sdk/github-copilot": (input, options) =>
|
||||
// GitHub Copilot has no canonical public URL; the user's opencode config
|
||||
// is expected to supply `baseURL`. Runtime check kicks in if it's missing.
|
||||
GitHubCopilot.model(
|
||||
String(input.model.api.id),
|
||||
{
|
||||
@@ -197,7 +202,7 @@ const PROVIDERS: Record<string, ProviderModel> = {
|
||||
protocol: GitHubCopilot.shouldUseResponsesApi(String(input.model.api.id)) ? "openai-responses" : "openai-chat",
|
||||
providerOptions: openAIOptions(options),
|
||||
}),
|
||||
},
|
||||
} as GitHubCopilot.ModelOptions,
|
||||
),
|
||||
"@ai-sdk/google": (input, options) =>
|
||||
Google.model(String(input.model.api.id), sharedOptions(input, options, { protocol: "gemini" })),
|
||||
|
||||
@@ -7,7 +7,7 @@ const types = (events: ReadonlyArray<{ readonly type: string }>) => events.map((
|
||||
describe("LLMNativeEvents", () => {
|
||||
test("synthesizes text and reasoning boundaries around native deltas", () => {
|
||||
const events = LLMNativeEvents.toSessionEvents([
|
||||
{ type: "request-start", id: "req_1", model: LLM.model({ id: "gpt-5", provider: "openai", route: "openai-responses" }) },
|
||||
{ type: "request-start", id: "req_1", model: LLM.model({ id: "gpt-5", provider: "openai", route: "openai-responses", baseURL: "https://api.openai.com/v1" }) },
|
||||
{ type: "step-start", index: 0 },
|
||||
{ type: "text-delta", text: "Hello" },
|
||||
{ type: "text-delta", text: "!" },
|
||||
|
||||
Reference in New Issue
Block a user