@opencode-ai/ai
Advanced tools
| import type { WebSocketChannelDriver } from "../route/transport/index.js"; | ||
| export interface DriverInput { | ||
| readonly id: string; | ||
| readonly name: string; | ||
| readonly request: Readonly<Record<string, unknown>>; | ||
| readonly message: string; | ||
| readonly base: WebSocketChannelDriver; | ||
| } | ||
| export declare const driver: (input: DriverInput) => WebSocketChannelDriver; | ||
| export declare const OpenResponsesContinuation: { | ||
| readonly driver: (input: DriverInput) => WebSocketChannelDriver; | ||
| }; |
| import { AIError, TransportReason } from "../schema/index.js"; | ||
| import { Effect, Option, Schema } from "effect"; | ||
| import * as ProviderShared from "./shared.js"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| const PROTOCOL = "open-responses.websocket.v1"; | ||
| const VERSION = 1; | ||
| const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event); | ||
| const checkpointValue = (checkpoint) => { | ||
| if (checkpoint?.protocol !== PROTOCOL || !ProviderShared.isRecord(checkpoint.value)) | ||
| return undefined; | ||
| if (checkpoint.value.version !== VERSION) | ||
| return undefined; | ||
| if (typeof checkpoint.value.responseID !== "string" || checkpoint.value.responseID.trim().length === 0) | ||
| return undefined; | ||
| if (!ProviderShared.isRecord(checkpoint.value.request) || !Array.isArray(checkpoint.value.output)) | ||
| return undefined; | ||
| return { | ||
| version: VERSION, | ||
| responseID: checkpoint.value.responseID, | ||
| request: checkpoint.value.request, | ||
| output: checkpoint.value.output, | ||
| }; | ||
| }; | ||
| const canonical = (value) => { | ||
| if (value === undefined) | ||
| return "undefined"; | ||
| if (Array.isArray(value)) | ||
| return `[${value.map(canonical).join(",")}]`; | ||
| if (!ProviderShared.isRecord(value)) | ||
| return ProviderShared.encodeJson(value); | ||
| return `{${Object.keys(value) | ||
| .sort() | ||
| .map((key) => `${ProviderShared.encodeJson(key)}:${canonical(value[key])}`) | ||
| .join(",")}}`; | ||
| }; | ||
| const json = (value) => { | ||
| if (typeof value !== "string") | ||
| return value; | ||
| return Option.getOrElse(Schema.decodeUnknownOption(ProviderShared.Json)(value), () => value); | ||
| }; | ||
| const comparable = (value) => { | ||
| if (!ProviderShared.isRecord(value)) | ||
| return value; | ||
| if (value.type === "message" && value.role === "assistant") | ||
| return { | ||
| role: "assistant", | ||
| content: value.content, | ||
| ...(value.phase === undefined ? {} : { phase: value.phase }), | ||
| }; | ||
| if (value.type === "function_call") | ||
| return { | ||
| type: value.type, | ||
| call_id: value.call_id, | ||
| name: value.name, | ||
| arguments: json(value.arguments), | ||
| }; | ||
| if (value.type === "reasoning") | ||
| return { | ||
| type: value.type, | ||
| summary: value.summary, | ||
| encrypted_content: value.encrypted_content, | ||
| }; | ||
| return value; | ||
| }; | ||
| const invariant = (request) => { | ||
| const { type: _type, input: _input, previous_response_id: _previousResponseID, ...rest } = request; | ||
| return rest; | ||
| }; | ||
| const incremental = (request, checkpoint) => { | ||
| const input = request.input; | ||
| const previousInput = checkpoint.request.input; | ||
| if (!Array.isArray(input) || !Array.isArray(previousInput)) | ||
| return undefined; | ||
| if (canonical(invariant(request)) !== canonical(invariant(checkpoint.request))) | ||
| return undefined; | ||
| const baseline = [...previousInput, ...checkpoint.output]; | ||
| if (input.length <= baseline.length) | ||
| return undefined; | ||
| if (!baseline.every((item, index) => canonical(comparable(item)) === canonical(comparable(input[index])))) | ||
| return undefined; | ||
| return input.slice(baseline.length); | ||
| }; | ||
| const code = (event) => event.code || event.error?.code || event.response?.error?.code || undefined; | ||
| const rejected = (input, observation, recovery) => ({ | ||
| type: "rejected", | ||
| recovery, | ||
| error: new AIError({ | ||
| module: input.id, | ||
| method: "stream", | ||
| reason: new TransportReason({ | ||
| message: observation.error.message, | ||
| transport: "websocket", | ||
| operation: "read", | ||
| phase: "receive", | ||
| delivery: "rejected", | ||
| recovery, | ||
| }), | ||
| }), | ||
| }); | ||
| export const driver = (input) => { | ||
| const { previous_response_id: _previousResponseID, ...request } = input.request; | ||
| let output = []; | ||
| return { | ||
| create: (checkpoint) => Effect.sync(() => { | ||
| output = []; | ||
| const previous = checkpointValue(checkpoint); | ||
| const delta = previous ? incremental(request, previous) : undefined; | ||
| if (!previous || !delta) | ||
| return { message: ProviderShared.encodeJson(request), mode: "full" }; | ||
| return { | ||
| message: ProviderShared.encodeJson({ ...request, input: delta, previous_response_id: previous.responseID }), | ||
| mode: "incremental", | ||
| }; | ||
| }), | ||
| observe: (create, frame) => Effect.gen(function* () { | ||
| const event = yield* decodeEvent(frame).pipe(Effect.mapError(() => ProviderShared.eventError(input.id, `Invalid ${input.name} WebSocket event`, frame))); | ||
| const observation = yield* input.base.observe(create, frame); | ||
| if (event.type === "response.output_item.done" && event.item) | ||
| output.push(event.item); | ||
| if (observation.type === "provider-failure") { | ||
| const rejection = code(event); | ||
| if (rejection === "previous_response_not_found") | ||
| return rejected(input, observation, "retry-full"); | ||
| if (rejection === "websocket_connection_limit_reached") | ||
| return rejected(input, observation, "rotate-and-retry-full"); | ||
| } | ||
| if (observation.type !== "completed") | ||
| return observation; | ||
| const responseID = event.response?.id; | ||
| if (!responseID || responseID.trim().length === 0) | ||
| return observation; | ||
| return { | ||
| ...observation, | ||
| checkpoint: { | ||
| protocol: PROTOCOL, | ||
| value: { version: VERSION, responseID, request, output: output.slice() }, | ||
| }, | ||
| }; | ||
| }), | ||
| }; | ||
| }; | ||
| export const OpenResponsesContinuation = { driver }; |
| import { Effect } from "effect"; | ||
| import { type AIError, type ToolResultPart } from "../../schema/index.js"; | ||
| import { OpenResponses } from "../open-responses.js"; | ||
| export type Item = OpenResponses.StreamItem & { | ||
| readonly id: string; | ||
| readonly status?: string; | ||
| readonly action?: unknown; | ||
| readonly queries?: unknown; | ||
| readonly results?: unknown; | ||
| readonly code?: string; | ||
| readonly container_id?: string; | ||
| readonly outputs?: unknown; | ||
| readonly server_label?: string; | ||
| readonly output?: unknown; | ||
| readonly result?: string; | ||
| readonly output_format?: "png" | "jpeg" | "webp"; | ||
| readonly error?: unknown; | ||
| }; | ||
| export interface Definition { | ||
| readonly name: string; | ||
| readonly input: (item: Item) => unknown; | ||
| readonly result?: (item: Item) => Effect.Effect<ToolResultPart["result"], AIError>; | ||
| } | ||
| export type Definitions = Readonly<Record<string, Definition>>; | ||
| export declare const isItem: <Tools extends Definitions>(item: OpenResponses.StreamItem, tools: Tools) => item is Item; | ||
| export declare const onDone: (state: OpenResponses.ParserState, item: Item, tools: Definitions) => Effect.Effect<OpenResponses.StepResult, AIError>; | ||
| export * as ResponsesHostedTools from "./responses-hosted-tools.js"; |
| import { Effect } from "effect"; | ||
| import { LLMEvent } from "../../schema/index.js"; | ||
| import { OpenResponses } from "../open-responses.js"; | ||
| import { Lifecycle } from "./lifecycle.js"; | ||
| export const isItem = (item, tools) => item.type in tools && typeof item.id === "string" && item.id.length > 0; | ||
| export const onDone = Effect.fn("ResponsesHostedTools.onDone")(function* (state, item, tools) { | ||
| const tool = tools[item.type]; | ||
| if (!tool) | ||
| return [state, []]; | ||
| const providerMetadata = OpenResponses.providerMetadata(state, { itemId: item.id }); | ||
| const events = []; | ||
| const lifecycle = Lifecycle.stepStart(state.lifecycle, events); | ||
| events.push(LLMEvent.toolCall({ | ||
| id: item.id, | ||
| name: tool.name, | ||
| input: tool.input(item), | ||
| providerExecuted: true, | ||
| providerMetadata, | ||
| }), LLMEvent.toolResult({ | ||
| id: item.id, | ||
| name: tool.name, | ||
| result: tool.result | ||
| ? yield* tool.result(item) | ||
| : item.error !== undefined && item.error !== null | ||
| ? { type: "error", value: item.error } | ||
| : { type: "json", value: item }, | ||
| providerExecuted: true, | ||
| providerMetadata, | ||
| })); | ||
| return [{ ...state, lifecycle }, events]; | ||
| }); | ||
| export * as ResponsesHostedTools from "./responses-hosted-tools.js"; |
| import { Protocol } from "../route/protocol.js"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| export declare const protocol: Protocol<{ | ||
| readonly input: readonly ({ | ||
| readonly type: "reasoning"; | ||
| readonly summary: readonly { | ||
| readonly type: "summary_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly id?: string | undefined; | ||
| readonly encrypted_content?: string | null | undefined; | ||
| } | { | ||
| readonly type: "item_reference"; | ||
| readonly id: string; | ||
| } | { | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| } | { | ||
| readonly role: "developer"; | ||
| readonly content: string; | ||
| } | { | ||
| readonly role: "user"; | ||
| readonly content: readonly ({ | ||
| readonly type: "input_image"; | ||
| readonly image_url: string; | ||
| } | { | ||
| readonly type: "input_file"; | ||
| readonly filename: string; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
| readonly type: "function_call"; | ||
| readonly name: string; | ||
| readonly arguments: string; | ||
| readonly call_id: string; | ||
| readonly id?: string | undefined; | ||
| } | { | ||
| readonly type: "function_call_output"; | ||
| readonly call_id: string; | ||
| readonly output: string | readonly ({ | ||
| readonly type: "input_image"; | ||
| readonly image_url: string; | ||
| } | { | ||
| readonly type: "input_file"; | ||
| readonly filename: string; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| })[]; | ||
| readonly model: string; | ||
| readonly stream: true; | ||
| readonly metadata?: { | ||
| readonly [x: string]: string; | ||
| } | undefined; | ||
| readonly instructions?: string | undefined; | ||
| readonly reasoning?: { | ||
| readonly summary?: "auto" | "concise" | "detailed" | undefined; | ||
| readonly effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined; | ||
| } | undefined; | ||
| readonly tools?: readonly { | ||
| readonly type: "function"; | ||
| readonly description: string; | ||
| readonly name: string; | ||
| readonly parameters: { | ||
| readonly [x: string]: unknown; | ||
| }; | ||
| readonly strict?: boolean | undefined; | ||
| }[] | undefined; | ||
| readonly text?: { | ||
| readonly verbosity?: import("./utils/open-responses-options.js").TextVerbosity | undefined; | ||
| } | undefined; | ||
| readonly temperature?: number | undefined; | ||
| readonly tool_choice?: "required" | "auto" | "none" | { | ||
| readonly type: "function"; | ||
| readonly name: string; | ||
| } | { | ||
| readonly type: "allowed_tools"; | ||
| readonly mode: "required" | "auto" | "none"; | ||
| readonly tools: readonly { | ||
| readonly type: "function"; | ||
| readonly name: string; | ||
| }[]; | ||
| } | undefined; | ||
| readonly top_p?: number | undefined; | ||
| readonly store?: boolean | undefined; | ||
| readonly include?: readonly import("./utils/open-responses-options.js").ResponseIncludable[] | undefined; | ||
| readonly truncation?: "auto" | "disabled" | undefined; | ||
| readonly stream_options?: { | ||
| readonly include_obfuscation?: boolean | undefined; | ||
| } | undefined; | ||
| readonly prompt_cache_key?: string | undefined; | ||
| readonly frequency_penalty?: number | undefined; | ||
| readonly presence_penalty?: number | undefined; | ||
| readonly safety_identifier?: string | undefined; | ||
| readonly top_logprobs?: number | undefined; | ||
| readonly service_tier?: "default" | "auto" | "flex" | "priority" | undefined; | ||
| readonly max_output_tokens?: number | undefined; | ||
| readonly max_tool_calls?: number | undefined; | ||
| readonly parallel_tool_calls?: boolean | undefined; | ||
| }, string, { | ||
| readonly [x: string]: unknown; | ||
| readonly type: string; | ||
| readonly status?: unknown; | ||
| readonly code?: string | null | undefined; | ||
| readonly message?: string | undefined; | ||
| readonly headers?: unknown; | ||
| readonly text?: string | undefined; | ||
| readonly error?: { | ||
| readonly type?: string | null | undefined; | ||
| readonly code?: string | null | undefined; | ||
| readonly message?: string | null | undefined; | ||
| readonly param?: string | null | undefined; | ||
| } | null | undefined; | ||
| readonly item?: { | ||
| readonly [x: string]: unknown; | ||
| readonly type: string; | ||
| readonly id?: string | undefined; | ||
| readonly name?: string | undefined; | ||
| readonly arguments?: string | undefined; | ||
| readonly encrypted_content?: string | null | undefined; | ||
| readonly call_id?: string | undefined; | ||
| } | undefined; | ||
| readonly delta?: string | undefined; | ||
| readonly response?: { | ||
| readonly [x: string]: unknown; | ||
| readonly id?: string | undefined; | ||
| readonly error?: { | ||
| readonly type?: string | null | undefined; | ||
| readonly code?: string | null | undefined; | ||
| readonly message?: string | null | undefined; | ||
| readonly param?: string | null | undefined; | ||
| } | null | undefined; | ||
| readonly usage?: { | ||
| readonly input_tokens?: number | undefined; | ||
| readonly output_tokens?: number | undefined; | ||
| readonly output_tokens_details?: { | ||
| readonly reasoning_tokens?: number | undefined; | ||
| } | null | undefined; | ||
| readonly total_tokens?: number | undefined; | ||
| readonly input_tokens_details?: { | ||
| readonly cached_tokens?: number | undefined; | ||
| readonly cache_write_tokens?: number | undefined; | ||
| } | null | undefined; | ||
| } | null | undefined; | ||
| readonly service_tier?: string | null | undefined; | ||
| readonly incomplete_details?: { | ||
| readonly reason?: string | undefined; | ||
| } | null | undefined; | ||
| } | undefined; | ||
| readonly param?: string | null | undefined; | ||
| readonly status_code?: unknown; | ||
| readonly item_id?: string | undefined; | ||
| readonly summary_index?: number | undefined; | ||
| }, OpenResponses.ParserState>; | ||
| export * as XAIResponses from "./xai-responses.js"; |
| import { Effect } from "effect"; | ||
| import { Protocol } from "../route/protocol.js"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| import { ProviderShared } from "./shared.js"; | ||
| import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js"; | ||
| const ADAPTER = "xai-responses"; | ||
| const NAME = "xAI Responses"; | ||
| const extension = { | ||
| id: ADAPTER, | ||
| name: NAME, | ||
| }; | ||
| const HOSTED_TOOLS = { | ||
| web_search_call: { name: "web_search", input: (item) => item.action ?? {} }, | ||
| x_search_call: { name: "x_search", input: (item) => item.action ?? {} }, | ||
| file_search_call: { name: "file_search", input: (item) => ({ queries: item.queries ?? [] }) }, | ||
| code_interpreter_call: { | ||
| name: "code_interpreter", | ||
| input: (item) => ({ code: item.code, container_id: item.container_id }), | ||
| }, | ||
| image_generation_call: { name: "image_generation", input: () => ({}) }, | ||
| mcp_call: { | ||
| name: "mcp", | ||
| input: (item) => ({ server_label: item.server_label, name: item.name, arguments: item.arguments }), | ||
| }, | ||
| }; | ||
| const step = (state, event) => { | ||
| if (event.type === "response.reasoning_text.delta" || event.type === "response.reasoning_summary.delta") | ||
| return event.item_id | ||
| ? Effect.succeed(OpenResponses.onReasoningDelta(state, event, event.item_id)) | ||
| : ProviderShared.eventError(ADAPTER, `${event.type} is missing item_id`); | ||
| if (event.type === "response.reasoning_text.done" || event.type === "response.reasoning_summary.done") | ||
| return event.item_id | ||
| ? Effect.succeed(OpenResponses.onReasoningDone(state, event)) | ||
| : ProviderShared.eventError(ADAPTER, `${event.type} is missing item_id`); | ||
| if (event.type === "response.output_item.done" && event.item && ResponsesHostedTools.isItem(event.item, HOSTED_TOOLS)) | ||
| return ResponsesHostedTools.onDone(state, event.item, HOSTED_TOOLS); | ||
| return OpenResponses.step(state, event); | ||
| }; | ||
| export const protocol = Protocol.make({ | ||
| id: ADAPTER, | ||
| body: OpenResponses.protocol.body, | ||
| stream: { | ||
| event: OpenResponses.protocol.stream.event, | ||
| initial: (request) => OpenResponses.initial(request, extension), | ||
| step, | ||
| terminal: OpenResponses.terminal, | ||
| }, | ||
| }); | ||
| export * as XAIResponses from "./xai-responses.js"; |
@@ -11,1 +11,2 @@ export * as AnthropicMessages from "./anthropic-messages.js"; | ||
| export * as OpenResponsesChannel from "./open-responses-channel.js"; | ||
| export * as XAIResponses from "./xai-responses.js"; |
@@ -11,1 +11,2 @@ export * as AnthropicMessages from "./anthropic-messages.js"; | ||
| export * as OpenResponsesChannel from "./open-responses-channel.js"; | ||
| export * as XAIResponses from "./xai-responses.js"; |
@@ -10,7 +10,2 @@ import { Headers } from "effect/unstable/http"; | ||
| readonly headers?: (headers: Headers.Headers) => Headers.Headers; | ||
| readonly driver?: (input: { | ||
| readonly request: Readonly<Record<string, unknown>>; | ||
| readonly message: string; | ||
| readonly base: WebSocketChannelDriver; | ||
| }) => WebSocketChannelDriver; | ||
| } | ||
@@ -17,0 +12,0 @@ export interface Prepared { |
@@ -7,2 +7,3 @@ import { Effect, Schema, Stream } from "effect"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| import { OpenResponsesContinuation } from "./open-responses-continuation.js"; | ||
| const WebSocketResponseCreate = Schema.StructWithRest(Schema.Struct({ type: Schema.tag("response.create") }), [ | ||
@@ -91,3 +92,9 @@ Schema.Record(Schema.String, Schema.Unknown), | ||
| rotateAfterMs: options.rotateAfterMs, | ||
| driver: options.driver?.({ request: create.request, message: create.message, base }) ?? base, | ||
| driver: OpenResponsesContinuation.driver({ | ||
| id: options.id, | ||
| name: options.name, | ||
| request: create.request, | ||
| message: create.message, | ||
| base, | ||
| }), | ||
| }; | ||
@@ -94,0 +101,0 @@ }) |
@@ -16,7 +16,7 @@ import { Effect, Schema } from "effect"; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>]>; | ||
| export type MediaInput = Schema.Schema.Type<typeof MediaInput>; | ||
| export declare const MessagePhase: Schema.Literals<readonly ["commentary", "final_answer"]>; | ||
| export declare const MessagePhase: Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>; | ||
| type MessagePhase = Schema.Schema.Type<typeof MessagePhase>; | ||
@@ -40,4 +40,4 @@ export declare const InputItem: Schema.Union<readonly [Schema.Struct<{ | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>]>]>>; | ||
@@ -52,3 +52,3 @@ }>, Schema.Struct<{ | ||
| }>>; | ||
| readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>; | ||
| readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>; | ||
| }>, Schema.Struct<{ | ||
@@ -83,4 +83,7 @@ readonly type: Schema.tag<"reasoning">; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"input_video">; | ||
| readonly video_url: Schema.String; | ||
| }>]>>]>; | ||
@@ -136,4 +139,4 @@ }>]>; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>]>]>>; | ||
@@ -148,3 +151,3 @@ }>, Schema.Struct<{ | ||
| }>>; | ||
| readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>; | ||
| readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>; | ||
| }>, Schema.Struct<{ | ||
@@ -179,4 +182,7 @@ readonly type: Schema.tag<"reasoning">; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"input_video">; | ||
| readonly video_url: Schema.String; | ||
| }>]>>]>; | ||
@@ -249,4 +255,4 @@ }>]>>; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>]>]>>; | ||
@@ -261,3 +267,3 @@ }>, Schema.Struct<{ | ||
| }>>; | ||
| readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>; | ||
| readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>; | ||
| }>, Schema.Struct<{ | ||
@@ -292,4 +298,7 @@ readonly type: Schema.tag<"reasoning">; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"input_video">; | ||
| readonly video_url: Schema.String; | ||
| }>]>>]>; | ||
@@ -446,3 +455,2 @@ }>]>>; | ||
| }) => MediaInput | undefined; | ||
| readonly messagePhase?: (value: unknown) => MessagePhase | null | undefined; | ||
| } | ||
@@ -561,4 +569,4 @@ export interface ParserState { | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -576,3 +584,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -593,7 +601,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -871,4 +882,4 @@ })[]; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -886,3 +897,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -903,7 +914,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -1042,4 +1056,4 @@ })[]; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -1057,3 +1071,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -1074,7 +1088,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -1081,0 +1098,0 @@ })[]; |
@@ -28,5 +28,9 @@ import { Effect, Schema } from "effect"; | ||
| filename: Schema.String, | ||
| file_data: Schema.String, | ||
| mime_type: Schema.optional(Schema.String), | ||
| file_data: Schema.optional(Schema.String), | ||
| file_url: Schema.optional(Schema.String), | ||
| }); | ||
| const OpenResponsesInputVideo = Schema.Struct({ | ||
| type: Schema.tag("input_video"), | ||
| video_url: Schema.String, | ||
| }); | ||
| const MediaInput = Schema.Union([OpenResponsesInputImage, OpenResponsesInputFile]); | ||
@@ -38,3 +42,3 @@ const OpenResponsesInputContent = Schema.Union([OpenResponsesInputText, MediaInput]); | ||
| }); | ||
| export const MessagePhase = Schema.Literals(["commentary", "final_answer"]); | ||
| export const MessagePhase = Schema.NullOr(Schema.Literals(["commentary", "final_answer"])); | ||
| const OpenResponsesReasoningSummaryText = Schema.Struct({ | ||
@@ -61,2 +65,3 @@ type: Schema.tag("summary_text"), | ||
| OpenResponsesInputFile, | ||
| OpenResponsesInputVideo, | ||
| ]); | ||
@@ -288,3 +293,3 @@ const OpenResponsesFunctionCallOutput = Schema.Union([ | ||
| }; | ||
| const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension) { | ||
| const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension, target) { | ||
| const media = ProviderShared.normalizeMedia(part); | ||
@@ -294,10 +299,15 @@ const extended = extension.lowerMedia?.({ part, media, request }); | ||
| return extended; | ||
| const url = typeof part.data === "string" && (part.data.startsWith("https://") || part.data.startsWith("http://")) | ||
| ? part.data | ||
| : undefined; | ||
| if (!media.mime.startsWith("image/")) { | ||
| if (target === "tool-result" && media.mime.startsWith("video/")) | ||
| return { type: "input_video", video_url: url ?? media.dataUrl }; | ||
| return { | ||
| type: "input_file", | ||
| filename: part.filename ?? (media.mime === "application/pdf" ? "document.pdf" : "file"), | ||
| file_data: media.dataUrl, | ||
| ...(url ? { file_url: url } : { file_data: media.base64 }), | ||
| }; | ||
| } | ||
| return { type: "input_image", image_url: media.dataUrl }; | ||
| return { type: "input_image", image_url: url ?? media.dataUrl }; | ||
| }); | ||
@@ -308,5 +318,11 @@ const lowerUserContent = Effect.fnUntraced(function* (part, request, extension) { | ||
| if (part.type === "media") | ||
| return yield* lowerMedia(part, request, extension); | ||
| return yield* lowerMessageMedia(part, request, extension); | ||
| return yield* ProviderShared.unsupportedContent(extension.name, "user", ["text", "media"]); | ||
| }); | ||
| const lowerMessageMedia = Effect.fnUntraced(function* (part, request, extension) { | ||
| const lowered = yield* lowerMedia(part, request, extension, "message"); | ||
| if (lowered.type === "input_video") | ||
| return yield* ProviderShared.invalidRequest(`${extension.name} user messages do not support input_video`); | ||
| return lowered; | ||
| }); | ||
| // Tool results may carry structured text, images, and files. Keep media as provider-native | ||
@@ -317,4 +333,9 @@ // content instead of JSON-stringifying base64 into a prompt string. | ||
| return { type: "input_text", text: item.text }; | ||
| return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension); | ||
| return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension, "tool-result"); | ||
| }); | ||
| const lowerHostedToolResultContentItem = Effect.fnUntraced(function* (item, request, extension) { | ||
| if (item.type === "text") | ||
| return { type: "input_text", text: item.text }; | ||
| return yield* lowerMessageMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension); | ||
| }); | ||
| const lowerToolResultOutput = Effect.fnUntraced(function* (part, request, extension) { | ||
@@ -360,3 +381,3 @@ // Text/json/error results are encoded as a plain string for backward | ||
| const id = itemID(part.providerMetadata, providerMetadataKey); | ||
| const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase, extension) : undefined; | ||
| const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase) : undefined; | ||
| const group = groups.at(-1); | ||
@@ -421,3 +442,3 @@ if (group && group.id === id && group.phase === phase) | ||
| role: "user", | ||
| content: yield* Effect.forEach(content, (item) => lowerToolResultContentItem(item, request, extension)), | ||
| content: yield* Effect.forEach(content, (item) => lowerHostedToolResultContentItem(item, request, extension)), | ||
| }); | ||
@@ -930,3 +951,3 @@ } | ||
| messageItems: new Set(), | ||
| messagePhase: (value) => messagePhase(value, extension), | ||
| messagePhase, | ||
| messagePhases: {}, | ||
@@ -936,6 +957,6 @@ reasoningItems: {}, | ||
| }); | ||
| const messagePhase = (value, extension) => { | ||
| if (value === "commentary" || value === "final_answer") | ||
| const messagePhase = (value) => { | ||
| if (value === null || value === "commentary" || value === "final_answer") | ||
| return value; | ||
| return extension.messagePhase?.(value); | ||
| return undefined; | ||
| }; | ||
@@ -942,0 +963,0 @@ export const protocol = Protocol.make({ |
@@ -34,4 +34,4 @@ import { Route, type RouteRoutedLanguageModelInput } from "../route/client.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -49,3 +49,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -66,7 +66,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -73,0 +76,0 @@ })[]; |
@@ -6,3 +6,2 @@ import { Schema } from "effect"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| import { type Options } from "./open-responses-channel.js"; | ||
| export declare const DEFAULT_BASE_URL = "https://api.openai.com/v1"; | ||
@@ -12,12 +11,34 @@ export declare const PATH = "/responses"; | ||
| readonly stream: Schema.Literal<true>; | ||
| readonly tools: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| readonly description: Schema.String; | ||
| readonly parameters: Schema.$Record<Schema.String, Schema.Unknown>; | ||
| readonly strict: Schema.optional<Schema.Boolean>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"image_generation">; | ||
| readonly action: Schema.optional<Schema.Literals<readonly ["auto", "generate", "edit"]>>; | ||
| readonly background: Schema.optional<Schema.Literals<readonly ["auto", "opaque", "transparent"]>>; | ||
| readonly input_fidelity: Schema.optional<Schema.Literals<readonly ["low", "high"]>>; | ||
| readonly output_compression: Schema.optional<Schema.Int>; | ||
| readonly output_format: Schema.optional<Schema.Literals<readonly ["png", "jpeg", "webp"]>>; | ||
| readonly partial_images: Schema.optional<Schema.Int>; | ||
| readonly quality: Schema.optional<Schema.Literals<readonly ["auto", "low", "medium", "high"]>>; | ||
| readonly size: Schema.optional<Schema.String>; | ||
| }>]>>>; | ||
| readonly tool_choice: Schema.optional<Schema.Union<readonly [Schema.Union<readonly [Schema.Literals<readonly ["auto", "none", "required"]>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"allowed_tools">; | ||
| readonly mode: Schema.Literals<readonly ["auto", "none", "required"]>; | ||
| readonly tools: Schema.$Array<Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| }>>; | ||
| }>]>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"image_generation">; | ||
| }>]>>; | ||
| readonly model: Schema.String; | ||
| readonly input: Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.tag<"message">; | ||
| readonly id: Schema.optionalKey<Schema.String>; | ||
| readonly role: Schema.tag<"assistant">; | ||
| readonly content: Schema.$Array<Schema.Struct<{ | ||
| readonly type: Schema.tag<"output_text">; | ||
| readonly text: Schema.String; | ||
| }>>; | ||
| readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>; | ||
| }>, Schema.Union<readonly [Schema.Struct<{ | ||
| readonly role: Schema.tag<"system">; | ||
@@ -39,4 +60,4 @@ readonly content: Schema.String; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>]>]>>; | ||
@@ -51,3 +72,3 @@ }>, Schema.Struct<{ | ||
| }>>; | ||
| readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>; | ||
| readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>; | ||
| }>, Schema.Struct<{ | ||
@@ -82,37 +103,9 @@ readonly type: Schema.tag<"reasoning">; | ||
| readonly filename: Schema.String; | ||
| readonly file_data: Schema.String; | ||
| readonly mime_type: Schema.optional<Schema.String>; | ||
| readonly file_data: Schema.optional<Schema.String>; | ||
| readonly file_url: Schema.optional<Schema.String>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"input_video">; | ||
| readonly video_url: Schema.String; | ||
| }>]>>]>; | ||
| }>]>]>>; | ||
| readonly tools: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| readonly description: Schema.String; | ||
| readonly parameters: Schema.$Record<Schema.String, Schema.Unknown>; | ||
| readonly strict: Schema.optional<Schema.Boolean>; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"image_generation">; | ||
| readonly action: Schema.optional<Schema.Literals<readonly ["auto", "generate", "edit"]>>; | ||
| readonly background: Schema.optional<Schema.Literals<readonly ["auto", "opaque", "transparent"]>>; | ||
| readonly input_fidelity: Schema.optional<Schema.Literals<readonly ["low", "high"]>>; | ||
| readonly output_compression: Schema.optional<Schema.Int>; | ||
| readonly output_format: Schema.optional<Schema.Literals<readonly ["png", "jpeg", "webp"]>>; | ||
| readonly partial_images: Schema.optional<Schema.Int>; | ||
| readonly quality: Schema.optional<Schema.Literals<readonly ["auto", "low", "medium", "high"]>>; | ||
| readonly size: Schema.optional<Schema.String>; | ||
| }>]>>>; | ||
| readonly tool_choice: Schema.optional<Schema.Union<readonly [Schema.Union<readonly [Schema.Literals<readonly ["auto", "none", "required"]>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| }>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"allowed_tools">; | ||
| readonly mode: Schema.Literals<readonly ["auto", "none", "required"]>; | ||
| readonly tools: Schema.$Array<Schema.Struct<{ | ||
| readonly type: Schema.tag<"function">; | ||
| readonly name: Schema.String; | ||
| }>>; | ||
| }>]>, Schema.Struct<{ | ||
| readonly type: Schema.tag<"image_generation">; | ||
| }>]>>; | ||
| readonly model: Schema.String; | ||
| readonly instructions: Schema.optional<Schema.String>; | ||
@@ -172,4 +165,4 @@ readonly store: Schema.optional<Schema.Boolean>; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -187,3 +180,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -204,17 +197,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -364,4 +351,4 @@ readonly model: string; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -379,3 +366,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -396,17 +383,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -476,3 +457,3 @@ readonly model: string; | ||
| }, string>; | ||
| export declare const channelTransport: (options: Omit<Options, "driver">) => import("../route/transport/index.js").Transport<{ | ||
| export declare const channelTransport: (options: import("./open-responses-channel.js").Options) => import("../route/transport/index.js").Transport<{ | ||
| readonly input: readonly ({ | ||
@@ -503,4 +484,4 @@ readonly type: "reasoning"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -518,3 +499,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -535,17 +516,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -641,4 +616,4 @@ readonly model: string; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -656,3 +631,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -673,17 +648,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -779,4 +748,4 @@ readonly model: string; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -794,3 +763,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -811,17 +780,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -828,0 +791,0 @@ readonly model: string; |
@@ -8,10 +8,9 @@ import { Effect, Encoding, Schema } from "effect"; | ||
| import { HttpTransport } from "../route/transport/index.js"; | ||
| import { LLMEvent, LLMRequest } from "../schema/index.js"; | ||
| import { LLMRequest } from "../schema/index.js"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| import { optionalArray, ProviderShared } from "./shared.js"; | ||
| import { Lifecycle } from "./utils/lifecycle.js"; | ||
| import { OpenAIImage } from "./utils/openai-image.js"; | ||
| import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js"; | ||
| import { ToolSchemaProjection } from "./utils/tool-schema.js"; | ||
| import { OpenResponsesChannel } from "./open-responses-channel.js"; | ||
| import { OpenAIResponsesChannel } from "./openai-responses-channel.js"; | ||
| const ADAPTER = "openai-responses"; | ||
@@ -39,15 +38,4 @@ const NAME = "OpenAI Responses"; | ||
| ]); | ||
| const OpenAIResponsesInputItem = Schema.Union([ | ||
| Schema.Struct({ | ||
| type: Schema.tag("message"), | ||
| id: Schema.optionalKey(Schema.String), | ||
| role: Schema.tag("assistant"), | ||
| content: Schema.Array(Schema.Struct({ type: Schema.tag("output_text"), text: Schema.String })), | ||
| phase: Schema.optionalKey(Schema.NullOr(OpenResponses.MessagePhase)), | ||
| }), | ||
| OpenResponses.InputItem, | ||
| ]); | ||
| const OpenAIResponsesCoreFields = { | ||
| ...OpenResponses.coreFields, | ||
| input: Schema.Array(OpenAIResponsesInputItem), | ||
| tools: optionalArray(OpenAIResponsesTools), | ||
@@ -63,13 +51,2 @@ tool_choice: Schema.optional(OpenAIResponsesToolChoice), | ||
| name: NAME, | ||
| messagePhase: (value) => (value === null ? null : undefined), | ||
| lowerMedia: ({ part, media, request }) => { | ||
| if (request.model.provider !== "xai" || media.mime !== "application/pdf") | ||
| return undefined; | ||
| return { | ||
| type: "input_file", | ||
| filename: part.filename ?? "document.pdf", | ||
| file_data: media.base64, | ||
| mime_type: media.mime, | ||
| }; | ||
| }, | ||
| }; | ||
@@ -112,19 +89,2 @@ const nativeImageToolInput = (tool) => { | ||
| }); | ||
| const HOSTED_TOOLS = { | ||
| web_search_call: { name: "web_search", input: (item) => item.action ?? {} }, | ||
| web_search_preview_call: { name: "web_search_preview", input: (item) => item.action ?? {} }, | ||
| file_search_call: { name: "file_search", input: (item) => ({ queries: item.queries ?? [] }) }, | ||
| code_interpreter_call: { | ||
| name: "code_interpreter", | ||
| input: (item) => ({ code: item.code, container_id: item.container_id }), | ||
| }, | ||
| computer_use_call: { name: "computer_use", input: (item) => item.action ?? {} }, | ||
| image_generation_call: { name: "image_generation", input: () => ({}) }, | ||
| mcp_call: { | ||
| name: "mcp", | ||
| input: (item) => ({ server_label: item.server_label, name: item.name, arguments: item.arguments }), | ||
| }, | ||
| local_shell_call: { name: "local_shell", input: (item) => item.action ?? {} }, | ||
| }; | ||
| const isHostedToolItem = (item) => item.type in HOSTED_TOOLS && typeof item.id === "string" && item.id.length > 0; | ||
| const hostedToolResult = Effect.fn("OpenAIResponses.hostedToolResult")(function* (item) { | ||
@@ -148,22 +108,18 @@ const isError = item.error !== undefined && item.error !== null; | ||
| }); | ||
| const onHostedToolDone = Effect.fn("OpenAIResponses.onHostedToolDone")(function* (state, item) { | ||
| const tool = HOSTED_TOOLS[item.type]; | ||
| const providerMetadata = OpenResponses.providerMetadata(state, { itemId: item.id }); | ||
| const events = []; | ||
| const lifecycle = Lifecycle.stepStart(state.lifecycle, events); | ||
| events.push(LLMEvent.toolCall({ | ||
| id: item.id, | ||
| name: tool.name, | ||
| input: tool.input(item), | ||
| providerExecuted: true, | ||
| providerMetadata, | ||
| }), LLMEvent.toolResult({ | ||
| id: item.id, | ||
| name: tool.name, | ||
| result: yield* hostedToolResult(item), | ||
| providerExecuted: true, | ||
| providerMetadata, | ||
| })); | ||
| return [{ ...state, lifecycle }, events]; | ||
| }); | ||
| const HOSTED_TOOLS = { | ||
| web_search_call: { name: "web_search", input: (item) => item.action ?? {} }, | ||
| web_search_preview_call: { name: "web_search_preview", input: (item) => item.action ?? {} }, | ||
| file_search_call: { name: "file_search", input: (item) => ({ queries: item.queries ?? [] }) }, | ||
| code_interpreter_call: { | ||
| name: "code_interpreter", | ||
| input: (item) => ({ code: item.code, container_id: item.container_id }), | ||
| }, | ||
| computer_use_call: { name: "computer_use", input: (item) => item.action ?? {} }, | ||
| image_generation_call: { name: "image_generation", input: () => ({}), result: hostedToolResult }, | ||
| mcp_call: { | ||
| name: "mcp", | ||
| input: (item) => ({ server_label: item.server_label, name: item.name, arguments: item.arguments }), | ||
| }, | ||
| local_shell_call: { name: "local_shell", input: (item) => item.action ?? {} }, | ||
| }; | ||
| const step = (state, event) => { | ||
@@ -178,4 +134,4 @@ if (event.type === "response.reasoning_text.delta" || event.type === "response.reasoning_summary.delta") | ||
| : ProviderShared.eventError(ADAPTER, `${event.type} is missing item_id`); | ||
| if (event.type === "response.output_item.done" && event.item && isHostedToolItem(event.item)) | ||
| return onHostedToolDone(state, event.item); | ||
| if (event.type === "response.output_item.done" && event.item && ResponsesHostedTools.isItem(event.item, HOSTED_TOOLS)) | ||
| return ResponsesHostedTools.onDone(state, event.item, HOSTED_TOOLS); | ||
| return OpenResponses.step(state, event); | ||
@@ -199,6 +155,3 @@ }; | ||
| export const httpTransport = HttpTransport.sseJson.with(); | ||
| export const channelTransport = (options) => OpenResponsesChannel.transport({ | ||
| ...options, | ||
| driver: (input) => OpenAIResponsesChannel.driver({ id: options.id, name: options.name, ...input }), | ||
| }); | ||
| export const channelTransport = (OpenResponsesChannel.transport); | ||
| export const transport = channelTransport({ | ||
@@ -205,0 +158,0 @@ id: ADAPTER, |
@@ -144,4 +144,4 @@ import type { Route as RouteDef, RouteDefaultsInput } from "../route/client.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -159,3 +159,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -176,17 +176,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -193,0 +187,0 @@ readonly model: string; |
@@ -147,4 +147,4 @@ import { type AtLeastOne, type ProviderAuthOption } from "../route/auth-options.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -162,3 +162,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -179,17 +179,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -196,0 +190,0 @@ readonly model: string; |
@@ -47,4 +47,4 @@ import type { ProviderPackage } from "../provider-package.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -62,3 +62,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -79,7 +79,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -86,0 +89,0 @@ })[]; |
@@ -45,4 +45,4 @@ import type { ProviderPackage } from "../provider-package.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -60,3 +60,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -77,7 +77,10 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
@@ -84,0 +87,0 @@ })[]; |
@@ -132,4 +132,4 @@ import { type ProviderAuthOption } from "../route/auth-options.js"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
@@ -147,3 +147,3 @@ readonly type: "input_text"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| } | { | ||
@@ -164,17 +164,11 @@ readonly type: "function_call"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| readonly file_data?: string | undefined; | ||
| readonly file_url?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| } | { | ||
| readonly type: "input_video"; | ||
| readonly video_url: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
@@ -181,0 +175,0 @@ readonly model: string; |
+1
-135
@@ -114,137 +114,3 @@ import { type ProviderAuthOption } from "../route/auth-options.js"; | ||
| readonly presence_penalty?: number | undefined; | ||
| }, import("../route/transport/http.js").HttpPrepared<string>> | Route<{ | ||
| readonly input: readonly ({ | ||
| readonly type: "reasoning"; | ||
| readonly summary: readonly { | ||
| readonly type: "summary_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly id?: string | undefined; | ||
| readonly encrypted_content?: string | null | undefined; | ||
| } | { | ||
| readonly type: "item_reference"; | ||
| readonly id: string; | ||
| } | { | ||
| readonly role: "system"; | ||
| readonly content: string; | ||
| } | { | ||
| readonly role: "developer"; | ||
| readonly content: string; | ||
| } | { | ||
| readonly role: "user"; | ||
| readonly content: readonly ({ | ||
| readonly type: "input_image"; | ||
| readonly image_url: string; | ||
| } | { | ||
| readonly type: "input_file"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | undefined; | ||
| } | { | ||
| readonly type: "function_call"; | ||
| readonly name: string; | ||
| readonly arguments: string; | ||
| readonly call_id: string; | ||
| readonly id?: string | undefined; | ||
| } | { | ||
| readonly type: "function_call_output"; | ||
| readonly call_id: string; | ||
| readonly output: string | readonly ({ | ||
| readonly type: "input_image"; | ||
| readonly image_url: string; | ||
| } | { | ||
| readonly type: "input_file"; | ||
| readonly filename: string; | ||
| readonly file_data: string; | ||
| readonly mime_type?: string | undefined; | ||
| } | { | ||
| readonly type: "input_text"; | ||
| readonly text: string; | ||
| })[]; | ||
| } | { | ||
| readonly type: "message"; | ||
| readonly content: readonly { | ||
| readonly type: "output_text"; | ||
| readonly text: string; | ||
| }[]; | ||
| readonly role: "assistant"; | ||
| readonly id?: string | undefined; | ||
| readonly phase?: "commentary" | "final_answer" | null | undefined; | ||
| })[]; | ||
| readonly model: string; | ||
| readonly stream: true; | ||
| readonly metadata?: { | ||
| readonly [x: string]: string; | ||
| } | undefined; | ||
| readonly instructions?: string | undefined; | ||
| readonly reasoning?: { | ||
| readonly summary?: "auto" | "concise" | "detailed" | undefined; | ||
| readonly effort?: import("../protocols/utils/open-responses-options.js").ReasoningEffort | undefined; | ||
| } | undefined; | ||
| readonly tools?: readonly ({ | ||
| readonly type: "function"; | ||
| readonly description: string; | ||
| readonly name: string; | ||
| readonly parameters: { | ||
| readonly [x: string]: unknown; | ||
| }; | ||
| readonly strict?: boolean | undefined; | ||
| } | { | ||
| readonly type: "image_generation"; | ||
| readonly size?: string | undefined; | ||
| readonly action?: "generate" | "auto" | "edit" | undefined; | ||
| readonly output_format?: "png" | "jpeg" | "webp" | undefined; | ||
| readonly quality?: "auto" | "low" | "medium" | "high" | undefined; | ||
| readonly background?: "auto" | "opaque" | "transparent" | undefined; | ||
| readonly output_compression?: number | undefined; | ||
| readonly input_fidelity?: "low" | "high" | undefined; | ||
| readonly partial_images?: number | undefined; | ||
| })[] | undefined; | ||
| readonly text?: { | ||
| readonly verbosity?: import("../protocols/utils/open-responses-options.js").TextVerbosity | undefined; | ||
| } | undefined; | ||
| readonly temperature?: number | undefined; | ||
| readonly tool_choice?: "required" | "auto" | "none" | { | ||
| readonly type: "function"; | ||
| readonly name: string; | ||
| } | { | ||
| readonly type: "allowed_tools"; | ||
| readonly mode: "required" | "auto" | "none"; | ||
| readonly tools: readonly { | ||
| readonly type: "function"; | ||
| readonly name: string; | ||
| }[]; | ||
| } | { | ||
| readonly type: "image_generation"; | ||
| } | undefined; | ||
| readonly top_p?: number | undefined; | ||
| readonly store?: boolean | undefined; | ||
| readonly include?: readonly import("../protocols/utils/open-responses-options.js").ResponseIncludable[] | undefined; | ||
| readonly truncation?: "auto" | "disabled" | undefined; | ||
| readonly stream_options?: { | ||
| readonly include_obfuscation?: boolean | undefined; | ||
| } | undefined; | ||
| readonly prompt_cache_key?: string | undefined; | ||
| readonly frequency_penalty?: number | undefined; | ||
| readonly presence_penalty?: number | undefined; | ||
| readonly safety_identifier?: string | undefined; | ||
| readonly top_logprobs?: number | undefined; | ||
| readonly service_tier?: "default" | "auto" | "flex" | "priority" | undefined; | ||
| readonly max_output_tokens?: number | undefined; | ||
| readonly max_tool_calls?: number | undefined; | ||
| readonly parallel_tool_calls?: boolean | undefined; | ||
| }, import("../protocols/open-responses-channel.js").Prepared>)[]; | ||
| }, import("../route/transport/http.js").HttpPrepared<string>> | Route<unknown, import("../protocols/open-responses-channel.js").Prepared>)[]; | ||
| export declare const configure: (input?: LanguageModelOptions) => { | ||
@@ -251,0 +117,0 @@ id: string & import("effect/Brand").Brand<"AI.ProviderID">; |
@@ -8,3 +8,4 @@ import { AuthOptions } from "../route/auth-options.js"; | ||
| import * as OpenAIChat from "../protocols/openai-chat.js"; | ||
| import * as OpenAIResponses from "../protocols/openai-responses.js"; | ||
| import { OpenResponsesChannel } from "../protocols/open-responses-channel.js"; | ||
| import { XAIResponses } from "../protocols/xai-responses.js"; | ||
| import { XAIImages } from "../protocols/xai-images.js"; | ||
@@ -17,5 +18,5 @@ export const id = ProviderID.make("xai"); | ||
| providerMetadataKey: "xai", | ||
| protocol: OpenAIResponses.protocol, | ||
| protocol: XAIResponses.protocol, | ||
| endpoint: Endpoint.path("/responses", { baseURL: OpenAICompatibleProfiles.profiles.xai.baseURL }), | ||
| transport: OpenAIResponses.channelTransport({ | ||
| transport: OpenResponsesChannel.transport({ | ||
| id: "openai-responses", | ||
@@ -22,0 +23,0 @@ name: "xAI Responses", |
+3
-3
| { | ||
| "$schema": "https://json.schemastore.org/package.json", | ||
| "version": "0.0.0-dev-17929", | ||
| "version": "0.0.0-dev-17938", | ||
| "name": "@opencode-ai/ai", | ||
@@ -33,3 +33,3 @@ "type": "module", | ||
| "@effect/platform-node": "4.0.0-rc.110", | ||
| "@opencode-ai/http-recorder": "0.0.0-dev-17929", | ||
| "@opencode-ai/http-recorder": "0.0.0-dev-17938", | ||
| "@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-dev-17929", | ||
| "@opencode-ai/schema": "0.0.0-dev-17938", | ||
| "aws4fetch": "1.0.20", | ||
@@ -46,0 +46,0 @@ "effect": "4.0.0-rc.110", |
| import type { WebSocketChannelDriver } from "../route/transport/index.js"; | ||
| export interface DriverInput { | ||
| readonly id: string; | ||
| readonly name: string; | ||
| readonly request: Readonly<Record<string, unknown>>; | ||
| readonly message: string; | ||
| readonly base: WebSocketChannelDriver; | ||
| } | ||
| export declare const driver: (input: DriverInput) => WebSocketChannelDriver; | ||
| export declare const OpenAIResponsesChannel: { | ||
| readonly driver: (input: DriverInput) => WebSocketChannelDriver; | ||
| }; |
| import { AIError, TransportReason } from "../schema/index.js"; | ||
| import { Effect, Option, Schema } from "effect"; | ||
| import * as ProviderShared from "./shared.js"; | ||
| import { OpenResponses } from "./open-responses.js"; | ||
| const PROTOCOL = "openai-responses.websocket.v1"; | ||
| const VERSION = 1; | ||
| const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event); | ||
| const checkpointValue = (checkpoint) => { | ||
| if (checkpoint?.protocol !== PROTOCOL || !ProviderShared.isRecord(checkpoint.value)) | ||
| return undefined; | ||
| if (checkpoint.value.version !== VERSION) | ||
| return undefined; | ||
| if (typeof checkpoint.value.responseID !== "string" || checkpoint.value.responseID.trim().length === 0) | ||
| return undefined; | ||
| if (!ProviderShared.isRecord(checkpoint.value.request) || !Array.isArray(checkpoint.value.output)) | ||
| return undefined; | ||
| return { | ||
| version: VERSION, | ||
| responseID: checkpoint.value.responseID, | ||
| request: checkpoint.value.request, | ||
| output: checkpoint.value.output, | ||
| }; | ||
| }; | ||
| const canonical = (value) => { | ||
| if (value === undefined) | ||
| return "undefined"; | ||
| if (Array.isArray(value)) | ||
| return `[${value.map(canonical).join(",")}]`; | ||
| if (!ProviderShared.isRecord(value)) | ||
| return ProviderShared.encodeJson(value); | ||
| return `{${Object.keys(value) | ||
| .sort() | ||
| .map((key) => `${ProviderShared.encodeJson(key)}:${canonical(value[key])}`) | ||
| .join(",")}}`; | ||
| }; | ||
| const json = (value) => { | ||
| if (typeof value !== "string") | ||
| return value; | ||
| return Option.getOrElse(Schema.decodeUnknownOption(ProviderShared.Json)(value), () => value); | ||
| }; | ||
| const comparable = (value) => { | ||
| if (!ProviderShared.isRecord(value)) | ||
| return value; | ||
| if (value.type === "message" && value.role === "assistant") | ||
| return { | ||
| role: "assistant", | ||
| content: value.content, | ||
| ...(value.phase === undefined ? {} : { phase: value.phase }), | ||
| }; | ||
| if (value.type === "function_call") | ||
| return { | ||
| type: value.type, | ||
| call_id: value.call_id, | ||
| name: value.name, | ||
| arguments: json(value.arguments), | ||
| }; | ||
| if (value.type === "reasoning") | ||
| return { | ||
| type: value.type, | ||
| summary: value.summary, | ||
| encrypted_content: value.encrypted_content, | ||
| }; | ||
| return value; | ||
| }; | ||
| const invariant = (request) => { | ||
| const { type: _type, input: _input, previous_response_id: _previousResponseID, ...rest } = request; | ||
| return rest; | ||
| }; | ||
| const incremental = (request, checkpoint) => { | ||
| const input = request.input; | ||
| const previousInput = checkpoint.request.input; | ||
| if (!Array.isArray(input) || !Array.isArray(previousInput)) | ||
| return undefined; | ||
| if (canonical(invariant(request)) !== canonical(invariant(checkpoint.request))) | ||
| return undefined; | ||
| const baseline = [...previousInput, ...checkpoint.output]; | ||
| if (input.length <= baseline.length) | ||
| return undefined; | ||
| if (!baseline.every((item, index) => canonical(comparable(item)) === canonical(comparable(input[index])))) | ||
| return undefined; | ||
| return input.slice(baseline.length); | ||
| }; | ||
| const code = (event) => event.code || event.error?.code || event.response?.error?.code || undefined; | ||
| const rejected = (input, observation, recovery) => ({ | ||
| type: "rejected", | ||
| recovery, | ||
| error: new AIError({ | ||
| module: input.id, | ||
| method: "stream", | ||
| reason: new TransportReason({ | ||
| message: observation.error.message, | ||
| transport: "websocket", | ||
| operation: "read", | ||
| phase: "receive", | ||
| delivery: "rejected", | ||
| recovery, | ||
| }), | ||
| }), | ||
| }); | ||
| export const driver = (input) => { | ||
| const { previous_response_id: _previousResponseID, ...request } = input.request; | ||
| let output = []; | ||
| return { | ||
| create: (checkpoint) => Effect.sync(() => { | ||
| output = []; | ||
| const previous = checkpointValue(checkpoint); | ||
| const delta = previous ? incremental(request, previous) : undefined; | ||
| if (!previous || !delta) | ||
| return { message: ProviderShared.encodeJson(request), mode: "full" }; | ||
| return { | ||
| message: ProviderShared.encodeJson({ ...request, input: delta, previous_response_id: previous.responseID }), | ||
| mode: "incremental", | ||
| }; | ||
| }), | ||
| observe: (create, frame) => Effect.gen(function* () { | ||
| const event = yield* decodeEvent(frame).pipe(Effect.mapError(() => ProviderShared.eventError(input.id, `Invalid ${input.name} WebSocket event`, frame))); | ||
| const observation = yield* input.base.observe(create, frame); | ||
| if (event.type === "response.output_item.done" && event.item) | ||
| output.push(event.item); | ||
| if (observation.type === "provider-failure") { | ||
| const rejection = code(event); | ||
| if (rejection === "previous_response_not_found") | ||
| return rejected(input, observation, "retry-full"); | ||
| if (rejection === "websocket_connection_limit_reached") | ||
| return rejected(input, observation, "rotate-and-retry-full"); | ||
| } | ||
| if (observation.type !== "completed") | ||
| return observation; | ||
| const responseID = event.response?.id; | ||
| if (!responseID || responseID.trim().length === 0) | ||
| return observation; | ||
| return { | ||
| ...observation, | ||
| checkpoint: { | ||
| protocol: PROTOCOL, | ||
| value: { version: VERSION, responseID, request, output: output.slice() }, | ||
| }, | ||
| }; | ||
| }), | ||
| }; | ||
| }; | ||
| export const OpenAIResponsesChannel = { driver }; |
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.
1192410
0.45%198
2.06%27453
0.36%+ Added
- Removed