refactor(ai): rename flattened tool helper

This commit is contained in:
Aiden Cline
2026-09-29 22:19:42 -05:00
parent 300dc84c69
commit 0dcebdb88a
12 changed files with 15 additions and 19 deletions
@@ -1031,10 +1031,9 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
// messages. Tools live highest in the cache hierarchy, so when callers // messages. Tools live highest in the cache hierarchy, so when callers
// over-mark we keep their tool hints and shed the message-tail ones first. // over-mark we keep their tool hints and shed the message-tail ones first.
const breakpoints = Cache.newBreakpoints(ANTHROPIC_BREAKPOINT_CAP) const breakpoints = Cache.newBreakpoints(ANTHROPIC_BREAKPOINT_CAP)
const definitions = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools).map((tool) => lowerTool(breakpoints, tool))
const tools = definitions.length === 0 ? undefined : definitions.map((tool) => lowerTool(breakpoints, tool))
// Anthropic rejects tool_choice when tools are absent; "none" is only meaningful with tools present. // Anthropic rejects tool_choice when tools are absent; "none" is only meaningful with tools present.
const toolChoice = tools === undefined || !request.toolChoice ? undefined : yield* lowerToolChoice(request.toolChoice) const toolChoice = tools.length === 0 || !request.toolChoice ? undefined : yield* lowerToolChoice(request.toolChoice)
const systemParts = request.system.filter((part) => part.text.length > 0) const systemParts = request.system.filter((part) => part.text.length > 0)
const system = const system =
systemParts.length === 0 systemParts.length === 0
@@ -1057,7 +1056,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
model: request.model.id, model: request.model.id,
system, system,
messages, messages,
tools, tools: tools.length === 0 ? undefined : tools,
tool_choice: toolChoice, tool_choice: toolChoice,
stream: true as const, stream: true as const,
max_tokens: maxTokens, max_tokens: maxTokens,
@@ -463,7 +463,7 @@ const applyThinkingBindingDefault = (request: LLMRequest, thinking: Readonly<Rec
const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request: LLMRequest) { const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request: LLMRequest) {
const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
const generation = request.generation const generation = request.generation
const options = yield* decodeOptions(request.providerOptions ?? {}) const options = yield* decodeOptions(request.providerOptions ?? {})
const maxTokens = const maxTokens =
+1 -1
View File
@@ -438,7 +438,7 @@ const lowerMessages = Effect.fn("Gemini.lowerMessages")(function* (request: LLMR
}) })
const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMRequest) { const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request: LLMRequest) {
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
const hasTools = tools.length > 0 const hasTools = tools.length > 0
const generation = request.generation const generation = request.generation
const options = yield* decodeOptions(request.providerOptions ?? {}) const options = yield* decodeOptions(request.providerOptions ?? {})
+1 -1
View File
@@ -26,7 +26,7 @@ const Body = Schema.Struct({
}) })
const fromRequest = Effect.fn("MetaMessages.fromRequest")(function* (request: LLMRequest) { const fromRequest = Effect.fn("MetaMessages.fromRequest")(function* (request: LLMRequest) {
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
const body = yield* AnthropicMessages.protocol.body.from(request) const body = yield* AnthropicMessages.protocol.body.from(request)
return { return {
...body, ...body,
+1 -1
View File
@@ -67,7 +67,7 @@ const adapter = {
const fromRequest = Effect.fn("MetaResponses.fromRequest")(function* (request: LLMRequest) { const fromRequest = Effect.fn("MetaResponses.fromRequest")(function* (request: LLMRequest) {
const key = request.model.route.providerMetadataKey ?? String(request.model.provider) const key = request.model.route.providerMetadataKey ?? String(request.model.provider)
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
const projected = LLMRequest.update(request, { const projected = LLMRequest.update(request, {
messages: request.messages.map((message) => messages: request.messages.map((message) =>
Message.make({ Message.make({
+1 -1
View File
@@ -390,7 +390,7 @@ export const fromRequest = Effect.fn("MistralChat.fromRequest")(function* (reque
tool: (name) => ({ type: "function" as const, function: { name } }), tool: (name) => ({ type: "function" as const, function: { name } }),
}) })
: undefined : undefined
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
return { return {
model: request.model.id, model: request.model.id,
messages: yield* lowerMessages(request), messages: yield* lowerMessages(request),
+1 -1
View File
@@ -816,7 +816,7 @@ export const fromRequestWithAdapter = Effect.fn("OpenResponses.fromRequestWithAd
request: LLMRequest, request: LLMRequest,
adapter: ProviderAdapter, adapter: ProviderAdapter,
) { ) {
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
return { return {
...(yield* lowerConversation(request, adapter)), ...(yield* lowerConversation(request, adapter)),
...lowerGeneration(request), ...lowerGeneration(request),
+1 -1
View File
@@ -826,7 +826,7 @@ export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (
const zaiToolStream = const zaiToolStream =
request.model.compatibility?.zaiToolStream ?? detectZaiToolStream(provider, baseURL, request.model.id) request.model.compatibility?.zaiToolStream ?? detectZaiToolStream(provider, baseURL, request.model.id)
const hasHistory = hasToolHistory(request.messages) const hasHistory = hasToolHistory(request.messages)
const tools = ProviderShared.toolDefinitions(request.tools) const tools = ProviderShared.flatTools(request.tools)
const hasActiveTools = tools.length > 0 const hasActiveTools = tools.length > 0
return { return {
model: request.model.id, model: request.model.id,
@@ -181,7 +181,7 @@ const lowerToolEntry = Effect.fn("OpenAIResponses.lowerToolEntry")(function* (to
type: "namespace" as const, type: "namespace" as const,
name: tool.name, name: tool.name,
description: tool.description ?? `Tools in the ${tool.name} namespace.`, description: tool.description ?? `Tools in the ${tool.name} namespace.`,
tools: yield* Effect.forEach(ProviderShared.toolDefinitions(tool.tools), (leaf) => tools: yield* Effect.forEach(ProviderShared.flatTools(tool.tools), (leaf) =>
OpenResponses.lowerTool(NAME, leaf), OpenResponses.lowerTool(NAME, leaf),
), ),
} }
+2 -5
View File
@@ -287,11 +287,8 @@ export const unsupportedOperation = (input: {
}), }),
}) })
/** /** The route flattens namespaces before a flat protocol's `body.from`, so only plain tools remain. */
* Tool definitions of a route-lowered request. The route flattens namespaces export const flatTools = (tools: ReadonlyArray<ToolEntry>) =>
* before a flat protocol's `body.from`, so no namespace reaches this point.
*/
export const toolDefinitions = (tools: ReadonlyArray<ToolEntry>) =>
tools.filter((tool): tool is ToolDefinition => tool.type === "tool") tools.filter((tool): tool is ToolDefinition => tool.type === "tool")
export const matchToolChoice = <Auto, None, Required, Tool>( export const matchToolChoice = <Auto, None, Required, Tool>(
+1 -1
View File
@@ -95,7 +95,7 @@ export const protocol = Protocol.make({
}) })
export const compact = ResponsesCompaction.make(adapter, (request) => export const compact = ResponsesCompaction.make(adapter, (request) =>
OpenResponses.lowerTools(ProviderShared.toolDefinitions(request.tools), adapter), OpenResponses.lowerTools(ProviderShared.flatTools(request.tools), adapter),
) )
export * as XAIResponses from "./xai-responses.js" export * as XAIResponses from "./xai-responses.js"
+1 -1
View File
@@ -487,7 +487,7 @@ function callOptions(
presencePenalty: request.generation?.presencePenalty, presencePenalty: request.generation?.presencePenalty,
frequencyPenalty: request.generation?.frequencyPenalty, frequencyPenalty: request.generation?.frequencyPenalty,
seed: request.generation?.seed, seed: request.generation?.seed,
tools: ProviderShared.toolDefinitions(request.tools).map(tool), tools: ProviderShared.flatTools(request.tools).map(tool),
toolChoice: toolChoice(request.toolChoice), toolChoice: toolChoice(request.toolChoice),
headers: request.http?.headers, headers: request.http?.headers,
providerOptions: requestProviderOptions(request.providerOptions, packageName, modelID, optionKey), providerOptions: requestProviderOptions(request.providerOptions, packageName, modelID, optionKey),