UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

209 lines 8.43 kB
export async function* wrapOpenAIStream(stream, options = {}) { const { includeUsage = true, includeToolCalls = true, emitFunctionCallsAsTokens = false, choiceIndex = 0, } = options; let usage; const choiceState = new Map(); const getChoiceState = (index) => { if (!choiceState.has(index)) { choiceState.set(index, { functionCallAccumulator: null, toolCallsAccumulator: new Map(), finished: false, }); } return choiceState.get(index); }; try { for await (const chunk of stream) { const choices = chunk.choices; if (!choices || choices.length === 0) { continue; } if (chunk.usage) { usage = chunk.usage; } for (const choice of choices) { if (!choice) continue; const idx = choice.index; if (choiceIndex !== "all" && idx !== choiceIndex) { continue; } const state = getChoiceState(idx); const delta = choice.delta; if (!delta) continue; const choicePrefix = choiceIndex === "all" ? `[choice:${idx}]` : ""; if (delta.content) { yield { type: "token", value: choicePrefix ? `${choicePrefix}${delta.content}` : delta.content, timestamp: Date.now(), }; } if (delta.function_call) { if (delta.function_call.name) { state.functionCallAccumulator = { name: delta.function_call.name, arguments: delta.function_call.arguments || "", }; } else if (delta.function_call.arguments && state.functionCallAccumulator) { state.functionCallAccumulator.arguments += delta.function_call.arguments; } if (emitFunctionCallsAsTokens && delta.function_call.arguments) { yield { type: "token", value: delta.function_call.arguments, timestamp: Date.now(), }; } } if (delta.tool_calls) { for (const toolCall of delta.tool_calls) { const existing = state.toolCallsAccumulator.get(toolCall.index); if (toolCall.id || toolCall.function?.name) { state.toolCallsAccumulator.set(toolCall.index, { id: toolCall.id || existing?.id || "", name: toolCall.function?.name || existing?.name || "", arguments: toolCall.function?.arguments || "", }); } else if (toolCall.function?.arguments && existing) { existing.arguments += toolCall.function.arguments; } if (emitFunctionCallsAsTokens && toolCall.function?.arguments) { yield { type: "token", value: toolCall.function.arguments, timestamp: Date.now(), }; } } } if (choice.finish_reason && !state.finished) { state.finished = true; if (state.functionCallAccumulator && includeToolCalls) { yield { type: "message", value: JSON.stringify({ type: "function_call", function_call: state.functionCallAccumulator, ...(choiceIndex === "all" ? { choiceIndex: idx } : {}), }), role: "assistant", timestamp: Date.now(), }; } if (state.toolCallsAccumulator.size > 0 && includeToolCalls) { const toolCalls = Array.from(state.toolCallsAccumulator.values()); yield { type: "message", value: JSON.stringify({ type: "tool_calls", tool_calls: toolCalls, ...(choiceIndex === "all" ? { choiceIndex: idx } : {}), }), role: "assistant", timestamp: Date.now(), }; } } } } yield { type: "complete", timestamp: Date.now(), ...(includeUsage && usage ? { usage } : {}), }; } catch (error) { yield { type: "error", error: error instanceof Error ? error : new Error(String(error)), timestamp: Date.now(), }; } } export function openaiStream(client, params, options) { return async () => { const stream = await client.chat.completions.create({ ...params, stream: true, }); return wrapOpenAIStream(stream, options); }; } export function openaiText(client, model, prompt, options) { const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt; const { includeUsage, includeToolCalls, emitFunctionCallsAsTokens, ...chatParams } = options || {}; return openaiStream(client, { model, messages, ...chatParams }, { includeUsage, includeToolCalls, emitFunctionCallsAsTokens }); } export function openaiJSON(client, model, prompt, options) { const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt; const { includeUsage, includeToolCalls, emitFunctionCallsAsTokens, ...chatParams } = options || {}; return openaiStream(client, { model, messages, response_format: { type: "json_object" }, ...chatParams, }, { includeUsage, includeToolCalls, emitFunctionCallsAsTokens }); } export function openaiWithTools(client, model, messages, tools, options) { const { includeUsage, includeToolCalls, emitFunctionCallsAsTokens, ...chatParams } = options || {}; return openaiStream(client, { model, messages, tools, ...chatParams }, { includeUsage, includeToolCalls: includeToolCalls ?? true, emitFunctionCallsAsTokens, }); } export function isOpenAIChunk(obj) { if (!obj || typeof obj !== "object" || !("choices" in obj)) { return false; } const chunk = obj; if (!Array.isArray(chunk.choices) || chunk.choices.length === 0) { return false; } const firstChoice = chunk.choices[0]; return firstChoice !== undefined && "delta" in firstChoice; } export async function extractOpenAIText(stream) { let text = ""; for await (const chunk of stream) { const content = chunk.choices?.[0]?.delta?.content; if (content) { text += content; } } return text; } export function isOpenAIStream(input) { if (!input || typeof input !== "object") return false; if (!(Symbol.asyncIterator in input)) return false; const stream = input; if (typeof stream.toReadableStream === "function" && "controller" in stream) { return true; } if ("response" in stream && typeof stream.toReadableStream === "function") { return true; } return false; } export const openaiAdapter = { name: "openai", detect: isOpenAIStream, wrap: wrapOpenAIStream, }; import { registerAdapter } from "./registry"; try { registerAdapter(openaiAdapter, { silent: true }); } catch { } //# sourceMappingURL=openai.js.map