Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/core/src/v1/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@ export const Assistant = Schema.Struct({
structured: Schema.optional(Schema.Any),
variant: Schema.optional(Schema.String),
finish: Schema.optional(Schema.String),
// HTTP response headers from the LLM provider. Used by plugins (e.g. LiteLLM
// proxy) to read routing metadata such as x-litellm-model-api-base that
// identifies the actual model selected by an auto-router behind the proxy.
responseHeaders: Schema.optional(Schema.Record(Schema.String, Schema.String)),
}).annotate({ identifier: "AssistantMessage" })
export type Assistant = Omit<Types.DeepMutable<Schema.Schema.Type<typeof Assistant>>, "error"> & {
error?: AssistantError
Expand Down
4 changes: 4 additions & 0 deletions packages/llm/src/schema/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ export const StepFinish = Schema.Struct({
reason: FinishReason,
usage: Schema.optional(Usage),
providerMetadata: Schema.optional(ProviderMetadata),
// HTTP response headers from the LLM provider. Used by plugins (e.g. LiteLLM
// proxy) to read routing metadata such as x-litellm-model-api-base that
// identifies the actual model selected by an auto-router behind the proxy.
responseHeaders: Schema.optional(Schema.Record(Schema.String, Schema.String)),
}).annotate({ identifier: "LLM.Event.StepFinish" })
export type StepFinish = Schema.Schema.Type<typeof StepFinish>

Expand Down
4 changes: 4 additions & 0 deletions packages/opencode/src/session/llm/ai-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ export function toLLMEvents(
reason: finishReason(event.finishReason),
usage: usage(event.usage),
providerMetadata: metadata,
// Capture HTTP response headers so plugins can read provider-specific
// routing metadata (e.g. x-litellm-model-api-base from a LiteLLM
// auto-router) that is only available in the response headers.
responseHeaders: event.response?.headers as Record<string, string> | undefined,
}),
]
})
Expand Down
4 changes: 4 additions & 0 deletions packages/opencode/src/session/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,10 @@ export const layer = Layer.effect(
ctx.assistantMessage.finish = value.reason
ctx.assistantMessage.cost += usage.cost
ctx.assistantMessage.tokens = usage.tokens
// Store provider response headers so plugins can read routing
// metadata (e.g. x-litellm-model-api-base from a LiteLLM proxy).
if (value.responseHeaders && Object.keys(value.responseHeaders).length > 0)
ctx.assistantMessage.responseHeaders = value.responseHeaders
yield* session.updatePart({
id: PartID.ascending(),
reason: value.reason,
Expand Down
Loading