@opencode-ai/ai
Advanced tools
@@ -39,3 +39,3 @@ // Apply an `LLMRequest.cache` policy by injecting `CacheHint`s onto the parts | ||
| // whole policy pass for these — emitting hints would be harmless but pointless. | ||
| const RESPECTS_INLINE_HINTS = new Set(["anthropic-messages", "bedrock-converse"]); | ||
| const RESPECTS_INLINE_HINTS = new Set(["anthropic-messages", "bedrock-converse", "openrouter"]); | ||
| const makeHint = (ttlSeconds) => ttlSeconds !== undefined ? new CacheHint({ type: "ephemeral", ttlSeconds }) : new CacheHint({ type: "ephemeral" }); | ||
@@ -109,2 +109,4 @@ const markLastTool = (tools, hint, budget) => { | ||
| return request; | ||
| if (request.model.route.id === "openrouter" && (request.cache === undefined || request.cache === "auto")) | ||
| return request; | ||
| const policy = resolve(request.cache); | ||
@@ -111,0 +113,0 @@ if (!policy.tools && !policy.system && !policy.messages) |
@@ -1,6 +0,6 @@ | ||
| import { Schema } from "effect"; | ||
| import { Effect, Schema } from "effect"; | ||
| import { Route } from "../route/client"; | ||
| import { HttpTransport } from "../route/transport"; | ||
| import { Protocol } from "../route/protocol"; | ||
| import { LLMEvent, Usage, type FinishReasonDetails } from "../schema"; | ||
| import { LLMError, LLMEvent, Usage, type FinishReasonDetails, type CacheHint, type LLMRequest } from "../schema"; | ||
| import { Lifecycle } from "./utils/lifecycle"; | ||
@@ -10,2 +10,6 @@ import { ToolStream } from "./utils/tool-stream"; | ||
| export declare const PATH = "/chat/completions"; | ||
| declare const OpenAIChatCacheControl: Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>; | ||
| export declare const bodyFields: { | ||
@@ -15,3 +19,15 @@ model: Schema.String; | ||
| readonly role: Schema.Literal<"system">; | ||
| readonly content: Schema.String; | ||
| readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.Literal<"text">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.Literal<"image_url">; | ||
| readonly image_url: Schema.Struct<{ | ||
| readonly url: Schema.String; | ||
| }>; | ||
| }>]>>]>; | ||
| }>, Schema.Struct<{ | ||
@@ -22,2 +38,6 @@ readonly role: Schema.Literal<"user">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
@@ -44,2 +64,6 @@ readonly type: Schema.Literal<"image_url">; | ||
| readonly reasoning_details: Schema.optional<Schema.Unknown>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>, Schema.Struct<{ | ||
@@ -49,2 +73,6 @@ readonly role: Schema.Literal<"tool">; | ||
| readonly content: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>]>>; | ||
@@ -58,2 +86,6 @@ tools: Schema.optional<Schema.$Array<Schema.Struct<{ | ||
| }>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>>>; | ||
@@ -85,3 +117,15 @@ tool_choice: Schema.optional<Schema.Union<readonly [Schema.Literals<readonly ["auto", "none", "required"]>, Schema.Struct<{ | ||
| readonly role: Schema.Literal<"system">; | ||
| readonly content: Schema.String; | ||
| readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.Literal<"text">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.Literal<"image_url">; | ||
| readonly image_url: Schema.Struct<{ | ||
| readonly url: Schema.String; | ||
| }>; | ||
| }>]>>]>; | ||
| }>, Schema.Struct<{ | ||
@@ -92,2 +136,6 @@ readonly role: Schema.Literal<"user">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
@@ -114,2 +162,6 @@ readonly type: Schema.Literal<"image_url">; | ||
| readonly reasoning_details: Schema.optional<Schema.Unknown>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>, Schema.Struct<{ | ||
@@ -119,2 +171,6 @@ readonly role: Schema.Literal<"tool">; | ||
| readonly content: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>]>>; | ||
@@ -128,2 +184,6 @@ tools: Schema.optional<Schema.$Array<Schema.Struct<{ | ||
| }>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>>>; | ||
@@ -207,2 +267,194 @@ tool_choice: Schema.optional<Schema.Union<readonly [Schema.Literals<readonly ["auto", "none", "required"]>, Schema.Struct<{ | ||
| } | ||
| interface LoweringOptions { | ||
| readonly cacheControl?: (cache: CacheHint | undefined) => Schema.Schema.Type<typeof OpenAIChatCacheControl> | undefined; | ||
| } | ||
| export declare const fromRequest: (request: LLMRequest, options?: LoweringOptions | undefined) => Effect.Effect<{ | ||
| reasoning_effort?: string | undefined; | ||
| store?: boolean | undefined; | ||
| temperature: number | undefined; | ||
| top_p: number | undefined; | ||
| frequency_penalty: number | undefined; | ||
| presence_penalty: number | undefined; | ||
| seed: number | undefined; | ||
| stop: readonly string[] | undefined; | ||
| max_completion_tokens: number | undefined; | ||
| model: string & import("effect/Brand").Brand<"LLM.ModelID">; | ||
| messages: ({ | ||
| readonly role: "system"; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
| readonly role: "user"; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
| readonly [x: string]: unknown; | ||
| readonly content: string | null; | ||
| readonly role: "assistant"; | ||
| readonly reasoning?: string | undefined; | ||
| readonly reasoning_content?: string | undefined; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
| readonly id: string; | ||
| readonly type: "function"; | ||
| readonly function: { | ||
| readonly name: string; | ||
| readonly arguments: string; | ||
| }; | ||
| }[] | undefined; | ||
| readonly reasoning_details?: unknown; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
| tools: { | ||
| readonly function: { | ||
| readonly name: string; | ||
| readonly description: string; | ||
| readonly parameters: { | ||
| readonly [x: string]: unknown; | ||
| }; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
| tool_choice: "required" | "none" | "auto" | { | ||
| type: "function"; | ||
| function: { | ||
| name: string; | ||
| }; | ||
| } | undefined; | ||
| stream: true; | ||
| stream_options: { | ||
| include_usage: boolean; | ||
| }; | ||
| } | { | ||
| reasoning_effort?: string | undefined; | ||
| store?: boolean | undefined; | ||
| temperature: number | undefined; | ||
| top_p: number | undefined; | ||
| frequency_penalty: number | undefined; | ||
| presence_penalty: number | undefined; | ||
| seed: number | undefined; | ||
| stop: readonly string[] | undefined; | ||
| max_tokens: number | undefined; | ||
| model: string & import("effect/Brand").Brand<"LLM.ModelID">; | ||
| messages: ({ | ||
| readonly role: "system"; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
| readonly role: "user"; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
| readonly [x: string]: unknown; | ||
| readonly content: string | null; | ||
| readonly role: "assistant"; | ||
| readonly reasoning?: string | undefined; | ||
| readonly reasoning_content?: string | undefined; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
| readonly id: string; | ||
| readonly type: "function"; | ||
| readonly function: { | ||
| readonly name: string; | ||
| readonly arguments: string; | ||
| }; | ||
| }[] | undefined; | ||
| readonly reasoning_details?: unknown; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
| tools: { | ||
| readonly function: { | ||
| readonly name: string; | ||
| readonly description: string; | ||
| readonly parameters: { | ||
| readonly [x: string]: unknown; | ||
| }; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
| tool_choice: "required" | "none" | "auto" | { | ||
| type: "function"; | ||
| function: { | ||
| name: string; | ||
| }; | ||
| } | undefined; | ||
| stream: true; | ||
| stream_options: { | ||
| include_usage: boolean; | ||
| }; | ||
| }, LLMError, never>; | ||
| /** | ||
@@ -218,3 +470,15 @@ * The OpenAI Chat protocol — request body construction, body schema, and the | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -225,2 +489,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -239,2 +507,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -250,5 +522,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -258,3 +534,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -267,2 +542,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -329,3 +609,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -336,2 +628,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -350,2 +646,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -361,5 +661,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -369,3 +673,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -378,2 +681,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -403,3 +711,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -410,2 +730,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -424,2 +748,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -435,5 +763,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -443,3 +775,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -452,2 +783,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -454,0 +790,0 @@ readonly temperature?: number | undefined; |
@@ -26,2 +26,6 @@ import { Effect, Schema } from "effect"; | ||
| // JSON-encodes it before transport. | ||
| const OpenAIChatCacheControl = Schema.Struct({ | ||
| type: Schema.Literal("ephemeral"), | ||
| ttl: Schema.optional(Schema.String), | ||
| }); | ||
| const OpenAIChatFunction = Schema.Struct({ | ||
@@ -35,2 +39,3 @@ name: Schema.String, | ||
| function: OpenAIChatFunction, | ||
| cache_control: Schema.optional(OpenAIChatCacheControl), | ||
| }); | ||
@@ -46,4 +51,8 @@ const OpenAIChatAssistantToolCall = Schema.Struct({ | ||
| const OpenAIChatUserContent = Schema.Union([ | ||
| Schema.Struct({ type: Schema.Literal("text"), text: Schema.String }), | ||
| Schema.Struct({ | ||
| type: Schema.Literal("text"), | ||
| text: Schema.String, | ||
| cache_control: Schema.optional(OpenAIChatCacheControl), | ||
| }), | ||
| Schema.Struct({ | ||
| type: Schema.Literal("image_url"), | ||
@@ -54,4 +63,7 @@ image_url: Schema.Struct({ url: Schema.String }), | ||
| const OpenAIChatMessage = Schema.Union([ | ||
| Schema.Struct({ role: Schema.Literal("system"), content: Schema.String }), | ||
| Schema.Struct({ | ||
| role: Schema.Literal("system"), | ||
| content: Schema.Union([Schema.String, Schema.Array(OpenAIChatUserContent)]), | ||
| }), | ||
| Schema.Struct({ | ||
| role: Schema.Literal("user"), | ||
@@ -68,4 +80,10 @@ content: Schema.Union([Schema.String, Schema.Array(OpenAIChatUserContent)]), | ||
| reasoning_details: Schema.optional(Schema.Unknown), | ||
| cache_control: Schema.optional(OpenAIChatCacheControl), | ||
| }), [Schema.Record(Schema.String, Schema.Unknown)]), | ||
| Schema.Struct({ role: Schema.Literal("tool"), tool_call_id: Schema.String, content: Schema.String }), | ||
| Schema.Struct({ | ||
| role: Schema.Literal("tool"), | ||
| tool_call_id: Schema.String, | ||
| content: Schema.String, | ||
| cache_control: Schema.optional(OpenAIChatCacheControl), | ||
| }), | ||
| ]).pipe(Schema.toTaggedUnion("role")); | ||
@@ -147,9 +165,3 @@ const OpenAIChatToolChoice = Schema.Union([ | ||
| }); | ||
| // ============================================================================= | ||
| // Request Lowering | ||
| // ============================================================================= | ||
| // Lowering is the only place that knows how common LLM messages map onto the | ||
| // OpenAI Chat wire format. Keep provider quirks here instead of leaking native | ||
| // fields into `LLMRequest`. | ||
| const lowerTool = (tool, inputSchema) => ({ | ||
| const lowerTool = (tool, inputSchema, options) => ({ | ||
| type: "function", | ||
@@ -161,2 +173,3 @@ function: { | ||
| }, | ||
| cache_control: options.cacheControl?.(tool.cache), | ||
| }); | ||
@@ -196,7 +209,7 @@ const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("OpenAI Chat", toolChoice, { | ||
| }; | ||
| const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (message) { | ||
| const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (message, options) { | ||
| const content = []; | ||
| for (const part of message.content) { | ||
| if (part.type === "text") { | ||
| content.push({ type: "text", text: part.text }); | ||
| content.push({ type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) }); | ||
| continue; | ||
@@ -210,7 +223,10 @@ } | ||
| } | ||
| if (content.every((part) => part.type === "text")) | ||
| return { role: "user", content: content.map((part) => part.text).join("") }; | ||
| if (content.every((part) => part.type === "text" && part.cache_control === undefined)) | ||
| return { | ||
| role: "user", | ||
| content: content.map((part) => (part.type === "text" ? part.text : "")).join(""), | ||
| }; | ||
| return { role: "user", content }; | ||
| }); | ||
| const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (message, configuredField) { | ||
| const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (message, configuredField, options = {}) { | ||
| const content = []; | ||
@@ -259,2 +275,3 @@ const reasoning = []; | ||
| })(); | ||
| const cached = message.content.findLast((part) => "cache" in part && part.cache !== undefined); | ||
| const result = { | ||
@@ -265,2 +282,3 @@ role: "assistant", | ||
| reasoning_details: details, | ||
| cache_control: options.cacheControl?.(cached && "cache" in cached ? cached.cache : undefined), | ||
| }; | ||
@@ -271,3 +289,3 @@ if (field === undefined || reasoningText === undefined) | ||
| }); | ||
| const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (message) { | ||
| const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (message, options) { | ||
| const messages = []; | ||
@@ -279,3 +297,8 @@ const images = []; | ||
| if (part.result.type !== "content") { | ||
| messages.push({ role: "tool", tool_call_id: part.id, content: ProviderShared.toolResultText(part) }); | ||
| messages.push({ | ||
| role: "tool", | ||
| tool_call_id: part.id, | ||
| content: ProviderShared.toolResultText(part), | ||
| cache_control: options.cacheControl?.(part.cache), | ||
| }); | ||
| continue; | ||
@@ -285,3 +308,8 @@ } | ||
| const text = content.filter((item) => item.type === "text").map((item) => item.text); | ||
| messages.push({ role: "tool", tool_call_id: part.id, content: text.join("\n") }); | ||
| messages.push({ | ||
| role: "tool", | ||
| tool_call_id: part.id, | ||
| content: text.join("\n"), | ||
| cache_control: options.cacheControl?.(part.cache), | ||
| }); | ||
| const files = content.filter((item) => item.type === "file"); | ||
@@ -292,11 +320,24 @@ images.push(...(yield* Effect.forEach(files, (item) => lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name })))); | ||
| }); | ||
| const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message, reasoningField) { | ||
| const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message, reasoningField, options = {}) { | ||
| if (message.role === "user") | ||
| return [yield* lowerUserMessage(message)]; | ||
| return [yield* lowerUserMessage(message, options)]; | ||
| if (message.role === "assistant") | ||
| return [yield* lowerAssistantMessage(message, reasoningField)]; | ||
| return (yield* lowerToolMessages(message)).messages; | ||
| return [yield* lowerAssistantMessage(message, reasoningField, options)]; | ||
| return (yield* lowerToolMessages(message, options)).messages; | ||
| }); | ||
| const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request) { | ||
| const system = request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }]; | ||
| const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request, options) { | ||
| const system = request.system.length === 0 | ||
| ? [] | ||
| : request.system.some((part) => part.cache !== undefined) && options.cacheControl !== undefined | ||
| ? [ | ||
| { | ||
| role: "system", | ||
| content: request.system.map((part) => ({ | ||
| type: "text", | ||
| text: part.text, | ||
| cache_control: options.cacheControl?.(part.cache), | ||
| })), | ||
| }, | ||
| ] | ||
| : [{ role: "system", content: ProviderShared.joinText(request.system) }]; | ||
| const messages = [...system]; | ||
@@ -313,3 +354,9 @@ const pendingImages = []; | ||
| if (pendingImages.length > 0) { | ||
| messages.push({ role: "user", content: [...pendingImages.splice(0), { type: "text", text: part.text }] }); | ||
| messages.push({ | ||
| role: "user", | ||
| content: [ | ||
| ...pendingImages.splice(0), | ||
| { type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) }, | ||
| ], | ||
| }); | ||
| continue; | ||
@@ -319,14 +366,30 @@ } | ||
| if (previous?.role === "user" && typeof previous.content === "string") | ||
| messages[messages.length - 1] = { role: "user", content: `${previous.content}\n${part.text}` }; | ||
| messages[messages.length - 1] = options.cacheControl?.(part.cache) | ||
| ? { | ||
| role: "user", | ||
| content: [ | ||
| { type: "text", text: previous.content }, | ||
| { type: "text", text: part.text, cache_control: options.cacheControl(part.cache) }, | ||
| ], | ||
| } | ||
| : { role: "user", content: `${previous.content}\n${part.text}` }; | ||
| else if (previous?.role === "user" && Array.isArray(previous.content)) | ||
| messages[messages.length - 1] = { | ||
| role: "user", | ||
| content: [...previous.content, { type: "text", text: part.text }], | ||
| content: [ | ||
| ...previous.content, | ||
| { type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) }, | ||
| ], | ||
| }; | ||
| else | ||
| messages.push({ role: "user", content: part.text }); | ||
| messages.push(options.cacheControl?.(part.cache) | ||
| ? { | ||
| role: "user", | ||
| content: [{ type: "text", text: part.text, cache_control: options.cacheControl(part.cache) }], | ||
| } | ||
| : { role: "user", content: part.text }); | ||
| continue; | ||
| } | ||
| if (message.role === "tool") { | ||
| const lowered = yield* lowerToolMessages(message); | ||
| const lowered = yield* lowerToolMessages(message, options); | ||
| messages.push(...lowered.messages); | ||
@@ -337,3 +400,3 @@ pendingImages.push(...lowered.images); | ||
| flushImages(); | ||
| messages.push(...(yield* lowerMessage(message, request.model.compatibility?.reasoningField))); | ||
| messages.push(...(yield* lowerMessage(message, request.model.compatibility?.reasoningField, options))); | ||
| } | ||
@@ -350,3 +413,3 @@ flushImages(); | ||
| }; | ||
| const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (request) { | ||
| export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (request, options = {}) { | ||
| // `fromRequest` returns the provider body only. Endpoint, auth, framing, | ||
@@ -362,6 +425,6 @@ // validation, and HTTP execution are composed by `Route.make`. | ||
| model: request.model.id, | ||
| messages: yield* lowerMessages(request), | ||
| messages: yield* lowerMessages(request, options), | ||
| tools: request.tools.length === 0 | ||
| ? undefined | ||
| : request.tools.map((tool) => lowerTool(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility))), | ||
| : request.tools.map((tool) => lowerTool(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility), options)), | ||
| tool_choice: request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined, | ||
@@ -368,0 +431,0 @@ stream: true, |
@@ -14,3 +14,15 @@ import { Route, type RouteRoutedModelInput } from "../route/client"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -21,2 +33,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -35,2 +51,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -46,5 +66,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -54,3 +78,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -63,2 +86,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -65,0 +93,0 @@ readonly temperature?: number | undefined; |
@@ -28,3 +28,15 @@ import { type AtLeastOne, type ProviderAuthOption } from "../route/auth-options"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -35,2 +47,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -49,2 +65,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -60,5 +80,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -68,3 +92,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -77,2 +100,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -79,0 +107,0 @@ readonly temperature?: number | undefined; |
@@ -35,3 +35,15 @@ import type { Config, Redacted } from "effect"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -42,2 +54,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -56,2 +72,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -67,5 +87,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -75,3 +99,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -84,2 +107,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -109,3 +137,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -116,2 +156,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -130,2 +174,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -141,5 +189,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -149,3 +201,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -158,2 +209,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -183,3 +239,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -190,2 +258,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -204,2 +276,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -215,5 +291,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -223,3 +303,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -232,2 +311,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -234,0 +318,0 @@ readonly temperature?: number | undefined; |
@@ -16,3 +16,15 @@ import { type ProviderAuthOption } from "../route/auth-options"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -23,2 +35,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -37,2 +53,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -48,5 +68,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -56,3 +80,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -65,2 +88,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -67,0 +95,0 @@ readonly temperature?: number | undefined; |
@@ -25,3 +25,15 @@ import type { ProviderPackage } from "../provider-package"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -32,2 +44,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -46,2 +62,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -57,5 +77,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -65,3 +89,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -74,2 +97,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -76,0 +104,0 @@ readonly temperature?: number | undefined; |
@@ -25,3 +25,15 @@ import { type ModelID } from "../schema"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -32,2 +44,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -46,2 +62,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -57,5 +77,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -65,3 +89,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -74,2 +97,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -76,0 +104,0 @@ readonly temperature?: number | undefined; |
@@ -14,3 +14,15 @@ import { type ProviderAuthOption } from "../route/auth-options"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -21,2 +33,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -35,2 +51,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -46,5 +66,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -54,3 +78,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -63,2 +86,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -65,0 +93,0 @@ readonly temperature?: number | undefined; |
@@ -13,7 +13,68 @@ import { Schema } from "effect"; | ||
| export declare const id: string & import("effect/Brand").Brand<"LLM.ProviderID">; | ||
| type OpenRouterString<Known extends string> = Known | (string & {}); | ||
| export interface OpenRouterProviderRouting { | ||
| readonly [key: string]: unknown; | ||
| readonly order?: ReadonlyArray<string>; | ||
| readonly allow_fallbacks?: boolean; | ||
| readonly require_parameters?: boolean; | ||
| readonly data_collection?: OpenRouterString<"allow" | "deny">; | ||
| readonly only?: ReadonlyArray<string>; | ||
| readonly ignore?: ReadonlyArray<string>; | ||
| readonly quantizations?: ReadonlyArray<string>; | ||
| readonly sort?: OpenRouterString<"price" | "throughput" | "latency">; | ||
| readonly max_price?: Readonly<{ | ||
| prompt?: number | string; | ||
| completion?: number | string; | ||
| image?: number | string; | ||
| audio?: number | string; | ||
| request?: number | string; | ||
| }>; | ||
| readonly zdr?: boolean; | ||
| } | ||
| export type OpenRouterPlugin = Readonly<{ | ||
| id: "web"; | ||
| max_results?: number; | ||
| search_prompt?: string; | ||
| engine?: OpenRouterString<"native" | "exa">; | ||
| }> | Readonly<{ | ||
| id: "file-parser"; | ||
| max_files?: number; | ||
| pdf?: { | ||
| engine?: string; | ||
| }; | ||
| }> | Readonly<{ | ||
| id: "moderation"; | ||
| }> | Readonly<{ | ||
| id: "response-healing"; | ||
| }> | Readonly<{ | ||
| id: "auto-router"; | ||
| allowed_models?: ReadonlyArray<string>; | ||
| }> | Readonly<{ | ||
| id: string & {}; | ||
| [key: string]: unknown; | ||
| }>; | ||
| export interface OpenRouterOptions { | ||
| readonly [key: string]: unknown; | ||
| readonly usage?: boolean | Record<string, unknown>; | ||
| readonly reasoning?: Record<string, unknown>; | ||
| readonly debug?: Readonly<{ | ||
| echo_upstream_body?: boolean; | ||
| }>; | ||
| readonly models?: ReadonlyArray<string>; | ||
| readonly plugins?: ReadonlyArray<OpenRouterPlugin>; | ||
| readonly promptCacheKey?: string; | ||
| readonly provider?: OpenRouterProviderRouting; | ||
| readonly reasoning?: Readonly<{ | ||
| enabled?: boolean; | ||
| exclude?: boolean; | ||
| effort?: OpenRouterString<"none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max">; | ||
| max_tokens?: number; | ||
| }>; | ||
| readonly usage?: boolean | Readonly<{ | ||
| include: boolean; | ||
| }>; | ||
| readonly user?: string; | ||
| readonly web_search_options?: Readonly<{ | ||
| max_results?: number; | ||
| search_prompt?: string; | ||
| engine?: OpenRouterString<"native" | "exa">; | ||
| }>; | ||
| } | ||
@@ -36,3 +97,15 @@ export type OpenRouterProviderOptionsInput = ProviderOptions & { | ||
| readonly role: Schema.Literal<"system">; | ||
| readonly content: Schema.String; | ||
| readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.Literal<"text">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.Literal<"image_url">; | ||
| readonly image_url: Schema.Struct<{ | ||
| readonly url: Schema.String; | ||
| }>; | ||
| }>]>>]>; | ||
| }>, Schema.Struct<{ | ||
@@ -43,2 +116,6 @@ readonly role: Schema.Literal<"user">; | ||
| readonly text: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, Schema.Struct<{ | ||
@@ -65,2 +142,6 @@ readonly type: Schema.Literal<"image_url">; | ||
| readonly reasoning_details: Schema.optional<Schema.Unknown>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>, Schema.Struct<{ | ||
@@ -70,2 +151,6 @@ readonly role: Schema.Literal<"tool">; | ||
| readonly content: Schema.String; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>]>>; | ||
@@ -79,2 +164,6 @@ tools: Schema.optional<Schema.$Array<Schema.Struct<{ | ||
| }>; | ||
| readonly cache_control: Schema.optional<Schema.Struct<{ | ||
| readonly type: Schema.Literal<"ephemeral">; | ||
| readonly ttl: Schema.optional<Schema.String>; | ||
| }>>; | ||
| }>>>; | ||
@@ -108,3 +197,15 @@ tool_choice: Schema.optional<Schema.Union<readonly [Schema.Literals<readonly ["auto", "none", "required"]>, Schema.Struct<{ | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -115,2 +216,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -129,2 +234,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -140,5 +249,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -148,3 +261,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -157,2 +269,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -220,3 +337,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -227,2 +356,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -241,2 +374,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -252,5 +389,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -260,3 +401,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -269,2 +409,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -295,3 +440,15 @@ readonly temperature?: number | undefined; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -302,2 +459,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -316,2 +477,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -327,5 +492,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -335,3 +504,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -344,2 +512,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -346,0 +519,0 @@ readonly temperature?: number | undefined; |
@@ -10,2 +10,3 @@ import { Effect, Schema } from "effect"; | ||
| import * as OpenAIChat from "../protocols/openai-chat"; | ||
| import { newBreakpoints, ttlBucket } from "../protocols/utils/cache"; | ||
| import { isRecord } from "../protocols/shared"; | ||
@@ -22,3 +23,3 @@ export const profile = OpenAICompatibleProfiles.profiles.openrouter; | ||
| schema: OpenRouterBody, | ||
| from: (request) => OpenAIChat.protocol.body.from(request).pipe(Effect.map((body) => { | ||
| from: (request) => OpenAIChat.fromRequest(request, { cacheControl: cacheControl() }).pipe(Effect.map((body) => { | ||
| const sourceAssistants = request.messages.filter((message) => message.role === "assistant"); | ||
@@ -52,12 +53,34 @@ let assistantIndex = 0; | ||
| }); | ||
| const cacheControl = () => { | ||
| const breakpoints = newBreakpoints(4); | ||
| return (cache) => { | ||
| if (cache === undefined || breakpoints.remaining === 0) | ||
| return undefined; | ||
| breakpoints.remaining -= 1; | ||
| return { | ||
| type: "ephemeral", | ||
| ...(ttlBucket(cache.ttlSeconds) === "1h" ? { ttl: "1h" } : {}), | ||
| }; | ||
| }; | ||
| }; | ||
| const bodyOptions = (input) => { | ||
| const openrouter = isRecord(input) ? input : {}; | ||
| const { promptCacheKey, ...options } = openrouter; | ||
| return { | ||
| ...(openrouter.usage === true | ||
| ...options, | ||
| ...(openrouter.usage === undefined || openrouter.usage === true | ||
| ? { usage: { include: true } } | ||
| : isRecord(openrouter.usage) | ||
| ? { usage: openrouter.usage } | ||
| : {}), | ||
| : openrouter.usage === false | ||
| ? { usage: { include: false } } | ||
| : isRecord(openrouter.usage) | ||
| ? { usage: openrouter.usage } | ||
| : {}), | ||
| ...(Array.isArray(openrouter.models) ? { models: openrouter.models } : {}), | ||
| ...(isRecord(openrouter.provider) ? { provider: openrouter.provider } : {}), | ||
| ...(Array.isArray(openrouter.plugins) ? { plugins: openrouter.plugins } : {}), | ||
| ...(isRecord(openrouter.web_search_options) ? { web_search_options: openrouter.web_search_options } : {}), | ||
| ...(isRecord(openrouter.debug) ? { debug: openrouter.debug } : {}), | ||
| ...(typeof openrouter.user === "string" ? { user: openrouter.user } : {}), | ||
| ...(isRecord(openrouter.reasoning) ? { reasoning: openrouter.reasoning } : {}), | ||
| ...(typeof openrouter.promptCacheKey === "string" ? { prompt_cache_key: openrouter.promptCacheKey } : {}), | ||
| ...(typeof promptCacheKey === "string" ? { prompt_cache_key: promptCacheKey } : {}), | ||
| }; | ||
@@ -64,0 +87,0 @@ }; |
@@ -24,3 +24,15 @@ import { type ProviderAuthOption } from "../route/auth-options"; | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| readonly content: string | readonly ({ | ||
| readonly type: "text"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
| readonly type: "image_url"; | ||
| readonly image_url: { | ||
| readonly url: string; | ||
| }; | ||
| })[]; | ||
| } | { | ||
@@ -31,2 +43,6 @@ readonly role: "user"; | ||
| readonly text: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| } | { | ||
@@ -45,2 +61,6 @@ readonly type: "image_url"; | ||
| readonly reasoning_text?: string | undefined; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| readonly tool_calls?: readonly { | ||
@@ -56,5 +76,9 @@ readonly id: string; | ||
| } | { | ||
| readonly content: string; | ||
| readonly role: "tool"; | ||
| readonly tool_call_id: string; | ||
| readonly content: string; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| })[]; | ||
@@ -64,3 +88,2 @@ readonly stream: true; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly function: { | ||
@@ -73,2 +96,7 @@ readonly name: string; | ||
| }; | ||
| readonly type: "function"; | ||
| readonly cache_control?: { | ||
| readonly type: "ephemeral"; | ||
| readonly ttl?: string | undefined; | ||
| } | undefined; | ||
| }[] | undefined; | ||
@@ -75,0 +103,0 @@ readonly temperature?: number | undefined; |
@@ -87,2 +87,3 @@ import { Schema } from "effect"; | ||
| readonly providerExecuted: Schema.optional<Schema.Boolean>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -137,2 +138,3 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; | ||
| readonly encrypted: Schema.optional<Schema.String>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -160,2 +162,3 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; | ||
| readonly providerExecuted: Schema.optional<Schema.Boolean>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -206,2 +209,3 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; | ||
| readonly encrypted: Schema.optional<Schema.String>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -232,2 +236,3 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; | ||
| readonly providerExecuted: Schema.optional<Schema.Boolean>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -278,2 +283,3 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; | ||
| readonly encrypted: Schema.optional<Schema.String>; | ||
| readonly cache: Schema.optional<typeof CacheHint>; | ||
| readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>; | ||
@@ -280,0 +286,0 @@ readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>; |
@@ -106,2 +106,3 @@ import { Schema } from "effect"; | ||
| providerExecuted: Schema.optional(Schema.Boolean), | ||
| cache: Schema.optional(CacheHint), | ||
| metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), | ||
@@ -137,2 +138,3 @@ providerMetadata: Schema.optional(ProviderMetadata), | ||
| encrypted: Schema.optional(Schema.String), | ||
| cache: Schema.optional(CacheHint), | ||
| metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), | ||
@@ -139,0 +141,0 @@ providerMetadata: Schema.optional(ProviderMetadata), |
+3
-3
| { | ||
| "$schema": "https://json.schemastore.org/package.json", | ||
| "version": "0.0.0-next-16605", | ||
| "version": "0.0.0-next-16607", | ||
| "name": "@opencode-ai/ai", | ||
@@ -33,3 +33,3 @@ "type": "module", | ||
| "@effect/platform-node": "4.0.0-beta.101", | ||
| "@opencode-ai/http-recorder": "0.0.0-next-16605", | ||
| "@opencode-ai/http-recorder": "0.0.0-next-16607", | ||
| "@tsconfig/bun": "1.0.9", | ||
@@ -43,3 +43,3 @@ "@types/bun": "1.3.13", | ||
| "@smithy/util-utf8": "4.2.2", | ||
| "@opencode-ai/schema": "0.0.0-next-16605", | ||
| "@opencode-ai/schema": "0.0.0-next-16607", | ||
| "aws4fetch": "1.0.20", | ||
@@ -46,0 +46,0 @@ "effect": "4.0.0-beta.101", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1114987
3.01%26116
3.51%+ Added
- Removed