mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-03 05:44:44 +00:00
refactor(ai): separate conversation and generation lowering
This commit is contained in:
parent
eb083cce63
commit
ffb9728068
3 changed files with 58 additions and 23 deletions
|
|
@ -689,13 +689,30 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|||
return input
|
||||
})
|
||||
|
||||
const lowerOptions = (request: LLMRequest) => {
|
||||
const options = OpenResponsesOptions.resolve(request)
|
||||
export const lowerConversation = Effect.fn("OpenResponses.lowerConversation")(function* (
|
||||
request: LLMRequest,
|
||||
extension: Extension,
|
||||
) {
|
||||
const instructions = ProviderShared.joinText(request.system)
|
||||
return {
|
||||
model: request.model.id,
|
||||
input: yield* lowerMessages(request, extension),
|
||||
...(instructions ? { instructions } : {}),
|
||||
}
|
||||
})
|
||||
|
||||
export const lowerGeneration = (request: LLMRequest) => {
|
||||
const options = OpenResponsesOptions.resolve(request)
|
||||
const generation = request.generation
|
||||
const cacheKey = ProviderShared.promptCacheKey(request)
|
||||
const parallelToolCalls = resolveParallelToolCalls(request)
|
||||
return {
|
||||
...(instructions ? { instructions } : {}),
|
||||
stream: true as const,
|
||||
max_output_tokens: generation?.maxTokens,
|
||||
temperature: generation?.temperature,
|
||||
top_p: generation?.topP,
|
||||
presence_penalty: generation?.presencePenalty,
|
||||
frequency_penalty: generation?.frequencyPenalty,
|
||||
...(options.store !== undefined ? { store: options.store } : {}),
|
||||
...(options.metadata ? { metadata: options.metadata } : {}),
|
||||
...(options.safetyIdentifier ? { safety_identifier: options.safetyIdentifier } : {}),
|
||||
|
|
@ -723,7 +740,7 @@ export const resolveParallelToolCalls = (request: LLMRequest) => {
|
|||
return disabled === undefined ? undefined : !disabled
|
||||
}
|
||||
|
||||
const allowedToolChoice = (request: LLMRequest) => {
|
||||
export const allowedToolChoice = (request: LLMRequest) => {
|
||||
const allowed = OpenResponsesOptions.resolve(request).allowedTools
|
||||
if (!allowed) return undefined
|
||||
return {
|
||||
|
|
@ -737,11 +754,10 @@ export const fromRequestWithExtension = Effect.fn("OpenResponses.fromRequestWith
|
|||
request: LLMRequest,
|
||||
extension: Extension,
|
||||
) {
|
||||
const generation = request.generation
|
||||
const toolSchemaCompatibility = request.model.compatibility?.toolSchema
|
||||
return {
|
||||
model: request.model.id,
|
||||
input: yield* lowerMessages(request, extension),
|
||||
...(yield* lowerConversation(request, extension)),
|
||||
...lowerGeneration(request),
|
||||
tools:
|
||||
request.tools.length === 0
|
||||
? undefined
|
||||
|
|
@ -755,13 +771,6 @@ export const fromRequestWithExtension = Effect.fn("OpenResponses.fromRequestWith
|
|||
tool_choice:
|
||||
allowedToolChoice(request) ??
|
||||
(request.toolChoice ? yield* lowerToolChoice(extension.name, request.toolChoice) : undefined),
|
||||
stream: true as const,
|
||||
max_output_tokens: generation?.maxTokens,
|
||||
temperature: generation?.temperature,
|
||||
top_p: generation?.topP,
|
||||
presence_penalty: generation?.presencePenalty,
|
||||
frequency_penalty: generation?.frequencyPenalty,
|
||||
...lowerOptions(request),
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Auth } from "../route/auth.js"
|
|||
import { Endpoint } from "../route/endpoint.js"
|
||||
import { Protocol } from "../route/protocol.js"
|
||||
import { HttpTransport } from "../route/transport/index.js"
|
||||
import { LLMRequest, type JsonSchema, type ToolDefinition } from "../schema/index.js"
|
||||
import type { LLMRequest, JsonSchema, ToolDefinition } from "../schema/index.js"
|
||||
import { OpenResponses } from "./open-responses.js"
|
||||
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js"
|
||||
import { OpenAIImage } from "./utils/openai-image.js"
|
||||
|
|
@ -125,15 +125,10 @@ const lowerToolChoice = (toolChoice: NonNullable<LLMRequest["toolChoice"]>, tool
|
|||
const decodeBody = ProviderShared.validateWith(Schema.decodeUnknownEffect(OpenAIResponsesBody))
|
||||
|
||||
const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request: LLMRequest) {
|
||||
const body = yield* OpenResponses.fromRequestWithExtension(
|
||||
LLMRequest.update(request, { tools: [], toolChoice: undefined }),
|
||||
extension,
|
||||
)
|
||||
const toolSchemaCompatibility = request.model.compatibility?.toolSchema
|
||||
const parallelToolCalls = OpenResponses.resolveParallelToolCalls(request)
|
||||
return yield* decodeBody({
|
||||
...body,
|
||||
...(parallelToolCalls === undefined ? {} : { parallel_tool_calls: parallelToolCalls }),
|
||||
...(yield* OpenResponses.lowerConversation(request, extension)),
|
||||
...OpenResponses.lowerGeneration(request),
|
||||
tools:
|
||||
request.tools.length === 0
|
||||
? undefined
|
||||
|
|
@ -141,7 +136,8 @@ const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request:
|
|||
lowerTool(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility)),
|
||||
),
|
||||
tool_choice:
|
||||
body.tool_choice ?? (request.toolChoice ? yield* lowerToolChoice(request.toolChoice, request.tools) : undefined),
|
||||
OpenResponses.allowedToolChoice(request) ??
|
||||
(request.toolChoice ? yield* lowerToolChoice(request.toolChoice, request.tools) : undefined),
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
30
packages/ai/test/provider/conversation-lowering.test.ts
Normal file
30
packages/ai/test/provider/conversation-lowering.test.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { expect } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { LLM, Message } from "../../src/index.js"
|
||||
import { OpenAI } from "../../src/providers.js"
|
||||
import { OpenResponses } from "../../src/protocols/open-responses.js"
|
||||
import { it } from "../lib/effect.js"
|
||||
|
||||
it.effect("conversation lowering excludes generation settings and tool definitions", () =>
|
||||
Effect.gen(function* () {
|
||||
const body = yield* OpenResponses.lowerConversation(
|
||||
LLM.request({
|
||||
model: OpenAI.configure({ apiKey: "test" }).responses("fixture"),
|
||||
system: "Keep the context",
|
||||
messages: [Message.user("hello"), Message.assistant("hi")],
|
||||
generation: { maxTokens: 100, temperature: 0.5 },
|
||||
providerOptions: { store: false },
|
||||
tools: [{ name: "unsupported", description: "Generation only", inputSchema: {}, native: { unsupported: {} } }],
|
||||
}),
|
||||
{ id: "open-responses", name: "Open Responses" },
|
||||
)
|
||||
expect(body).toEqual({
|
||||
model: "fixture",
|
||||
instructions: "Keep the context",
|
||||
input: [
|
||||
{ role: "user", content: [{ type: "input_text", text: "hello" }] },
|
||||
{ type: "message", role: "assistant", content: [{ type: "output_text", text: "hi" }] },
|
||||
],
|
||||
})
|
||||
}),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue