refactor(llm): share provider schema helpers
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
type ToolDefinition,
|
||||
type ToolResultPart,
|
||||
} from "../schema"
|
||||
import { ProviderShared } from "./shared"
|
||||
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
|
||||
|
||||
const ADAPTER = "anthropic-messages"
|
||||
|
||||
@@ -106,7 +106,7 @@ type AnthropicMessage = Schema.Schema.Type<typeof AnthropicMessage>
|
||||
const AnthropicTool = Schema.Struct({
|
||||
name: Schema.String,
|
||||
description: Schema.String,
|
||||
input_schema: Schema.Record(Schema.String, Schema.Unknown),
|
||||
input_schema: JsonObject,
|
||||
cache_control: Schema.optional(AnthropicCacheControl),
|
||||
})
|
||||
type AnthropicTool = Schema.Schema.Type<typeof AnthropicTool>
|
||||
@@ -123,15 +123,15 @@ const AnthropicThinking = Schema.Struct({
|
||||
|
||||
const AnthropicTargetFields = {
|
||||
model: Schema.String,
|
||||
system: Schema.optional(Schema.Array(AnthropicTextBlock)),
|
||||
system: optionalArray(AnthropicTextBlock),
|
||||
messages: Schema.Array(AnthropicMessage),
|
||||
tools: Schema.optional(Schema.Array(AnthropicTool)),
|
||||
tools: optionalArray(AnthropicTool),
|
||||
tool_choice: Schema.optional(AnthropicToolChoice),
|
||||
stream: Schema.Literal(true),
|
||||
max_tokens: Schema.Number,
|
||||
temperature: Schema.optional(Schema.Number),
|
||||
top_p: Schema.optional(Schema.Number),
|
||||
stop_sequences: Schema.optional(Schema.Array(Schema.String)),
|
||||
stop_sequences: optionalArray(Schema.String),
|
||||
thinking: Schema.optional(AnthropicThinking),
|
||||
}
|
||||
const AnthropicMessagesTarget = Schema.Struct(AnthropicTargetFields)
|
||||
@@ -140,8 +140,8 @@ export type AnthropicMessagesTarget = Schema.Schema.Type<typeof AnthropicMessage
|
||||
const AnthropicUsage = Schema.Struct({
|
||||
input_tokens: Schema.optional(Schema.Number),
|
||||
output_tokens: Schema.optional(Schema.Number),
|
||||
cache_creation_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
cache_read_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),
|
||||
cache_creation_input_tokens: optionalNull(Schema.Number),
|
||||
cache_read_input_tokens: optionalNull(Schema.Number),
|
||||
})
|
||||
type AnthropicUsage = Schema.Schema.Type<typeof AnthropicUsage>
|
||||
|
||||
@@ -165,8 +165,8 @@ const AnthropicStreamDelta = Schema.Struct({
|
||||
thinking: Schema.optional(Schema.String),
|
||||
partial_json: Schema.optional(Schema.String),
|
||||
signature: Schema.optional(Schema.String),
|
||||
stop_reason: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
stop_sequence: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
stop_reason: optionalNull(Schema.String),
|
||||
stop_sequence: optionalNull(Schema.String),
|
||||
})
|
||||
|
||||
const AnthropicChunk = Schema.Struct({
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
type ToolResultPart,
|
||||
} from "../schema"
|
||||
import { BedrockEventStream } from "./bedrock-event-stream"
|
||||
import { ProviderShared } from "./shared"
|
||||
import { JsonObject, optionalArray, ProviderShared } from "./shared"
|
||||
|
||||
const ADAPTER = "bedrock-converse"
|
||||
|
||||
@@ -163,7 +163,7 @@ const BedrockTool = Schema.Struct({
|
||||
name: Schema.String,
|
||||
description: Schema.String,
|
||||
inputSchema: Schema.Struct({
|
||||
json: Schema.Record(Schema.String, Schema.Unknown),
|
||||
json: JsonObject,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -178,13 +178,13 @@ const BedrockToolChoice = Schema.Union([
|
||||
const BedrockTargetFields = {
|
||||
modelId: Schema.String,
|
||||
messages: Schema.Array(BedrockMessage),
|
||||
system: Schema.optional(Schema.Array(BedrockSystemBlock)),
|
||||
system: optionalArray(BedrockSystemBlock),
|
||||
inferenceConfig: Schema.optional(
|
||||
Schema.Struct({
|
||||
maxTokens: Schema.optional(Schema.Number),
|
||||
temperature: Schema.optional(Schema.Number),
|
||||
topP: Schema.optional(Schema.Number),
|
||||
stopSequences: Schema.optional(Schema.Array(Schema.String)),
|
||||
stopSequences: optionalArray(Schema.String),
|
||||
}),
|
||||
),
|
||||
toolConfig: Schema.optional(
|
||||
@@ -193,7 +193,7 @@ const BedrockTargetFields = {
|
||||
toolChoice: Schema.optional(BedrockToolChoice),
|
||||
}),
|
||||
),
|
||||
additionalModelRequestFields: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
||||
additionalModelRequestFields: Schema.optional(JsonObject),
|
||||
}
|
||||
const BedrockConverseTarget = Schema.Struct(BedrockTargetFields)
|
||||
export type BedrockConverseTarget = Schema.Schema.Type<typeof BedrockConverseTarget>
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
type ToolCallPart,
|
||||
type ToolDefinition,
|
||||
} from "../schema"
|
||||
import { ProviderShared } from "./shared"
|
||||
import { JsonObject, optionalArray, ProviderShared } from "./shared"
|
||||
|
||||
const ADAPTER = "gemini"
|
||||
|
||||
@@ -73,7 +73,7 @@ const GeminiSystemInstruction = Schema.Struct({
|
||||
const GeminiFunctionDeclaration = Schema.Struct({
|
||||
name: Schema.String,
|
||||
description: Schema.String,
|
||||
parameters: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
||||
parameters: Schema.optional(JsonObject),
|
||||
})
|
||||
|
||||
const GeminiTool = Schema.Struct({
|
||||
@@ -83,7 +83,7 @@ const GeminiTool = Schema.Struct({
|
||||
const GeminiToolConfig = Schema.Struct({
|
||||
functionCallingConfig: Schema.Struct({
|
||||
mode: Schema.Literals(["AUTO", "NONE", "ANY"]),
|
||||
allowedFunctionNames: Schema.optional(Schema.Array(Schema.String)),
|
||||
allowedFunctionNames: optionalArray(Schema.String),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -96,14 +96,14 @@ const GeminiGenerationConfig = Schema.Struct({
|
||||
maxOutputTokens: Schema.optional(Schema.Number),
|
||||
temperature: Schema.optional(Schema.Number),
|
||||
topP: Schema.optional(Schema.Number),
|
||||
stopSequences: Schema.optional(Schema.Array(Schema.String)),
|
||||
stopSequences: optionalArray(Schema.String),
|
||||
thinkingConfig: Schema.optional(GeminiThinkingConfig),
|
||||
})
|
||||
|
||||
const GeminiTargetFields = {
|
||||
contents: Schema.Array(GeminiContent),
|
||||
systemInstruction: Schema.optional(GeminiSystemInstruction),
|
||||
tools: Schema.optional(Schema.Array(GeminiTool)),
|
||||
tools: optionalArray(GeminiTool),
|
||||
toolConfig: Schema.optional(GeminiToolConfig),
|
||||
generationConfig: Schema.optional(GeminiGenerationConfig),
|
||||
}
|
||||
@@ -125,7 +125,7 @@ const GeminiCandidate = Schema.Struct({
|
||||
})
|
||||
|
||||
const GeminiChunk = Schema.Struct({
|
||||
candidates: Schema.optional(Schema.Array(GeminiCandidate)),
|
||||
candidates: optionalArray(GeminiCandidate),
|
||||
usageMetadata: Schema.optional(GeminiUsage),
|
||||
})
|
||||
type GeminiChunk = Schema.Schema.Type<typeof GeminiChunk>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Array as Arr, Effect, Schema } from "effect"
|
||||
import { Adapter } from "../adapter"
|
||||
import { Auth } from "../auth"
|
||||
import { Endpoint } from "../endpoint"
|
||||
@@ -14,19 +14,25 @@ import {
|
||||
type ToolCallPart,
|
||||
type ToolDefinition,
|
||||
} from "../schema"
|
||||
import { ProviderShared } from "./shared"
|
||||
import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
|
||||
|
||||
const ADAPTER = "openai-chat"
|
||||
|
||||
// =============================================================================
|
||||
// Public Model Input
|
||||
// =============================================================================
|
||||
export type OpenAIChatModelInput = Omit<ModelInput, "provider" | "protocol" | "headers"> & {
|
||||
readonly apiKey?: string
|
||||
readonly headers?: Record<string, string>
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Request Target Schema
|
||||
// =============================================================================
|
||||
const OpenAIChatFunction = Schema.Struct({
|
||||
name: Schema.String,
|
||||
description: Schema.String,
|
||||
parameters: Schema.Record(Schema.String, Schema.Unknown),
|
||||
parameters: JsonObject,
|
||||
})
|
||||
|
||||
const OpenAIChatTool = Schema.Struct({
|
||||
@@ -51,85 +57,83 @@ const OpenAIChatMessage = Schema.Union([
|
||||
Schema.Struct({
|
||||
role: Schema.Literal("assistant"),
|
||||
content: Schema.NullOr(Schema.String),
|
||||
tool_calls: Schema.optional(Schema.Array(OpenAIChatAssistantToolCall)),
|
||||
tool_calls: optionalArray(OpenAIChatAssistantToolCall),
|
||||
reasoning_content: Schema.optional(Schema.String),
|
||||
}),
|
||||
Schema.Struct({ role: Schema.Literal("tool"), tool_call_id: Schema.String, content: Schema.String }),
|
||||
])
|
||||
type OpenAIChatMessage = Schema.Schema.Type<typeof OpenAIChatMessage>
|
||||
|
||||
const OpenAIChatToolChoiceFunction = Schema.Struct({ name: Schema.String })
|
||||
|
||||
const OpenAIChatToolChoice = Schema.Union([
|
||||
Schema.Literals(["auto", "none", "required"]),
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("function"),
|
||||
function: OpenAIChatToolChoiceFunction,
|
||||
function: Schema.Struct({ name: Schema.String }),
|
||||
}),
|
||||
])
|
||||
|
||||
const OpenAIChatTargetFields = {
|
||||
model: Schema.String,
|
||||
messages: Schema.Array(OpenAIChatMessage),
|
||||
tools: Schema.optional(Schema.Array(OpenAIChatTool)),
|
||||
tools: optionalArray(OpenAIChatTool),
|
||||
tool_choice: Schema.optional(OpenAIChatToolChoice),
|
||||
stream: Schema.Literal(true),
|
||||
stream_options: Schema.optional(Schema.Struct({ include_usage: Schema.Boolean })),
|
||||
max_tokens: Schema.optional(Schema.Number),
|
||||
temperature: Schema.optional(Schema.Number),
|
||||
top_p: Schema.optional(Schema.Number),
|
||||
stop: Schema.optional(Schema.Array(Schema.String)),
|
||||
stop: optionalArray(Schema.String),
|
||||
}
|
||||
const OpenAIChatTarget = Schema.Struct(OpenAIChatTargetFields)
|
||||
export type OpenAIChatTarget = Schema.Schema.Type<typeof OpenAIChatTarget>
|
||||
|
||||
// =============================================================================
|
||||
// Streaming Chunk Schema
|
||||
// =============================================================================
|
||||
const OpenAIChatUsage = Schema.Struct({
|
||||
prompt_tokens: Schema.optional(Schema.Number),
|
||||
completion_tokens: Schema.optional(Schema.Number),
|
||||
total_tokens: Schema.optional(Schema.Number),
|
||||
prompt_tokens_details: Schema.optional(
|
||||
Schema.NullOr(
|
||||
Schema.Struct({
|
||||
cached_tokens: Schema.optional(Schema.Number),
|
||||
}),
|
||||
),
|
||||
prompt_tokens_details: optionalNull(
|
||||
Schema.Struct({
|
||||
cached_tokens: Schema.optional(Schema.Number),
|
||||
}),
|
||||
),
|
||||
completion_tokens_details: Schema.optional(
|
||||
Schema.NullOr(
|
||||
Schema.Struct({
|
||||
reasoning_tokens: Schema.optional(Schema.Number),
|
||||
}),
|
||||
),
|
||||
completion_tokens_details: optionalNull(
|
||||
Schema.Struct({
|
||||
reasoning_tokens: Schema.optional(Schema.Number),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
const OpenAIChatToolCallDeltaFunction = Schema.Struct({
|
||||
name: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
arguments: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
name: optionalNull(Schema.String),
|
||||
arguments: optionalNull(Schema.String),
|
||||
})
|
||||
|
||||
const OpenAIChatToolCallDelta = Schema.Struct({
|
||||
index: Schema.Number,
|
||||
id: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
function: Schema.optional(Schema.NullOr(OpenAIChatToolCallDeltaFunction)),
|
||||
id: optionalNull(Schema.String),
|
||||
function: optionalNull(OpenAIChatToolCallDeltaFunction),
|
||||
})
|
||||
type OpenAIChatToolCallDelta = Schema.Schema.Type<typeof OpenAIChatToolCallDelta>
|
||||
|
||||
const OpenAIChatDelta = Schema.Struct({
|
||||
content: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
tool_calls: Schema.optional(Schema.NullOr(Schema.Array(OpenAIChatToolCallDelta))),
|
||||
content: optionalNull(Schema.String),
|
||||
tool_calls: optionalNull(Schema.Array(OpenAIChatToolCallDelta)),
|
||||
})
|
||||
|
||||
const OpenAIChatChoice = Schema.Struct({
|
||||
delta: Schema.optional(Schema.NullOr(OpenAIChatDelta)),
|
||||
finish_reason: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
delta: optionalNull(OpenAIChatDelta),
|
||||
finish_reason: optionalNull(Schema.String),
|
||||
})
|
||||
|
||||
const OpenAIChatChunk = Schema.Struct({
|
||||
choices: Schema.Array(OpenAIChatChoice),
|
||||
usage: Schema.optional(Schema.NullOr(OpenAIChatUsage)),
|
||||
usage: optionalNull(OpenAIChatUsage),
|
||||
})
|
||||
type OpenAIChatChunk = Schema.Schema.Type<typeof OpenAIChatChunk>
|
||||
type OpenAIChatRequestMessage = LLMRequest["messages"][number]
|
||||
|
||||
interface ParsedToolCall {
|
||||
readonly id: string
|
||||
@@ -146,6 +150,9 @@ interface ParserState {
|
||||
|
||||
const invalid = ProviderShared.invalidRequest
|
||||
|
||||
// =============================================================================
|
||||
// Request Lowering
|
||||
// =============================================================================
|
||||
const lowerTool = (tool: ToolDefinition): OpenAIChatTool => ({
|
||||
type: "function",
|
||||
function: {
|
||||
@@ -172,58 +179,61 @@ const lowerToolCall = (part: ToolCallPart): OpenAIChatAssistantToolCall => ({
|
||||
},
|
||||
})
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
const openAICompatibleReasoningContent = (native: unknown) =>
|
||||
isRecord(native) && typeof native.reasoning_content === "string" ? native.reasoning_content : undefined
|
||||
|
||||
const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (message: OpenAIChatRequestMessage) {
|
||||
const content: TextPart[] = []
|
||||
for (const part of message.content) {
|
||||
if (part.type !== "text") return yield* invalid(`OpenAI Chat user messages only support text content for now`)
|
||||
content.push(part)
|
||||
}
|
||||
return { role: "user" as const, content: ProviderShared.joinText(content) }
|
||||
})
|
||||
|
||||
const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (
|
||||
message: OpenAIChatRequestMessage,
|
||||
) {
|
||||
const content: TextPart[] = []
|
||||
const toolCalls: OpenAIChatAssistantToolCall[] = []
|
||||
for (const part of message.content) {
|
||||
if (part.type === "text") {
|
||||
content.push(part)
|
||||
continue
|
||||
}
|
||||
if (part.type === "tool-call") {
|
||||
toolCalls.push(lowerToolCall(part))
|
||||
continue
|
||||
}
|
||||
return yield* invalid(`OpenAI Chat assistant messages only support text and tool-call content for now`)
|
||||
}
|
||||
return {
|
||||
role: "assistant" as const,
|
||||
content: content.length === 0 ? null : ProviderShared.joinText(content),
|
||||
tool_calls: toolCalls.length === 0 ? undefined : toolCalls,
|
||||
reasoning_content: openAICompatibleReasoningContent(message.native?.openaiCompatible),
|
||||
}
|
||||
})
|
||||
|
||||
const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (message: OpenAIChatRequestMessage) {
|
||||
const messages: OpenAIChatMessage[] = []
|
||||
for (const part of message.content) {
|
||||
if (part.type !== "tool-result") return yield* invalid(`OpenAI Chat tool messages only support tool-result content`)
|
||||
messages.push({ role: "tool", tool_call_id: part.id, content: ProviderShared.toolResultText(part) })
|
||||
}
|
||||
return messages
|
||||
})
|
||||
|
||||
const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message: OpenAIChatRequestMessage) {
|
||||
if (message.role === "user") return [yield* lowerUserMessage(message)]
|
||||
if (message.role === "assistant") return [yield* lowerAssistantMessage(message)]
|
||||
return yield* lowerToolMessages(message)
|
||||
})
|
||||
|
||||
const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request: LLMRequest) {
|
||||
const system: OpenAIChatMessage[] =
|
||||
request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }]
|
||||
const messages: OpenAIChatMessage[] = [...system]
|
||||
|
||||
for (const message of request.messages) {
|
||||
if (message.role === "user") {
|
||||
const content: TextPart[] = []
|
||||
for (const part of message.content) {
|
||||
if (part.type !== "text") return yield* invalid(`OpenAI Chat user messages only support text content for now`)
|
||||
content.push(part)
|
||||
}
|
||||
messages.push({ role: "user", content: ProviderShared.joinText(content) })
|
||||
continue
|
||||
}
|
||||
|
||||
if (message.role === "assistant") {
|
||||
const content: TextPart[] = []
|
||||
const toolCalls: OpenAIChatAssistantToolCall[] = []
|
||||
for (const part of message.content) {
|
||||
if (part.type === "text") {
|
||||
content.push(part)
|
||||
continue
|
||||
}
|
||||
if (part.type === "tool-call") {
|
||||
toolCalls.push(lowerToolCall(part))
|
||||
continue
|
||||
}
|
||||
return yield* invalid(`OpenAI Chat assistant messages only support text and tool-call content for now`)
|
||||
}
|
||||
messages.push({
|
||||
role: "assistant",
|
||||
content: content.length === 0 ? null : ProviderShared.joinText(content),
|
||||
tool_calls: toolCalls.length === 0 ? undefined : toolCalls,
|
||||
reasoning_content: isRecord(message.native?.openaiCompatible) && typeof message.native.openaiCompatible.reasoning_content === "string"
|
||||
? message.native.openaiCompatible.reasoning_content
|
||||
: undefined,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
for (const part of message.content) {
|
||||
if (part.type !== "tool-result")
|
||||
return yield* invalid(`OpenAI Chat tool messages only support tool-result content`)
|
||||
messages.push({ role: "tool", tool_call_id: part.id, content: ProviderShared.toolResultText(part) })
|
||||
}
|
||||
}
|
||||
|
||||
return messages
|
||||
return [...system, ...Arr.flatten(yield* Effect.forEach(request.messages, lowerMessage))]
|
||||
})
|
||||
|
||||
const prepare = Effect.fn("OpenAIChat.prepare")(function* (request: LLMRequest) {
|
||||
@@ -240,6 +250,9 @@ const prepare = Effect.fn("OpenAIChat.prepare")(function* (request: LLMRequest)
|
||||
}
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Stream Parsing
|
||||
// =============================================================================
|
||||
const mapFinishReason = (reason: string | null | undefined): FinishReason => {
|
||||
if (reason === "stop") return "stop"
|
||||
if (reason === "length") return "length"
|
||||
@@ -322,6 +335,9 @@ const finishEvents = (state: ParserState): ReadonlyArray<LLMEvent> => {
|
||||
]
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Protocol And OpenAI Adapter
|
||||
// =============================================================================
|
||||
/**
|
||||
* The OpenAI Chat protocol — request lowering, target schema, and the
|
||||
* streaming-chunk state machine. Reused by every adapter
|
||||
@@ -351,6 +367,9 @@ export const adapter = Adapter.make({
|
||||
framing: Framing.sse,
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Model Helper And Patches
|
||||
// =============================================================================
|
||||
export const model = (input: OpenAIChatModelInput) =>
|
||||
Adapter.bindModel(
|
||||
llmModel({
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
type ToolCallPart,
|
||||
type ToolDefinition,
|
||||
} from "../schema"
|
||||
import { ProviderShared } from "./shared"
|
||||
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
|
||||
|
||||
const ADAPTER = "openai-responses"
|
||||
|
||||
@@ -55,7 +55,7 @@ const OpenAIResponsesTool = Schema.Struct({
|
||||
type: Schema.Literal("function"),
|
||||
name: Schema.String,
|
||||
description: Schema.String,
|
||||
parameters: Schema.Record(Schema.String, Schema.Unknown),
|
||||
parameters: JsonObject,
|
||||
strict: Schema.optional(Schema.Boolean),
|
||||
})
|
||||
type OpenAIResponsesTool = Schema.Schema.Type<typeof OpenAIResponsesTool>
|
||||
@@ -68,7 +68,7 @@ const OpenAIResponsesToolChoice = Schema.Union([
|
||||
const OpenAIResponsesTargetFields = {
|
||||
model: Schema.String,
|
||||
input: Schema.Array(OpenAIResponsesInputItem),
|
||||
tools: Schema.optional(Schema.Array(OpenAIResponsesTool)),
|
||||
tools: optionalArray(OpenAIResponsesTool),
|
||||
tool_choice: Schema.optional(OpenAIResponsesToolChoice),
|
||||
stream: Schema.Literal(true),
|
||||
max_output_tokens: Schema.optional(Schema.Number),
|
||||
@@ -80,9 +80,9 @@ export type OpenAIResponsesTarget = Schema.Schema.Type<typeof OpenAIResponsesTar
|
||||
|
||||
const OpenAIResponsesUsage = Schema.Struct({
|
||||
input_tokens: Schema.optional(Schema.Number),
|
||||
input_tokens_details: Schema.optional(Schema.NullOr(Schema.Struct({ cached_tokens: Schema.optional(Schema.Number) }))),
|
||||
input_tokens_details: optionalNull(Schema.Struct({ cached_tokens: Schema.optional(Schema.Number) })),
|
||||
output_tokens: Schema.optional(Schema.Number),
|
||||
output_tokens_details: Schema.optional(Schema.NullOr(Schema.Struct({ reasoning_tokens: Schema.optional(Schema.Number) }))),
|
||||
output_tokens_details: optionalNull(Schema.Struct({ reasoning_tokens: Schema.optional(Schema.Number) })),
|
||||
total_tokens: Schema.optional(Schema.Number),
|
||||
})
|
||||
type OpenAIResponsesUsage = Schema.Schema.Type<typeof OpenAIResponsesUsage>
|
||||
@@ -117,8 +117,8 @@ const OpenAIResponsesChunk = Schema.Struct({
|
||||
item: Schema.optional(OpenAIResponsesStreamItem),
|
||||
response: Schema.optional(
|
||||
Schema.Struct({
|
||||
incomplete_details: Schema.optional(Schema.NullOr(Schema.Struct({ reason: Schema.String }))),
|
||||
usage: Schema.optional(Schema.NullOr(OpenAIResponsesUsage)),
|
||||
incomplete_details: optionalNull(Schema.Struct({ reason: Schema.String })),
|
||||
usage: optionalNull(OpenAIResponsesUsage),
|
||||
}),
|
||||
),
|
||||
code: Schema.optional(Schema.String),
|
||||
|
||||
@@ -7,6 +7,9 @@ import { InvalidRequestError, ProviderChunkError, type MediaPart, type ToolResul
|
||||
export const Json = Schema.fromJsonString(Schema.Unknown)
|
||||
export const decodeJson = Schema.decodeUnknownSync(Json)
|
||||
export const encodeJson = Schema.encodeSync(Json)
|
||||
export const JsonObject = Schema.Record(Schema.String, Schema.Unknown)
|
||||
export const optionalArray = <const S extends Schema.Top>(schema: S) => Schema.optional(Schema.Array(schema))
|
||||
export const optionalNull = <const S extends Schema.Top>(schema: S) => Schema.optional(Schema.NullOr(schema))
|
||||
|
||||
/**
|
||||
* Plain-record narrowing. Excludes arrays so adapters checking nested JSON
|
||||
|
||||
Reference in New Issue
Block a user