mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 19:46:16 +03:00
refactor(ai): use OpenAIChat assistant hook and drop OpenRouterBody cast (#57616)
This commit is contained in:
committed by
GitHub
Unverified
parent
d2812d147e
commit
a2cb1c4e7f
@@ -8,7 +8,7 @@ import type { ProviderPackage } from "../provider-package.js"
|
||||
import { SystemOne } from "../experimental/system-one.js"
|
||||
import { OpenAIChat } from "../protocols/openai-chat.js"
|
||||
import { cacheControl } from "../protocols/utils/cache.js"
|
||||
import { isRecord, ProviderShared } from "../protocols/shared.js"
|
||||
import { isRecord, JsonObject, lenient, ProviderShared } from "../protocols/shared.js"
|
||||
|
||||
export const id = ProviderID.make("openrouter")
|
||||
const baseURL = "https://openrouter.ai/api/v1"
|
||||
@@ -90,9 +90,26 @@ export type Settings = ProviderPackage.Settings &
|
||||
readonly baseURL?: string
|
||||
}
|
||||
|
||||
const OpenRouterBody = Schema.StructWithRest(Schema.Struct(OpenAIChat.bodyFields), [
|
||||
Schema.Record(Schema.String, Schema.Any),
|
||||
])
|
||||
const Options = Schema.Struct({
|
||||
usage: lenient(Schema.Union([Schema.Boolean, JsonObject])),
|
||||
models: lenient(Schema.Array(Schema.String)),
|
||||
provider: lenient(JsonObject),
|
||||
plugins: lenient(Schema.Array(JsonObject)),
|
||||
web_search_options: lenient(JsonObject),
|
||||
debug: lenient(JsonObject),
|
||||
user: lenient(Schema.String),
|
||||
reasoning: lenient(JsonObject),
|
||||
})
|
||||
const decodeOptions = Schema.decodeUnknownSync(Options)
|
||||
|
||||
const OpenRouterBody = Schema.StructWithRest(
|
||||
Schema.Struct({
|
||||
...OpenAIChat.bodyFields,
|
||||
...Options.fields,
|
||||
usage: Schema.optional(JsonObject),
|
||||
}),
|
||||
[JsonObject],
|
||||
)
|
||||
export type OpenRouterBody = Schema.Schema.Type<typeof OpenRouterBody>
|
||||
|
||||
export const protocol = Protocol.make({
|
||||
@@ -100,33 +117,24 @@ export const protocol = Protocol.make({
|
||||
body: {
|
||||
schema: OpenRouterBody,
|
||||
from: (request) =>
|
||||
OpenAIChat.fromRequest(request, { cacheControl: cacheControl() }).pipe(
|
||||
Effect.map((body) => {
|
||||
const sourceAssistants = request.messages.filter((message) => message.role === "assistant")
|
||||
let assistantIndex = 0
|
||||
const messages = body.messages.map((message) => {
|
||||
if (message.role !== "assistant") return message
|
||||
const source = sourceAssistants[assistantIndex++]
|
||||
const reasoning = source?.content
|
||||
.filter((part) => part.type === "reasoning")
|
||||
.map((part) => part.text)
|
||||
.join("")
|
||||
const reasoningDetails = Array.isArray(message.reasoning_details) ? message.reasoning_details : undefined
|
||||
return {
|
||||
...message,
|
||||
reasoning_content: undefined,
|
||||
reasoning_text: undefined,
|
||||
reasoning: reasoning && reasoningDetails && reasoningDetails.length > 0 ? reasoning : undefined,
|
||||
reasoning_details: reasoningDetails,
|
||||
}
|
||||
})
|
||||
OpenAIChat.fromRequest(request, {
|
||||
cacheControl: cacheControl(),
|
||||
assistant: (source, message) => {
|
||||
if (message.role !== "assistant") return message
|
||||
const reasoning = source.content
|
||||
.filter((part) => part.type === "reasoning")
|
||||
.map((part) => part.text)
|
||||
.join("")
|
||||
const reasoningDetails = Array.isArray(message.reasoning_details) ? message.reasoning_details : undefined
|
||||
return {
|
||||
...body,
|
||||
messages,
|
||||
...bodyOptions(request.providerOptions, request.generation?.maxTokens),
|
||||
} as OpenRouterBody
|
||||
}),
|
||||
),
|
||||
...message,
|
||||
reasoning_content: undefined,
|
||||
reasoning_text: undefined,
|
||||
reasoning: reasoning && reasoningDetails && reasoningDetails.length > 0 ? reasoning : undefined,
|
||||
reasoning_details: reasoningDetails,
|
||||
}
|
||||
},
|
||||
}).pipe(Effect.map((body) => bodyOptions(body, request.providerOptions, request.generation?.maxTokens))),
|
||||
},
|
||||
stream: OpenAIChat.protocol.stream,
|
||||
})
|
||||
@@ -138,26 +146,29 @@ const fitReasoning = (reasoning: Record<string, unknown>, maxTokens: number | un
|
||||
? { ...reasoning, max_tokens: ProviderShared.fitThinkingBudget(reasoning.max_tokens, maxTokens, 1_024) }
|
||||
: reasoning
|
||||
|
||||
const bodyOptions = (input: unknown, maxTokens: number | undefined) => {
|
||||
const bodyOptions = (body: OpenAIChat.OpenAIChatBody, input: unknown, maxTokens: number | undefined) => {
|
||||
const openrouter = isRecord(input) ? input : {}
|
||||
const { usage, models, provider, plugins, web_search_options, debug, user, reasoning, promptCacheKey, ...options } =
|
||||
openrouter
|
||||
const options = Object.fromEntries(
|
||||
Object.entries(openrouter).filter(([key]) => !(key in Options.fields) && key !== "promptCacheKey"),
|
||||
)
|
||||
const known = decodeOptions(openrouter)
|
||||
const usage =
|
||||
openrouter.usage === undefined || known.usage === true
|
||||
? { include: true }
|
||||
: known.usage === false
|
||||
? { include: false }
|
||||
: known.usage
|
||||
return {
|
||||
...options,
|
||||
...(usage === undefined || usage === true
|
||||
? { usage: { include: true } }
|
||||
: usage === false
|
||||
? { usage: { include: false } }
|
||||
: isRecord(usage)
|
||||
? { usage }
|
||||
: {}),
|
||||
...(Array.isArray(models) ? { models } : {}),
|
||||
...(isRecord(provider) ? { provider } : {}),
|
||||
...(Array.isArray(plugins) ? { plugins } : {}),
|
||||
...(isRecord(web_search_options) ? { web_search_options } : {}),
|
||||
...(isRecord(debug) ? { debug } : {}),
|
||||
...(typeof user === "string" ? { user } : {}),
|
||||
...(isRecord(reasoning) ? { reasoning: fitReasoning(reasoning, maxTokens) } : {}),
|
||||
...body,
|
||||
...(usage !== undefined ? { usage } : {}),
|
||||
...(known.models !== undefined ? { models: known.models } : {}),
|
||||
...(known.provider !== undefined ? { provider: known.provider } : {}),
|
||||
...(known.plugins !== undefined ? { plugins: known.plugins } : {}),
|
||||
...(known.web_search_options !== undefined ? { web_search_options: known.web_search_options } : {}),
|
||||
...(known.debug !== undefined ? { debug: known.debug } : {}),
|
||||
...(known.user !== undefined ? { user: known.user } : {}),
|
||||
...(known.reasoning !== undefined ? { reasoning: fitReasoning(known.reasoning, maxTokens) } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -492,6 +492,7 @@ describe("OpenRouter", () => {
|
||||
model: OpenRouter.configure({ apiKey: "test-key" }).model("anthropic/claude-sonnet-4.6"),
|
||||
cache: "none",
|
||||
messages: [
|
||||
Message.assistant(""),
|
||||
Message.assistant([
|
||||
{
|
||||
type: "reasoning",
|
||||
|
||||
Reference in New Issue
Block a user