@simulacra-ai/openai 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Simulacra OpenAI Provider
2
2
 
3
- The OpenAI provider allows Simulacra to use OpenAI models via the OpenAI SDK, including GPT, o1, and o3 series.
3
+ OpenAI chat-completions provider for Simulacra. Works against OpenAI directly (GPT, o-series) and against any OpenAI-compatible endpoint (DeepSeek, OpenRouter, self-hosted gateways like vLLM / llama.cpp / Ollama, Anthropic-via-compat, etc.).
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,22 +15,60 @@ import { Conversation } from "@simulacra-ai/core";
15
15
  import { OpenAIProvider } from "@simulacra-ai/openai";
16
16
  import OpenAI from "openai";
17
17
 
18
- // create a provider and conversation
19
- const provider = new OpenAIProvider(new OpenAI(), { model: MODEL_NAME });
18
+ const provider = new OpenAIProvider(new OpenAI(), { model: "gpt-4o" });
20
19
  using conversation = new Conversation(provider);
21
20
  ```
22
21
 
23
- ### OpenAIProviderConfig
22
+ For a non-OpenAI endpoint, point the SDK at it:
23
+
24
+ ```typescript
25
+ const sdk = new OpenAI({
26
+ baseURL: "https://api.deepseek.com",
27
+ apiKey: process.env.DEEPSEEK_API_KEY,
28
+ });
29
+ const provider = new OpenAIProvider(sdk, { model: "deepseek-v4-flash" });
30
+ ```
31
+
32
+ ## OpenAIProviderConfig
24
33
 
25
34
  ```typescript
26
35
  interface OpenAIProviderConfig {
27
36
  model: string;
28
37
  max_tokens?: number;
38
+ system_role?: "auto" | "system" | "developer";
39
+ strict_tools?: "auto" | "never";
40
+ upstream_reasoning?: "inline" | "field" | "drop";
29
41
  }
30
42
  ```
31
43
 
32
44
  Additional properties (`temperature`, `top_p`, etc.) spread into the API request.
33
45
 
46
+ ### `system_role`
47
+
48
+ Role used for the system prompt.
49
+
50
+ - `"auto"` (default): `gpt*` → `system`, o-series (`o1`, `o3`, `o4`, ...) → `developer`, anything else → `system`. The fallback to `system` is the broadly-compatible default — most non-OpenAI endpoints reject `developer`.
51
+ - `"system"` / `"developer"`: force regardless of model id.
52
+
53
+ Set explicitly when routing through a relay using `vendor/model` ids (`openai/o3`); the heuristic only matches bare ids.
54
+
55
+ ### `strict_tools`
56
+
57
+ Whether to emit OpenAI's `function.strict: true` flag on tool definitions.
58
+
59
+ - `"auto"` (default): emitted for `gpt*` and o-series. Other models get tool defs without `strict`.
60
+ - `"never"`: never emitted.
61
+
62
+ `strict` is an OpenAI-specific extension. Most other endpoints either ignore it or reject it.
63
+
64
+ ### `upstream_reasoning`
65
+
66
+ Treatment of prior `thinking` content blocks when serializing assistant messages back up the wire.
67
+
68
+ - `"inline"` (default): appended as text content. OpenAI tolerates it (treated as ordinary assistant text on subsequent calls).
69
+ - `"field"`: emitted as a `reasoning_content` field on the assistant message. Required by DeepSeek V4 thinking-mode, which rejects follow-up calls when prior reasoning is missing or inlined into content.
70
+ - `"drop"`: omitted entirely.
71
+
34
72
  ## License
35
73
 
36
74
  MIT
package/dist/index.cjs CHANGED
@@ -51,8 +51,9 @@ var OpenAIProvider = class _OpenAIProvider {
51
51
  * @returns A promise that resolves when the request completes.
52
52
  */
53
53
  async execute_request(request, receiver, cancellation) {
54
- const { model, max_tokens, system_role, strict_tools, ...api_extras } = this.#config;
54
+ const { model, max_tokens, system_role, strict_tools, upstream_reasoning, ...api_extras } = this.#config;
55
55
  const emit_strict = resolve_strict_tools(model, strict_tools);
56
+ const reasoning_mode = upstream_reasoning ?? "inline";
56
57
  const params = {
57
58
  ...api_extras,
58
59
  model,
@@ -64,7 +65,7 @@ var OpenAIProvider = class _OpenAIProvider {
64
65
  } : {},
65
66
  messages: [
66
67
  ...get_system_context(model, request.system, system_role),
67
- ...request.messages.flatMap((m) => to_openai_messages(m))
68
+ ...request.messages.flatMap((m) => to_openai_messages(m, reasoning_mode))
68
69
  ],
69
70
  stream_options: {
70
71
  include_usage: true
@@ -446,9 +447,9 @@ function from_openai_tool_call(tool_call) {
446
447
  extended
447
448
  };
448
449
  }
449
- function to_openai_messages(message) {
450
+ function to_openai_messages(message, upstream_reasoning) {
450
451
  if (message.role === "assistant") {
451
- return [to_openai_assistant_message(message)];
452
+ return [to_openai_assistant_message(message, upstream_reasoning)];
452
453
  }
453
454
  const tool_result_content = message.content.filter((c) => c.type === "tool_result");
454
455
  const other_content = message.content.filter((c) => c.type !== "tool_result");
@@ -531,7 +532,7 @@ function to_openai_messages(message) {
531
532
  }
532
533
  return results;
533
534
  }
534
- function to_openai_assistant_message(message) {
535
+ function to_openai_assistant_message(message, upstream_reasoning) {
535
536
  let result = {
536
537
  role: "assistant"
537
538
  };
@@ -598,6 +599,14 @@ function to_openai_assistant_message(message) {
598
599
  };
599
600
  break;
600
601
  case "thinking":
602
+ if (upstream_reasoning === "drop") {
603
+ break;
604
+ }
605
+ if (upstream_reasoning === "field") {
606
+ const widened = result;
607
+ widened.reasoning_content = widened.reasoning_content !== void 0 ? widened.reasoning_content + "\n" + content.thought : content.thought;
608
+ break;
609
+ }
601
610
  if (typeof result.content === "string") {
602
611
  result.content = [
603
612
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/openai-provider.ts"],"sourcesContent":["export { OpenAIProvider, type OpenAIProviderConfig } from \"./openai-provider.ts\";\n","import { OpenAI } from \"openai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolContent,\n ToolDefinition,\n Usage,\n} from \"@simulacra-ai/core\";\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nconst OPENAI_REASONING_DELTA_KEYS = [\"reasoning\", \"reasoning_content\", \"thinking\"] as const;\n\ntype OpenAIReasoningDeltaKey = (typeof OPENAI_REASONING_DELTA_KEYS)[number];\ntype OpenAICompletionDelta = OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta;\ntype OpenAIReasoningDelta = OpenAICompletionDelta &\n Partial<Record<OpenAIReasoningDeltaKey, string>>;\n\n/**\n * Configuration options for the OpenAI provider.\n */\nexport interface OpenAIProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gpt-4\", \"o1-preview\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /**\n * Which role to use for the system prompt.\n *\n * The OpenAI Chat Completions spec allows `system` (legacy / most providers)\n * and `developer` (introduced for o-series reasoning models). Most\n * OpenAI-compatible endpoints (DeepSeek, OpenRouter relays, Anthropic-via-\n * compat, self-hosted gateways, etc.) only accept `system` and reject\n * `developer` with a 400.\n *\n * - `\"auto\"` (default): use the built-in heuristic — `gpt*` → `\"system\"`,\n * o-series (`o1`, `o3`, `o4`, ...) → `\"developer\"`, anything else →\n * `\"system\"` (the broadly-compatible default).\n * - `\"system\"` / `\"developer\"`: force the role regardless of model id.\n *\n * The heuristic matches on the bare model id and does not understand\n * relay-style prefixes (`openai/o3`, `anthropic/claude-3-5-sonnet`,\n * etc.) — set this explicitly when routing OpenAI models through a\n * relay that uses `vendor/model` ids.\n */\n system_role?: \"auto\" | \"system\" | \"developer\";\n /**\n * Whether to emit OpenAI's strict structured-output flag on tool\n * definitions (`function.strict: true`).\n *\n * `strict` is an OpenAI-specific extension that constrains tool arguments\n * to the supplied JSON Schema. Most non-OpenAI endpoints either ignore the\n * field or reject it.\n *\n * - `\"auto\"` (default): emit `strict: true` when the model id matches the\n * built-in OpenAI heuristic — `gpt*` or o-series (`o1`, `o3`, `o4`, ...).\n * Any other model id (deepseek, etc.) gets tool defs without `strict`.\n * The heuristic matches on the bare model id; relay-style prefixes\n * (`openai/gpt-4o`) are NOT recognized — set this explicitly when\n * routing OpenAI models through a relay.\n * - `\"never\"`: never emit `strict`.\n */\n strict_tools?: \"auto\" | \"never\";\n}\n\n/**\n * Model provider implementation for OpenAI's chat completion models.\n *\n * This provider wraps the OpenAI SDK to provide streaming completions with\n * support for tool use and function calling. It handles message formatting,\n * content streaming, and usage tracking according to the ModelProvider\n * interface.\n *\n * Works against OpenAI directly as well as OpenAI-compatible endpoints\n * (DeepSeek, OpenRouter, self-hosted gateways, etc.). The default behaviour\n * picks `system` vs. `developer` for the system prompt and decides whether\n * to emit OpenAI's `strict` flag on tool defs based on the model id; both\n * can be overridden through `OpenAIProviderConfig.system_role` and\n * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.\n */\nexport class OpenAIProvider implements ModelProvider {\n readonly #sdk: OpenAI;\n readonly #config: OpenAIProviderConfig;\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new OpenAI provider instance.\n *\n * @param sdk - The initialized OpenAI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers.\n */\n constructor(\n sdk: OpenAI,\n config: OpenAIProviderConfig,\n context_transformers: ProviderContextTransformer[] = [],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, system_role, strict_tools, ...api_extras } = this.#config;\n const emit_strict = resolve_strict_tools(model, strict_tools);\n const params: OpenAI.ChatCompletionCreateParamsStreaming = {\n ...api_extras,\n model,\n stream: true,\n max_tokens,\n ...(request.tools.length > 0\n ? {\n tool_choice: \"auto\",\n tools: request.tools.map((t) => to_openai_tool(t, emit_strict)),\n }\n : {}),\n messages: [\n ...get_system_context(model, request.system, system_role),\n ...request.messages.flatMap((m) => to_openai_messages(m)),\n ],\n stream_options: {\n include_usage: true,\n },\n };\n\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const stream = await this.#sdk.chat.completions.create(params);\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(stream, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new OpenAIProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: OpenAI.Chat.Completions.ChatCompletionChunk | undefined;\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { choices: choices_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n choices: response?.choices ?? [],\n };\n\n for (const choice_chunk of choices_chunk) {\n if (!response.choices[choice_chunk.index]) {\n response.choices[choice_chunk.index] = choice_chunk;\n const message = from_openai_completion(response_chunk, choice_chunk);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage: {} });\n }\n receiver.start_message({ message, usage: {} });\n continue;\n }\n\n const { delta: delta_chunk, ...rest } = choice_chunk;\n const choice = (response.choices[choice_chunk.index] = {\n ...response.choices[choice_chunk.index],\n ...rest,\n delta: {\n ...response.choices[choice_chunk.index]?.delta,\n },\n });\n\n if (delta_chunk.role) {\n choice.delta.role = delta_chunk.role;\n }\n if (delta_chunk.refusal) {\n if (!choice.delta.refusal) {\n choice.delta.refusal = \"\";\n }\n choice.delta.refusal += delta_chunk.refusal;\n }\n const reasoning_delta = get_openai_reasoning_delta(delta_chunk);\n if (reasoning_delta) {\n const choice_delta = choice.delta as OpenAIReasoningDelta;\n const existing = choice_delta[reasoning_delta.key];\n if (!existing) {\n choice_delta[reasoning_delta.key] = reasoning_delta.thought;\n receiver.start_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice_delta[reasoning_delta.key] = existing + reasoning_delta.thought;\n receiver.update_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.content) {\n if (!choice.delta.content) {\n choice.delta.content = delta_chunk.content;\n receiver.start_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice.delta.content += delta_chunk.content;\n receiver.update_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls) {\n choice.delta.tool_calls = [];\n }\n for (const tool_call_chunk of delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls[tool_call_chunk.index]) {\n choice.delta.tool_calls[tool_call_chunk.index] = tool_call_chunk;\n receiver.start_content({\n content: from_openai_tool_call(tool_call_chunk),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n const tool_call = choice.delta.tool_calls[tool_call_chunk.index];\n\n if (tool_call_chunk.id) {\n tool_call.id = tool_call_chunk.id;\n }\n if (tool_call_chunk.type) {\n tool_call.type = tool_call_chunk.type;\n }\n if (tool_call_chunk.function) {\n if (!tool_call.function) {\n tool_call.function = tool_call_chunk.function;\n } else {\n if (tool_call_chunk.function.name) {\n tool_call.function.name = tool_call_chunk.function.name;\n }\n if (tool_call_chunk.function.arguments) {\n if (!tool_call.function.arguments) {\n tool_call.function.arguments = \"\";\n }\n tool_call.function.arguments += tool_call_chunk.function.arguments;\n }\n }\n }\n receiver.update_content({\n content: from_openai_tool_call(tool_call),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n }\n }\n }\n if (!response || !response.choices?.[0]) {\n throw new Error(\"no data\");\n }\n receiver.response_raw({ ...response });\n\n const message = from_openai_completion(response, response.choices[0]);\n const usage = response?.usage ? from_openai_usage(response.usage) : {};\n for (const content of message.content) {\n receiver.complete_content({ content, message, usage });\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction get_system_context(\n model: string,\n system: string | undefined,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): OpenAI.ChatCompletionMessageParam[] {\n if (!system) {\n return [];\n }\n const role = resolve_system_role(model, system_role);\n if (role === \"developer\") {\n return [\n {\n role: \"developer\",\n content: system,\n } as OpenAI.ChatCompletionDeveloperMessageParam,\n ];\n }\n return [\n {\n role: \"system\",\n content: system,\n } as OpenAI.ChatCompletionSystemMessageParam,\n ];\n}\n\nfunction resolve_system_role(\n model: string,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): \"system\" | \"developer\" {\n if (system_role === \"system\" || system_role === \"developer\") {\n return system_role;\n }\n if (model.startsWith(\"gpt\")) {\n return \"system\";\n }\n if (is_openai_reasoning_model(model)) {\n return \"developer\";\n }\n return \"system\";\n}\n\nfunction resolve_strict_tools(\n model: string,\n strict_tools: OpenAIProviderConfig[\"strict_tools\"] = \"auto\",\n): boolean {\n if (strict_tools === \"never\") {\n return false;\n }\n return model.startsWith(\"gpt\") || is_openai_reasoning_model(model);\n}\n\n// Best-effort match for OpenAI's o-series reasoning model ids (o1, o3,\n// o4-mini, etc.). The leading non-zero digit and end-of-string-or-hyphen\n// anchor narrow the pattern to what OpenAI actually ships. Two known\n// failure modes: a non-OpenAI vendor whose model id happens to follow the\n// same shape (e.g. `o2-fast`) gets matched as o-series, and a relay-style\n// id like `openai/o3` is NOT matched because the regex anchors at start\n// of string. Operators in either situation should set `system_role` and\n// `strict_tools` explicitly — the heuristic is a default, not a constraint.\nfunction is_openai_reasoning_model(model: string): boolean {\n return /^o[1-9]\\d*(-|$)/.test(model);\n}\n\nfunction to_openai_tool(tool: ToolDefinition, strict: boolean): OpenAI.Chat.ChatCompletionTool {\n function map_parameter_type(\n parameter: Prettify<ParameterType & { description?: string }>,\n ): OpenAI.FunctionParameters {\n switch (parameter.type) {\n case \"object\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n properties: Object.fromEntries(\n Object.entries(parameter.properties).map(([k, v]) => [k, map_parameter_type(v)]),\n ),\n additionalProperties: false,\n required: Object.entries(parameter.properties).map(([k]) => k),\n };\n case \"array\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n items: map_parameter_type(parameter.items),\n };\n default:\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description:\n parameter.default !== undefined\n ? parameter.description\n ? `${parameter.description} (default: ${parameter.default})`\n : `default: ${parameter.default}`\n : parameter.description,\n enum: \"enum\" in parameter ? parameter.enum : undefined,\n };\n }\n }\n return {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: map_parameter_type({\n type: \"object\",\n required: true,\n properties: Object.fromEntries(\n tool.parameters.map(({ name, ...parameter }) => [name, parameter]),\n ),\n }),\n ...(strict ? { strict: true } : {}),\n },\n };\n}\n\nfunction from_openai_completion(\n completion: OpenAI.Chat.Completions.ChatCompletionChunk,\n choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice,\n) {\n let contents: Content[] = [];\n const thinking = from_openai_thinking(choice.delta);\n if (thinking) {\n contents = [...contents, thinking];\n }\n const delta_record = choice.delta as Record<string, unknown>;\n for (const key of Object.keys(choice.delta)) {\n if (key === \"role\") {\n continue;\n }\n if (is_openai_reasoning_delta_key(key)) {\n continue;\n }\n if (key === \"content\") {\n if (choice.delta.content) {\n contents = [...contents, from_openai_content(choice.delta)];\n }\n continue;\n }\n if (key === \"refusal\") {\n if (choice.delta.refusal) {\n contents = [...contents, from_openai_refusal(choice.delta)];\n }\n continue;\n }\n if (key === \"tool_calls\") {\n if (choice.delta.tool_calls) {\n contents = [...contents, ...choice.delta.tool_calls.map((t) => from_openai_tool_call(t))];\n }\n continue;\n }\n if (delta_record[key] !== undefined && delta_record[key] !== null) {\n const data = delta_record[key];\n contents = [\n ...contents,\n {\n type: \"raw\",\n model_kind: \"openai\",\n data: JSON.stringify({ [key]: data }),\n },\n ];\n }\n }\n return {\n id: completion.id,\n timestamp: completion.created,\n role: map_role(choice),\n content: contents,\n } as AssistantMessage;\n}\n\nfunction get_openai_reasoning_delta(delta: OpenAICompletionDelta) {\n const record = delta as Partial<Record<OpenAIReasoningDeltaKey, unknown>>;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n const thought = record[key];\n if (typeof thought === \"string\" && thought.length > 0) {\n return { key, thought };\n }\n }\n return undefined;\n}\n\nfunction from_openai_thinking(content: OpenAICompletionDelta) {\n const reasoning = get_openai_reasoning_delta(content);\n if (!reasoning) {\n return undefined;\n }\n const extended = get_openai_delta_extended(content);\n return {\n type: \"thinking\",\n thought: reasoning.thought,\n extended: {\n ...extended,\n openai_reasoning_field: reasoning.key,\n },\n } as Content;\n}\n\nfunction is_openai_reasoning_delta_key(key: string): key is OpenAIReasoningDeltaKey {\n return OPENAI_REASONING_DELTA_KEYS.includes(key as OpenAIReasoningDeltaKey);\n}\n\nfunction from_openai_refusal(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.refusal,\n extended: {\n ...get_openai_delta_extended(content),\n openai_refusal: true,\n },\n } as Content;\n}\n\nfunction from_openai_content(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.content,\n extended: get_openai_delta_extended(content),\n } as Content;\n}\n\nfunction get_openai_delta_extended(content: OpenAICompletionDelta) {\n const extended = { ...(content as Record<string, unknown>) };\n delete extended.content;\n delete extended.tool_calls;\n delete extended.function_call;\n delete extended.refusal;\n delete extended.role;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n delete extended[key];\n }\n return extended;\n}\n\nfunction from_openai_tool_call(\n tool_call: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall,\n) {\n const { id: tool_request_id, function: fn, type: _, index: __, ...extended } = tool_call;\n let params: unknown;\n try {\n params = JSON.parse(fn?.arguments ?? \"{}\");\n } catch {\n params = fn?.arguments;\n }\n return {\n tool_request_id,\n type: \"tool\",\n tool: fn?.name,\n params,\n extended,\n } as ToolContent;\n}\n\nfunction to_openai_messages(message: Message) {\n if (message.role === \"assistant\") {\n return [to_openai_assistant_message(message)];\n }\n // Partition content so tool_result blocks come before non-tool_result blocks.\n // OpenAI requires all tool-role messages immediately after the assistant message\n // containing the corresponding tool_calls; interleaving user messages between\n // tool messages causes a validation error.\n const tool_result_content = message.content.filter((c) => c.type === \"tool_result\");\n const other_content = message.content.filter((c) => c.type !== \"tool_result\");\n const ordered_content = [...tool_result_content, ...other_content];\n\n const results: OpenAI.ChatCompletionMessageParam[] = [];\n let result: OpenAI.ChatCompletionMessageParam | undefined;\n for (const content of ordered_content) {\n if (content.type === \"text\") {\n if (!result) {\n result = {\n role: \"user\",\n content: content.text,\n };\n } else if (result.role === \"tool\") {\n results.push(result);\n result = {\n role: \"user\",\n content: content.text,\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = [\n {\n type: \"text\",\n text: content.text,\n },\n ];\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n } else if (content.type === \"tool_result\") {\n if (!result) {\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else if (result.role !== \"tool\" || result.tool_call_id !== content.tool_request_id) {\n results.push(result);\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n result.content.push({\n type: \"text\",\n text: JSON.stringify(content.result),\n });\n }\n } else if (content.type === \"raw\") {\n result = {\n ...(result ?? {}),\n ...JSON.parse(content.data),\n };\n }\n }\n if (result) {\n results.push(result);\n }\n return results;\n}\n\nfunction to_openai_assistant_message(message: AssistantMessage) {\n let result: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n };\n for (const content of message.content) {\n switch (content.type) {\n case \"text\":\n if (content.extended && content.extended.openai_refusal === true) {\n result.refusal = content.text;\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.text;\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n break;\n case \"tool\":\n if (!result.tool_calls) {\n result.tool_calls = [];\n }\n result.tool_calls.push({\n id: content.tool_request_id,\n type: \"function\",\n function: {\n name: content.tool,\n arguments: JSON.stringify(content.params),\n },\n });\n break;\n case \"raw\":\n if (content.model_kind !== \"openai\") {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.data;\n } else {\n result.content.push({\n type: \"text\",\n text: content.data,\n });\n }\n break;\n }\n result = {\n ...result,\n ...JSON.parse(content.data),\n };\n break;\n case \"thinking\":\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.thought;\n } else {\n result.content.push({\n type: \"text\",\n text: content.thought,\n });\n }\n break;\n default:\n throw new Error(\"unexpected content type\");\n }\n }\n return result;\n}\n\nfunction from_openai_usage(usage: OpenAI.CompletionUsage | null | undefined) {\n return {\n input_tokens: usage?.prompt_tokens,\n output_tokens: usage?.completion_tokens,\n } as Usage;\n}\n\nfunction map_stop_reason(\n completion: OpenAI.ChatCompletionChunk,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const choice of completion.choices) {\n switch (choice.finish_reason) {\n case \"content_filter\":\n return {\n stop_reason: \"error\",\n stop_details: choice.finish_reason,\n };\n case \"function_call\":\n return {\n stop_reason: \"tool_use\",\n };\n case \"length\":\n return {\n stop_reason: \"max_tokens\",\n };\n case \"stop\":\n return {\n stop_reason: \"end_turn\",\n };\n case \"tool_calls\":\n return {\n stop_reason: \"tool_use\",\n };\n default:\n return {\n stop_reason: \"other\",\n stop_details: `${choice.finish_reason}`,\n };\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n\nfunction map_role(choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice) {\n switch (choice.delta.role) {\n case \"user\":\n case \"developer\":\n case \"system\":\n return \"user\";\n case \"assistant\":\n case \"tool\":\n return \"assistant\";\n default:\n throw new Error(\"invalid role\");\n }\n}\n"],"mappings":"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","names":["message","rest"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/openai-provider.ts"],"sourcesContent":["export { OpenAIProvider, type OpenAIProviderConfig } from \"./openai-provider.ts\";\n","import { OpenAI } from \"openai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolContent,\n ToolDefinition,\n Usage,\n} from \"@simulacra-ai/core\";\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nconst OPENAI_REASONING_DELTA_KEYS = [\"reasoning\", \"reasoning_content\", \"thinking\"] as const;\n\ntype OpenAIReasoningDeltaKey = (typeof OPENAI_REASONING_DELTA_KEYS)[number];\ntype OpenAICompletionDelta = OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta;\ntype OpenAIReasoningDelta = OpenAICompletionDelta &\n Partial<Record<OpenAIReasoningDeltaKey, string>>;\n\n/**\n * Configuration options for the OpenAI provider.\n */\nexport interface OpenAIProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gpt-4\", \"o1-preview\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /**\n * Which role to use for the system prompt.\n *\n * The OpenAI Chat Completions spec allows `system` (legacy / most providers)\n * and `developer` (introduced for o-series reasoning models). Most\n * OpenAI-compatible endpoints (DeepSeek, OpenRouter relays, Anthropic-via-\n * compat, self-hosted gateways, etc.) only accept `system` and reject\n * `developer` with a 400.\n *\n * - `\"auto\"` (default): use the built-in heuristic — `gpt*` → `\"system\"`,\n * o-series (`o1`, `o3`, `o4`, ...) → `\"developer\"`, anything else →\n * `\"system\"` (the broadly-compatible default).\n * - `\"system\"` / `\"developer\"`: force the role regardless of model id.\n *\n * The heuristic matches on the bare model id and does not understand\n * relay-style prefixes (`openai/o3`, `anthropic/claude-3-5-sonnet`,\n * etc.) — set this explicitly when routing OpenAI models through a\n * relay that uses `vendor/model` ids.\n */\n system_role?: \"auto\" | \"system\" | \"developer\";\n /**\n * Whether to emit OpenAI's strict structured-output flag on tool\n * definitions (`function.strict: true`).\n *\n * `strict` is an OpenAI-specific extension that constrains tool arguments\n * to the supplied JSON Schema. Most non-OpenAI endpoints either ignore the\n * field or reject it.\n *\n * - `\"auto\"` (default): emit `strict: true` when the model id matches the\n * built-in OpenAI heuristic — `gpt*` or o-series (`o1`, `o3`, `o4`, ...).\n * Any other model id (deepseek, etc.) gets tool defs without `strict`.\n * The heuristic matches on the bare model id; relay-style prefixes\n * (`openai/gpt-4o`) are NOT recognized — set this explicitly when\n * routing OpenAI models through a relay.\n * - `\"never\"`: never emit `strict`.\n */\n strict_tools?: \"auto\" | \"never\";\n /**\n * Treatment of prior `thinking` content blocks when serializing assistant\n * messages back up the wire.\n *\n * - `\"inline\"` (default): appended as text content. openai tolerates it.\n * - `\"field\"`: emitted as a `reasoning_content` field. required by\n * deepseek v4 thinking-mode.\n * - `\"drop\"`: omitted entirely.\n */\n upstream_reasoning?: \"inline\" | \"field\" | \"drop\";\n}\n\n/**\n * Model provider implementation for OpenAI's chat completion models.\n *\n * This provider wraps the OpenAI SDK to provide streaming completions with\n * support for tool use and function calling. It handles message formatting,\n * content streaming, and usage tracking according to the ModelProvider\n * interface.\n *\n * Works against OpenAI directly as well as OpenAI-compatible endpoints\n * (DeepSeek, OpenRouter, self-hosted gateways, etc.). The default behaviour\n * picks `system` vs. `developer` for the system prompt and decides whether\n * to emit OpenAI's `strict` flag on tool defs based on the model id; both\n * can be overridden through `OpenAIProviderConfig.system_role` and\n * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.\n * `OpenAIProviderConfig.upstream_reasoning` controls how prior thinking\n * content is round-tripped on subsequent calls for providers (deepseek v4)\n * that require it in a specific shape.\n */\nexport class OpenAIProvider implements ModelProvider {\n readonly #sdk: OpenAI;\n readonly #config: OpenAIProviderConfig;\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new OpenAI provider instance.\n *\n * @param sdk - The initialized OpenAI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers.\n */\n constructor(\n sdk: OpenAI,\n config: OpenAIProviderConfig,\n context_transformers: ProviderContextTransformer[] = [],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, system_role, strict_tools, upstream_reasoning, ...api_extras } =\n this.#config;\n const emit_strict = resolve_strict_tools(model, strict_tools);\n const reasoning_mode = upstream_reasoning ?? \"inline\";\n const params: OpenAI.ChatCompletionCreateParamsStreaming = {\n ...api_extras,\n model,\n stream: true,\n max_tokens,\n ...(request.tools.length > 0\n ? {\n tool_choice: \"auto\",\n tools: request.tools.map((t) => to_openai_tool(t, emit_strict)),\n }\n : {}),\n messages: [\n ...get_system_context(model, request.system, system_role),\n ...request.messages.flatMap((m) => to_openai_messages(m, reasoning_mode)),\n ],\n stream_options: {\n include_usage: true,\n },\n };\n\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const stream = await this.#sdk.chat.completions.create(params);\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(stream, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new OpenAIProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: OpenAI.Chat.Completions.ChatCompletionChunk | undefined;\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { choices: choices_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n choices: response?.choices ?? [],\n };\n\n for (const choice_chunk of choices_chunk) {\n if (!response.choices[choice_chunk.index]) {\n response.choices[choice_chunk.index] = choice_chunk;\n const message = from_openai_completion(response_chunk, choice_chunk);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage: {} });\n }\n receiver.start_message({ message, usage: {} });\n continue;\n }\n\n const { delta: delta_chunk, ...rest } = choice_chunk;\n const choice = (response.choices[choice_chunk.index] = {\n ...response.choices[choice_chunk.index],\n ...rest,\n delta: {\n ...response.choices[choice_chunk.index]?.delta,\n },\n });\n\n if (delta_chunk.role) {\n choice.delta.role = delta_chunk.role;\n }\n if (delta_chunk.refusal) {\n if (!choice.delta.refusal) {\n choice.delta.refusal = \"\";\n }\n choice.delta.refusal += delta_chunk.refusal;\n }\n const reasoning_delta = get_openai_reasoning_delta(delta_chunk);\n if (reasoning_delta) {\n const choice_delta = choice.delta as OpenAIReasoningDelta;\n const existing = choice_delta[reasoning_delta.key];\n if (!existing) {\n choice_delta[reasoning_delta.key] = reasoning_delta.thought;\n receiver.start_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice_delta[reasoning_delta.key] = existing + reasoning_delta.thought;\n receiver.update_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.content) {\n if (!choice.delta.content) {\n choice.delta.content = delta_chunk.content;\n receiver.start_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice.delta.content += delta_chunk.content;\n receiver.update_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls) {\n choice.delta.tool_calls = [];\n }\n for (const tool_call_chunk of delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls[tool_call_chunk.index]) {\n choice.delta.tool_calls[tool_call_chunk.index] = tool_call_chunk;\n receiver.start_content({\n content: from_openai_tool_call(tool_call_chunk),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n const tool_call = choice.delta.tool_calls[tool_call_chunk.index];\n\n if (tool_call_chunk.id) {\n tool_call.id = tool_call_chunk.id;\n }\n if (tool_call_chunk.type) {\n tool_call.type = tool_call_chunk.type;\n }\n if (tool_call_chunk.function) {\n if (!tool_call.function) {\n tool_call.function = tool_call_chunk.function;\n } else {\n if (tool_call_chunk.function.name) {\n tool_call.function.name = tool_call_chunk.function.name;\n }\n if (tool_call_chunk.function.arguments) {\n if (!tool_call.function.arguments) {\n tool_call.function.arguments = \"\";\n }\n tool_call.function.arguments += tool_call_chunk.function.arguments;\n }\n }\n }\n receiver.update_content({\n content: from_openai_tool_call(tool_call),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n }\n }\n }\n if (!response || !response.choices?.[0]) {\n throw new Error(\"no data\");\n }\n receiver.response_raw({ ...response });\n\n const message = from_openai_completion(response, response.choices[0]);\n const usage = response?.usage ? from_openai_usage(response.usage) : {};\n for (const content of message.content) {\n receiver.complete_content({ content, message, usage });\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction get_system_context(\n model: string,\n system: string | undefined,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): OpenAI.ChatCompletionMessageParam[] {\n if (!system) {\n return [];\n }\n const role = resolve_system_role(model, system_role);\n if (role === \"developer\") {\n return [\n {\n role: \"developer\",\n content: system,\n } as OpenAI.ChatCompletionDeveloperMessageParam,\n ];\n }\n return [\n {\n role: \"system\",\n content: system,\n } as OpenAI.ChatCompletionSystemMessageParam,\n ];\n}\n\nfunction resolve_system_role(\n model: string,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): \"system\" | \"developer\" {\n if (system_role === \"system\" || system_role === \"developer\") {\n return system_role;\n }\n if (model.startsWith(\"gpt\")) {\n return \"system\";\n }\n if (is_openai_reasoning_model(model)) {\n return \"developer\";\n }\n return \"system\";\n}\n\nfunction resolve_strict_tools(\n model: string,\n strict_tools: OpenAIProviderConfig[\"strict_tools\"] = \"auto\",\n): boolean {\n if (strict_tools === \"never\") {\n return false;\n }\n return model.startsWith(\"gpt\") || is_openai_reasoning_model(model);\n}\n\n// Best-effort match for OpenAI's o-series reasoning model ids (o1, o3,\n// o4-mini, etc.). The leading non-zero digit and end-of-string-or-hyphen\n// anchor narrow the pattern to what OpenAI actually ships. Two known\n// failure modes: a non-OpenAI vendor whose model id happens to follow the\n// same shape (e.g. `o2-fast`) gets matched as o-series, and a relay-style\n// id like `openai/o3` is NOT matched because the regex anchors at start\n// of string. Operators in either situation should set `system_role` and\n// `strict_tools` explicitly — the heuristic is a default, not a constraint.\nfunction is_openai_reasoning_model(model: string): boolean {\n return /^o[1-9]\\d*(-|$)/.test(model);\n}\n\nfunction to_openai_tool(tool: ToolDefinition, strict: boolean): OpenAI.Chat.ChatCompletionTool {\n function map_parameter_type(\n parameter: Prettify<ParameterType & { description?: string }>,\n ): OpenAI.FunctionParameters {\n switch (parameter.type) {\n case \"object\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n properties: Object.fromEntries(\n Object.entries(parameter.properties).map(([k, v]) => [k, map_parameter_type(v)]),\n ),\n additionalProperties: false,\n required: Object.entries(parameter.properties).map(([k]) => k),\n };\n case \"array\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n items: map_parameter_type(parameter.items),\n };\n default:\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description:\n parameter.default !== undefined\n ? parameter.description\n ? `${parameter.description} (default: ${parameter.default})`\n : `default: ${parameter.default}`\n : parameter.description,\n enum: \"enum\" in parameter ? parameter.enum : undefined,\n };\n }\n }\n return {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: map_parameter_type({\n type: \"object\",\n required: true,\n properties: Object.fromEntries(\n tool.parameters.map(({ name, ...parameter }) => [name, parameter]),\n ),\n }),\n ...(strict ? { strict: true } : {}),\n },\n };\n}\n\nfunction from_openai_completion(\n completion: OpenAI.Chat.Completions.ChatCompletionChunk,\n choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice,\n) {\n let contents: Content[] = [];\n const thinking = from_openai_thinking(choice.delta);\n if (thinking) {\n contents = [...contents, thinking];\n }\n const delta_record = choice.delta as Record<string, unknown>;\n for (const key of Object.keys(choice.delta)) {\n if (key === \"role\") {\n continue;\n }\n if (is_openai_reasoning_delta_key(key)) {\n continue;\n }\n if (key === \"content\") {\n if (choice.delta.content) {\n contents = [...contents, from_openai_content(choice.delta)];\n }\n continue;\n }\n if (key === \"refusal\") {\n if (choice.delta.refusal) {\n contents = [...contents, from_openai_refusal(choice.delta)];\n }\n continue;\n }\n if (key === \"tool_calls\") {\n if (choice.delta.tool_calls) {\n contents = [...contents, ...choice.delta.tool_calls.map((t) => from_openai_tool_call(t))];\n }\n continue;\n }\n if (delta_record[key] !== undefined && delta_record[key] !== null) {\n const data = delta_record[key];\n contents = [\n ...contents,\n {\n type: \"raw\",\n model_kind: \"openai\",\n data: JSON.stringify({ [key]: data }),\n },\n ];\n }\n }\n return {\n id: completion.id,\n timestamp: completion.created,\n role: map_role(choice),\n content: contents,\n } as AssistantMessage;\n}\n\nfunction get_openai_reasoning_delta(delta: OpenAICompletionDelta) {\n const record = delta as Partial<Record<OpenAIReasoningDeltaKey, unknown>>;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n const thought = record[key];\n if (typeof thought === \"string\" && thought.length > 0) {\n return { key, thought };\n }\n }\n return undefined;\n}\n\nfunction from_openai_thinking(content: OpenAICompletionDelta) {\n const reasoning = get_openai_reasoning_delta(content);\n if (!reasoning) {\n return undefined;\n }\n const extended = get_openai_delta_extended(content);\n return {\n type: \"thinking\",\n thought: reasoning.thought,\n extended: {\n ...extended,\n openai_reasoning_field: reasoning.key,\n },\n } as Content;\n}\n\nfunction is_openai_reasoning_delta_key(key: string): key is OpenAIReasoningDeltaKey {\n return OPENAI_REASONING_DELTA_KEYS.includes(key as OpenAIReasoningDeltaKey);\n}\n\nfunction from_openai_refusal(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.refusal,\n extended: {\n ...get_openai_delta_extended(content),\n openai_refusal: true,\n },\n } as Content;\n}\n\nfunction from_openai_content(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.content,\n extended: get_openai_delta_extended(content),\n } as Content;\n}\n\nfunction get_openai_delta_extended(content: OpenAICompletionDelta) {\n const extended = { ...(content as Record<string, unknown>) };\n delete extended.content;\n delete extended.tool_calls;\n delete extended.function_call;\n delete extended.refusal;\n delete extended.role;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n delete extended[key];\n }\n return extended;\n}\n\nfunction from_openai_tool_call(\n tool_call: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall,\n) {\n const { id: tool_request_id, function: fn, type: _, index: __, ...extended } = tool_call;\n let params: unknown;\n try {\n params = JSON.parse(fn?.arguments ?? \"{}\");\n } catch {\n params = fn?.arguments;\n }\n return {\n tool_request_id,\n type: \"tool\",\n tool: fn?.name,\n params,\n extended,\n } as ToolContent;\n}\n\nfunction to_openai_messages(\n message: Message,\n upstream_reasoning: NonNullable<OpenAIProviderConfig[\"upstream_reasoning\"]>,\n) {\n if (message.role === \"assistant\") {\n return [to_openai_assistant_message(message, upstream_reasoning)];\n }\n // Partition content so tool_result blocks come before non-tool_result blocks.\n // OpenAI requires all tool-role messages immediately after the assistant message\n // containing the corresponding tool_calls; interleaving user messages between\n // tool messages causes a validation error.\n const tool_result_content = message.content.filter((c) => c.type === \"tool_result\");\n const other_content = message.content.filter((c) => c.type !== \"tool_result\");\n const ordered_content = [...tool_result_content, ...other_content];\n\n const results: OpenAI.ChatCompletionMessageParam[] = [];\n let result: OpenAI.ChatCompletionMessageParam | undefined;\n for (const content of ordered_content) {\n if (content.type === \"text\") {\n if (!result) {\n result = {\n role: \"user\",\n content: content.text,\n };\n } else if (result.role === \"tool\") {\n results.push(result);\n result = {\n role: \"user\",\n content: content.text,\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = [\n {\n type: \"text\",\n text: content.text,\n },\n ];\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n } else if (content.type === \"tool_result\") {\n if (!result) {\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else if (result.role !== \"tool\" || result.tool_call_id !== content.tool_request_id) {\n results.push(result);\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n result.content.push({\n type: \"text\",\n text: JSON.stringify(content.result),\n });\n }\n } else if (content.type === \"raw\") {\n result = {\n ...(result ?? {}),\n ...JSON.parse(content.data),\n };\n }\n }\n if (result) {\n results.push(result);\n }\n return results;\n}\n\nfunction to_openai_assistant_message(\n message: AssistantMessage,\n upstream_reasoning: NonNullable<OpenAIProviderConfig[\"upstream_reasoning\"]>,\n) {\n let result: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n };\n for (const content of message.content) {\n switch (content.type) {\n case \"text\":\n if (content.extended && content.extended.openai_refusal === true) {\n result.refusal = content.text;\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.text;\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n break;\n case \"tool\":\n if (!result.tool_calls) {\n result.tool_calls = [];\n }\n result.tool_calls.push({\n id: content.tool_request_id,\n type: \"function\",\n function: {\n name: content.tool,\n arguments: JSON.stringify(content.params),\n },\n });\n break;\n case \"raw\":\n if (content.model_kind !== \"openai\") {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.data;\n } else {\n result.content.push({\n type: \"text\",\n text: content.data,\n });\n }\n break;\n }\n result = {\n ...result,\n ...JSON.parse(content.data),\n };\n break;\n case \"thinking\":\n if (upstream_reasoning === \"drop\") {\n break;\n }\n if (upstream_reasoning === \"field\") {\n const widened = result as OpenAI.ChatCompletionAssistantMessageParam & {\n reasoning_content?: string;\n };\n widened.reasoning_content =\n widened.reasoning_content !== undefined\n ? widened.reasoning_content + \"\\n\" + content.thought\n : content.thought;\n break;\n }\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.thought;\n } else {\n result.content.push({\n type: \"text\",\n text: content.thought,\n });\n }\n break;\n default:\n throw new Error(\"unexpected content type\");\n }\n }\n return result;\n}\n\nfunction from_openai_usage(usage: OpenAI.CompletionUsage | null | undefined) {\n return {\n input_tokens: usage?.prompt_tokens,\n output_tokens: usage?.completion_tokens,\n } as Usage;\n}\n\nfunction map_stop_reason(\n completion: OpenAI.ChatCompletionChunk,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const choice of completion.choices) {\n switch (choice.finish_reason) {\n case \"content_filter\":\n return {\n stop_reason: \"error\",\n stop_details: choice.finish_reason,\n };\n case \"function_call\":\n return {\n stop_reason: \"tool_use\",\n };\n case \"length\":\n return {\n stop_reason: \"max_tokens\",\n };\n case \"stop\":\n return {\n stop_reason: \"end_turn\",\n };\n case \"tool_calls\":\n return {\n stop_reason: \"tool_use\",\n };\n default:\n return {\n stop_reason: \"other\",\n stop_details: `${choice.finish_reason}`,\n };\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n\nfunction map_role(choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice) {\n switch (choice.delta.role) {\n case \"user\":\n case \"developer\":\n case \"system\":\n return \"user\";\n case \"assistant\":\n case \"tool\":\n return \"assistant\";\n default:\n throw new Error(\"invalid role\");\n }\n}\n"],"mappings":"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","names":["message","rest"]}
package/dist/index.d.cts CHANGED
@@ -46,6 +46,16 @@ interface OpenAIProviderConfig extends Record<string, unknown> {
46
46
  * - `"never"`: never emit `strict`.
47
47
  */
48
48
  strict_tools?: "auto" | "never";
49
+ /**
50
+ * Treatment of prior `thinking` content blocks when serializing assistant
51
+ * messages back up the wire.
52
+ *
53
+ * - `"inline"` (default): appended as text content. openai tolerates it.
54
+ * - `"field"`: emitted as a `reasoning_content` field. required by
55
+ * deepseek v4 thinking-mode.
56
+ * - `"drop"`: omitted entirely.
57
+ */
58
+ upstream_reasoning?: "inline" | "field" | "drop";
49
59
  }
50
60
  /**
51
61
  * Model provider implementation for OpenAI's chat completion models.
@@ -61,6 +71,9 @@ interface OpenAIProviderConfig extends Record<string, unknown> {
61
71
  * to emit OpenAI's `strict` flag on tool defs based on the model id; both
62
72
  * can be overridden through `OpenAIProviderConfig.system_role` and
63
73
  * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.
74
+ * `OpenAIProviderConfig.upstream_reasoning` controls how prior thinking
75
+ * content is round-tripped on subsequent calls for providers (deepseek v4)
76
+ * that require it in a specific shape.
64
77
  */
65
78
  declare class OpenAIProvider implements ModelProvider {
66
79
  #private;
package/dist/index.d.ts CHANGED
@@ -46,6 +46,16 @@ interface OpenAIProviderConfig extends Record<string, unknown> {
46
46
  * - `"never"`: never emit `strict`.
47
47
  */
48
48
  strict_tools?: "auto" | "never";
49
+ /**
50
+ * Treatment of prior `thinking` content blocks when serializing assistant
51
+ * messages back up the wire.
52
+ *
53
+ * - `"inline"` (default): appended as text content. openai tolerates it.
54
+ * - `"field"`: emitted as a `reasoning_content` field. required by
55
+ * deepseek v4 thinking-mode.
56
+ * - `"drop"`: omitted entirely.
57
+ */
58
+ upstream_reasoning?: "inline" | "field" | "drop";
49
59
  }
50
60
  /**
51
61
  * Model provider implementation for OpenAI's chat completion models.
@@ -61,6 +71,9 @@ interface OpenAIProviderConfig extends Record<string, unknown> {
61
71
  * to emit OpenAI's `strict` flag on tool defs based on the model id; both
62
72
  * can be overridden through `OpenAIProviderConfig.system_role` and
63
73
  * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.
74
+ * `OpenAIProviderConfig.upstream_reasoning` controls how prior thinking
75
+ * content is round-tripped on subsequent calls for providers (deepseek v4)
76
+ * that require it in a specific shape.
64
77
  */
65
78
  declare class OpenAIProvider implements ModelProvider {
66
79
  #private;
package/dist/index.js CHANGED
@@ -25,8 +25,9 @@ var OpenAIProvider = class _OpenAIProvider {
25
25
  * @returns A promise that resolves when the request completes.
26
26
  */
27
27
  async execute_request(request, receiver, cancellation) {
28
- const { model, max_tokens, system_role, strict_tools, ...api_extras } = this.#config;
28
+ const { model, max_tokens, system_role, strict_tools, upstream_reasoning, ...api_extras } = this.#config;
29
29
  const emit_strict = resolve_strict_tools(model, strict_tools);
30
+ const reasoning_mode = upstream_reasoning ?? "inline";
30
31
  const params = {
31
32
  ...api_extras,
32
33
  model,
@@ -38,7 +39,7 @@ var OpenAIProvider = class _OpenAIProvider {
38
39
  } : {},
39
40
  messages: [
40
41
  ...get_system_context(model, request.system, system_role),
41
- ...request.messages.flatMap((m) => to_openai_messages(m))
42
+ ...request.messages.flatMap((m) => to_openai_messages(m, reasoning_mode))
42
43
  ],
43
44
  stream_options: {
44
45
  include_usage: true
@@ -420,9 +421,9 @@ function from_openai_tool_call(tool_call) {
420
421
  extended
421
422
  };
422
423
  }
423
- function to_openai_messages(message) {
424
+ function to_openai_messages(message, upstream_reasoning) {
424
425
  if (message.role === "assistant") {
425
- return [to_openai_assistant_message(message)];
426
+ return [to_openai_assistant_message(message, upstream_reasoning)];
426
427
  }
427
428
  const tool_result_content = message.content.filter((c) => c.type === "tool_result");
428
429
  const other_content = message.content.filter((c) => c.type !== "tool_result");
@@ -505,7 +506,7 @@ function to_openai_messages(message) {
505
506
  }
506
507
  return results;
507
508
  }
508
- function to_openai_assistant_message(message) {
509
+ function to_openai_assistant_message(message, upstream_reasoning) {
509
510
  let result = {
510
511
  role: "assistant"
511
512
  };
@@ -572,6 +573,14 @@ function to_openai_assistant_message(message) {
572
573
  };
573
574
  break;
574
575
  case "thinking":
576
+ if (upstream_reasoning === "drop") {
577
+ break;
578
+ }
579
+ if (upstream_reasoning === "field") {
580
+ const widened = result;
581
+ widened.reasoning_content = widened.reasoning_content !== void 0 ? widened.reasoning_content + "\n" + content.thought : content.thought;
582
+ break;
583
+ }
575
584
  if (typeof result.content === "string") {
576
585
  result.content = [
577
586
  {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/openai-provider.ts"],"sourcesContent":["import { OpenAI } from \"openai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolContent,\n ToolDefinition,\n Usage,\n} from \"@simulacra-ai/core\";\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nconst OPENAI_REASONING_DELTA_KEYS = [\"reasoning\", \"reasoning_content\", \"thinking\"] as const;\n\ntype OpenAIReasoningDeltaKey = (typeof OPENAI_REASONING_DELTA_KEYS)[number];\ntype OpenAICompletionDelta = OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta;\ntype OpenAIReasoningDelta = OpenAICompletionDelta &\n Partial<Record<OpenAIReasoningDeltaKey, string>>;\n\n/**\n * Configuration options for the OpenAI provider.\n */\nexport interface OpenAIProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gpt-4\", \"o1-preview\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /**\n * Which role to use for the system prompt.\n *\n * The OpenAI Chat Completions spec allows `system` (legacy / most providers)\n * and `developer` (introduced for o-series reasoning models). Most\n * OpenAI-compatible endpoints (DeepSeek, OpenRouter relays, Anthropic-via-\n * compat, self-hosted gateways, etc.) only accept `system` and reject\n * `developer` with a 400.\n *\n * - `\"auto\"` (default): use the built-in heuristic — `gpt*` → `\"system\"`,\n * o-series (`o1`, `o3`, `o4`, ...) → `\"developer\"`, anything else →\n * `\"system\"` (the broadly-compatible default).\n * - `\"system\"` / `\"developer\"`: force the role regardless of model id.\n *\n * The heuristic matches on the bare model id and does not understand\n * relay-style prefixes (`openai/o3`, `anthropic/claude-3-5-sonnet`,\n * etc.) — set this explicitly when routing OpenAI models through a\n * relay that uses `vendor/model` ids.\n */\n system_role?: \"auto\" | \"system\" | \"developer\";\n /**\n * Whether to emit OpenAI's strict structured-output flag on tool\n * definitions (`function.strict: true`).\n *\n * `strict` is an OpenAI-specific extension that constrains tool arguments\n * to the supplied JSON Schema. Most non-OpenAI endpoints either ignore the\n * field or reject it.\n *\n * - `\"auto\"` (default): emit `strict: true` when the model id matches the\n * built-in OpenAI heuristic — `gpt*` or o-series (`o1`, `o3`, `o4`, ...).\n * Any other model id (deepseek, etc.) gets tool defs without `strict`.\n * The heuristic matches on the bare model id; relay-style prefixes\n * (`openai/gpt-4o`) are NOT recognized — set this explicitly when\n * routing OpenAI models through a relay.\n * - `\"never\"`: never emit `strict`.\n */\n strict_tools?: \"auto\" | \"never\";\n}\n\n/**\n * Model provider implementation for OpenAI's chat completion models.\n *\n * This provider wraps the OpenAI SDK to provide streaming completions with\n * support for tool use and function calling. It handles message formatting,\n * content streaming, and usage tracking according to the ModelProvider\n * interface.\n *\n * Works against OpenAI directly as well as OpenAI-compatible endpoints\n * (DeepSeek, OpenRouter, self-hosted gateways, etc.). The default behaviour\n * picks `system` vs. `developer` for the system prompt and decides whether\n * to emit OpenAI's `strict` flag on tool defs based on the model id; both\n * can be overridden through `OpenAIProviderConfig.system_role` and\n * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.\n */\nexport class OpenAIProvider implements ModelProvider {\n readonly #sdk: OpenAI;\n readonly #config: OpenAIProviderConfig;\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new OpenAI provider instance.\n *\n * @param sdk - The initialized OpenAI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers.\n */\n constructor(\n sdk: OpenAI,\n config: OpenAIProviderConfig,\n context_transformers: ProviderContextTransformer[] = [],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, system_role, strict_tools, ...api_extras } = this.#config;\n const emit_strict = resolve_strict_tools(model, strict_tools);\n const params: OpenAI.ChatCompletionCreateParamsStreaming = {\n ...api_extras,\n model,\n stream: true,\n max_tokens,\n ...(request.tools.length > 0\n ? {\n tool_choice: \"auto\",\n tools: request.tools.map((t) => to_openai_tool(t, emit_strict)),\n }\n : {}),\n messages: [\n ...get_system_context(model, request.system, system_role),\n ...request.messages.flatMap((m) => to_openai_messages(m)),\n ],\n stream_options: {\n include_usage: true,\n },\n };\n\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const stream = await this.#sdk.chat.completions.create(params);\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(stream, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new OpenAIProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: OpenAI.Chat.Completions.ChatCompletionChunk | undefined;\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { choices: choices_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n choices: response?.choices ?? [],\n };\n\n for (const choice_chunk of choices_chunk) {\n if (!response.choices[choice_chunk.index]) {\n response.choices[choice_chunk.index] = choice_chunk;\n const message = from_openai_completion(response_chunk, choice_chunk);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage: {} });\n }\n receiver.start_message({ message, usage: {} });\n continue;\n }\n\n const { delta: delta_chunk, ...rest } = choice_chunk;\n const choice = (response.choices[choice_chunk.index] = {\n ...response.choices[choice_chunk.index],\n ...rest,\n delta: {\n ...response.choices[choice_chunk.index]?.delta,\n },\n });\n\n if (delta_chunk.role) {\n choice.delta.role = delta_chunk.role;\n }\n if (delta_chunk.refusal) {\n if (!choice.delta.refusal) {\n choice.delta.refusal = \"\";\n }\n choice.delta.refusal += delta_chunk.refusal;\n }\n const reasoning_delta = get_openai_reasoning_delta(delta_chunk);\n if (reasoning_delta) {\n const choice_delta = choice.delta as OpenAIReasoningDelta;\n const existing = choice_delta[reasoning_delta.key];\n if (!existing) {\n choice_delta[reasoning_delta.key] = reasoning_delta.thought;\n receiver.start_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice_delta[reasoning_delta.key] = existing + reasoning_delta.thought;\n receiver.update_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.content) {\n if (!choice.delta.content) {\n choice.delta.content = delta_chunk.content;\n receiver.start_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice.delta.content += delta_chunk.content;\n receiver.update_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls) {\n choice.delta.tool_calls = [];\n }\n for (const tool_call_chunk of delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls[tool_call_chunk.index]) {\n choice.delta.tool_calls[tool_call_chunk.index] = tool_call_chunk;\n receiver.start_content({\n content: from_openai_tool_call(tool_call_chunk),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n const tool_call = choice.delta.tool_calls[tool_call_chunk.index];\n\n if (tool_call_chunk.id) {\n tool_call.id = tool_call_chunk.id;\n }\n if (tool_call_chunk.type) {\n tool_call.type = tool_call_chunk.type;\n }\n if (tool_call_chunk.function) {\n if (!tool_call.function) {\n tool_call.function = tool_call_chunk.function;\n } else {\n if (tool_call_chunk.function.name) {\n tool_call.function.name = tool_call_chunk.function.name;\n }\n if (tool_call_chunk.function.arguments) {\n if (!tool_call.function.arguments) {\n tool_call.function.arguments = \"\";\n }\n tool_call.function.arguments += tool_call_chunk.function.arguments;\n }\n }\n }\n receiver.update_content({\n content: from_openai_tool_call(tool_call),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n }\n }\n }\n if (!response || !response.choices?.[0]) {\n throw new Error(\"no data\");\n }\n receiver.response_raw({ ...response });\n\n const message = from_openai_completion(response, response.choices[0]);\n const usage = response?.usage ? from_openai_usage(response.usage) : {};\n for (const content of message.content) {\n receiver.complete_content({ content, message, usage });\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction get_system_context(\n model: string,\n system: string | undefined,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): OpenAI.ChatCompletionMessageParam[] {\n if (!system) {\n return [];\n }\n const role = resolve_system_role(model, system_role);\n if (role === \"developer\") {\n return [\n {\n role: \"developer\",\n content: system,\n } as OpenAI.ChatCompletionDeveloperMessageParam,\n ];\n }\n return [\n {\n role: \"system\",\n content: system,\n } as OpenAI.ChatCompletionSystemMessageParam,\n ];\n}\n\nfunction resolve_system_role(\n model: string,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): \"system\" | \"developer\" {\n if (system_role === \"system\" || system_role === \"developer\") {\n return system_role;\n }\n if (model.startsWith(\"gpt\")) {\n return \"system\";\n }\n if (is_openai_reasoning_model(model)) {\n return \"developer\";\n }\n return \"system\";\n}\n\nfunction resolve_strict_tools(\n model: string,\n strict_tools: OpenAIProviderConfig[\"strict_tools\"] = \"auto\",\n): boolean {\n if (strict_tools === \"never\") {\n return false;\n }\n return model.startsWith(\"gpt\") || is_openai_reasoning_model(model);\n}\n\n// Best-effort match for OpenAI's o-series reasoning model ids (o1, o3,\n// o4-mini, etc.). The leading non-zero digit and end-of-string-or-hyphen\n// anchor narrow the pattern to what OpenAI actually ships. Two known\n// failure modes: a non-OpenAI vendor whose model id happens to follow the\n// same shape (e.g. `o2-fast`) gets matched as o-series, and a relay-style\n// id like `openai/o3` is NOT matched because the regex anchors at start\n// of string. Operators in either situation should set `system_role` and\n// `strict_tools` explicitly — the heuristic is a default, not a constraint.\nfunction is_openai_reasoning_model(model: string): boolean {\n return /^o[1-9]\\d*(-|$)/.test(model);\n}\n\nfunction to_openai_tool(tool: ToolDefinition, strict: boolean): OpenAI.Chat.ChatCompletionTool {\n function map_parameter_type(\n parameter: Prettify<ParameterType & { description?: string }>,\n ): OpenAI.FunctionParameters {\n switch (parameter.type) {\n case \"object\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n properties: Object.fromEntries(\n Object.entries(parameter.properties).map(([k, v]) => [k, map_parameter_type(v)]),\n ),\n additionalProperties: false,\n required: Object.entries(parameter.properties).map(([k]) => k),\n };\n case \"array\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n items: map_parameter_type(parameter.items),\n };\n default:\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description:\n parameter.default !== undefined\n ? parameter.description\n ? `${parameter.description} (default: ${parameter.default})`\n : `default: ${parameter.default}`\n : parameter.description,\n enum: \"enum\" in parameter ? parameter.enum : undefined,\n };\n }\n }\n return {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: map_parameter_type({\n type: \"object\",\n required: true,\n properties: Object.fromEntries(\n tool.parameters.map(({ name, ...parameter }) => [name, parameter]),\n ),\n }),\n ...(strict ? { strict: true } : {}),\n },\n };\n}\n\nfunction from_openai_completion(\n completion: OpenAI.Chat.Completions.ChatCompletionChunk,\n choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice,\n) {\n let contents: Content[] = [];\n const thinking = from_openai_thinking(choice.delta);\n if (thinking) {\n contents = [...contents, thinking];\n }\n const delta_record = choice.delta as Record<string, unknown>;\n for (const key of Object.keys(choice.delta)) {\n if (key === \"role\") {\n continue;\n }\n if (is_openai_reasoning_delta_key(key)) {\n continue;\n }\n if (key === \"content\") {\n if (choice.delta.content) {\n contents = [...contents, from_openai_content(choice.delta)];\n }\n continue;\n }\n if (key === \"refusal\") {\n if (choice.delta.refusal) {\n contents = [...contents, from_openai_refusal(choice.delta)];\n }\n continue;\n }\n if (key === \"tool_calls\") {\n if (choice.delta.tool_calls) {\n contents = [...contents, ...choice.delta.tool_calls.map((t) => from_openai_tool_call(t))];\n }\n continue;\n }\n if (delta_record[key] !== undefined && delta_record[key] !== null) {\n const data = delta_record[key];\n contents = [\n ...contents,\n {\n type: \"raw\",\n model_kind: \"openai\",\n data: JSON.stringify({ [key]: data }),\n },\n ];\n }\n }\n return {\n id: completion.id,\n timestamp: completion.created,\n role: map_role(choice),\n content: contents,\n } as AssistantMessage;\n}\n\nfunction get_openai_reasoning_delta(delta: OpenAICompletionDelta) {\n const record = delta as Partial<Record<OpenAIReasoningDeltaKey, unknown>>;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n const thought = record[key];\n if (typeof thought === \"string\" && thought.length > 0) {\n return { key, thought };\n }\n }\n return undefined;\n}\n\nfunction from_openai_thinking(content: OpenAICompletionDelta) {\n const reasoning = get_openai_reasoning_delta(content);\n if (!reasoning) {\n return undefined;\n }\n const extended = get_openai_delta_extended(content);\n return {\n type: \"thinking\",\n thought: reasoning.thought,\n extended: {\n ...extended,\n openai_reasoning_field: reasoning.key,\n },\n } as Content;\n}\n\nfunction is_openai_reasoning_delta_key(key: string): key is OpenAIReasoningDeltaKey {\n return OPENAI_REASONING_DELTA_KEYS.includes(key as OpenAIReasoningDeltaKey);\n}\n\nfunction from_openai_refusal(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.refusal,\n extended: {\n ...get_openai_delta_extended(content),\n openai_refusal: true,\n },\n } as Content;\n}\n\nfunction from_openai_content(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.content,\n extended: get_openai_delta_extended(content),\n } as Content;\n}\n\nfunction get_openai_delta_extended(content: OpenAICompletionDelta) {\n const extended = { ...(content as Record<string, unknown>) };\n delete extended.content;\n delete extended.tool_calls;\n delete extended.function_call;\n delete extended.refusal;\n delete extended.role;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n delete extended[key];\n }\n return extended;\n}\n\nfunction from_openai_tool_call(\n tool_call: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall,\n) {\n const { id: tool_request_id, function: fn, type: _, index: __, ...extended } = tool_call;\n let params: unknown;\n try {\n params = JSON.parse(fn?.arguments ?? \"{}\");\n } catch {\n params = fn?.arguments;\n }\n return {\n tool_request_id,\n type: \"tool\",\n tool: fn?.name,\n params,\n extended,\n } as ToolContent;\n}\n\nfunction to_openai_messages(message: Message) {\n if (message.role === \"assistant\") {\n return [to_openai_assistant_message(message)];\n }\n // Partition content so tool_result blocks come before non-tool_result blocks.\n // OpenAI requires all tool-role messages immediately after the assistant message\n // containing the corresponding tool_calls; interleaving user messages between\n // tool messages causes a validation error.\n const tool_result_content = message.content.filter((c) => c.type === \"tool_result\");\n const other_content = message.content.filter((c) => c.type !== \"tool_result\");\n const ordered_content = [...tool_result_content, ...other_content];\n\n const results: OpenAI.ChatCompletionMessageParam[] = [];\n let result: OpenAI.ChatCompletionMessageParam | undefined;\n for (const content of ordered_content) {\n if (content.type === \"text\") {\n if (!result) {\n result = {\n role: \"user\",\n content: content.text,\n };\n } else if (result.role === \"tool\") {\n results.push(result);\n result = {\n role: \"user\",\n content: content.text,\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = [\n {\n type: \"text\",\n text: content.text,\n },\n ];\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n } else if (content.type === \"tool_result\") {\n if (!result) {\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else if (result.role !== \"tool\" || result.tool_call_id !== content.tool_request_id) {\n results.push(result);\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n result.content.push({\n type: \"text\",\n text: JSON.stringify(content.result),\n });\n }\n } else if (content.type === \"raw\") {\n result = {\n ...(result ?? {}),\n ...JSON.parse(content.data),\n };\n }\n }\n if (result) {\n results.push(result);\n }\n return results;\n}\n\nfunction to_openai_assistant_message(message: AssistantMessage) {\n let result: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n };\n for (const content of message.content) {\n switch (content.type) {\n case \"text\":\n if (content.extended && content.extended.openai_refusal === true) {\n result.refusal = content.text;\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.text;\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n break;\n case \"tool\":\n if (!result.tool_calls) {\n result.tool_calls = [];\n }\n result.tool_calls.push({\n id: content.tool_request_id,\n type: \"function\",\n function: {\n name: content.tool,\n arguments: JSON.stringify(content.params),\n },\n });\n break;\n case \"raw\":\n if (content.model_kind !== \"openai\") {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.data;\n } else {\n result.content.push({\n type: \"text\",\n text: content.data,\n });\n }\n break;\n }\n result = {\n ...result,\n ...JSON.parse(content.data),\n };\n break;\n case \"thinking\":\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.thought;\n } else {\n result.content.push({\n type: \"text\",\n text: content.thought,\n });\n }\n break;\n default:\n throw new Error(\"unexpected content type\");\n }\n }\n return result;\n}\n\nfunction from_openai_usage(usage: OpenAI.CompletionUsage | null | undefined) {\n return {\n input_tokens: usage?.prompt_tokens,\n output_tokens: usage?.completion_tokens,\n } as Usage;\n}\n\nfunction map_stop_reason(\n completion: OpenAI.ChatCompletionChunk,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const choice of completion.choices) {\n switch (choice.finish_reason) {\n case \"content_filter\":\n return {\n stop_reason: \"error\",\n stop_details: choice.finish_reason,\n };\n case \"function_call\":\n return {\n stop_reason: \"tool_use\",\n };\n case \"length\":\n return {\n stop_reason: \"max_tokens\",\n };\n case \"stop\":\n return {\n stop_reason: \"end_turn\",\n };\n case \"tool_calls\":\n return {\n stop_reason: \"tool_use\",\n };\n default:\n return {\n stop_reason: \"other\",\n stop_details: `${choice.finish_reason}`,\n };\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n\nfunction map_role(choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice) {\n switch (choice.delta.role) {\n case \"user\":\n case \"developer\":\n case \"system\":\n return \"user\";\n case \"assistant\":\n case \"tool\":\n return \"assistant\";\n default:\n throw new Error(\"invalid role\");\n }\n}\n"],"mappings":"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","names":["message","rest"]}
1
+ {"version":3,"sources":["../src/openai-provider.ts"],"sourcesContent":["import { OpenAI } from \"openai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolContent,\n ToolDefinition,\n Usage,\n} from \"@simulacra-ai/core\";\n\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nconst OPENAI_REASONING_DELTA_KEYS = [\"reasoning\", \"reasoning_content\", \"thinking\"] as const;\n\ntype OpenAIReasoningDeltaKey = (typeof OPENAI_REASONING_DELTA_KEYS)[number];\ntype OpenAICompletionDelta = OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta;\ntype OpenAIReasoningDelta = OpenAICompletionDelta &\n Partial<Record<OpenAIReasoningDeltaKey, string>>;\n\n/**\n * Configuration options for the OpenAI provider.\n */\nexport interface OpenAIProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gpt-4\", \"o1-preview\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /**\n * Which role to use for the system prompt.\n *\n * The OpenAI Chat Completions spec allows `system` (legacy / most providers)\n * and `developer` (introduced for o-series reasoning models). Most\n * OpenAI-compatible endpoints (DeepSeek, OpenRouter relays, Anthropic-via-\n * compat, self-hosted gateways, etc.) only accept `system` and reject\n * `developer` with a 400.\n *\n * - `\"auto\"` (default): use the built-in heuristic — `gpt*` → `\"system\"`,\n * o-series (`o1`, `o3`, `o4`, ...) → `\"developer\"`, anything else →\n * `\"system\"` (the broadly-compatible default).\n * - `\"system\"` / `\"developer\"`: force the role regardless of model id.\n *\n * The heuristic matches on the bare model id and does not understand\n * relay-style prefixes (`openai/o3`, `anthropic/claude-3-5-sonnet`,\n * etc.) — set this explicitly when routing OpenAI models through a\n * relay that uses `vendor/model` ids.\n */\n system_role?: \"auto\" | \"system\" | \"developer\";\n /**\n * Whether to emit OpenAI's strict structured-output flag on tool\n * definitions (`function.strict: true`).\n *\n * `strict` is an OpenAI-specific extension that constrains tool arguments\n * to the supplied JSON Schema. Most non-OpenAI endpoints either ignore the\n * field or reject it.\n *\n * - `\"auto\"` (default): emit `strict: true` when the model id matches the\n * built-in OpenAI heuristic — `gpt*` or o-series (`o1`, `o3`, `o4`, ...).\n * Any other model id (deepseek, etc.) gets tool defs without `strict`.\n * The heuristic matches on the bare model id; relay-style prefixes\n * (`openai/gpt-4o`) are NOT recognized — set this explicitly when\n * routing OpenAI models through a relay.\n * - `\"never\"`: never emit `strict`.\n */\n strict_tools?: \"auto\" | \"never\";\n /**\n * Treatment of prior `thinking` content blocks when serializing assistant\n * messages back up the wire.\n *\n * - `\"inline\"` (default): appended as text content. openai tolerates it.\n * - `\"field\"`: emitted as a `reasoning_content` field. required by\n * deepseek v4 thinking-mode.\n * - `\"drop\"`: omitted entirely.\n */\n upstream_reasoning?: \"inline\" | \"field\" | \"drop\";\n}\n\n/**\n * Model provider implementation for OpenAI's chat completion models.\n *\n * This provider wraps the OpenAI SDK to provide streaming completions with\n * support for tool use and function calling. It handles message formatting,\n * content streaming, and usage tracking according to the ModelProvider\n * interface.\n *\n * Works against OpenAI directly as well as OpenAI-compatible endpoints\n * (DeepSeek, OpenRouter, self-hosted gateways, etc.). The default behaviour\n * picks `system` vs. `developer` for the system prompt and decides whether\n * to emit OpenAI's `strict` flag on tool defs based on the model id; both\n * can be overridden through `OpenAIProviderConfig.system_role` and\n * `OpenAIProviderConfig.strict_tools` for endpoints whose behaviour differs.\n * `OpenAIProviderConfig.upstream_reasoning` controls how prior thinking\n * content is round-tripped on subsequent calls for providers (deepseek v4)\n * that require it in a specific shape.\n */\nexport class OpenAIProvider implements ModelProvider {\n readonly #sdk: OpenAI;\n readonly #config: OpenAIProviderConfig;\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new OpenAI provider instance.\n *\n * @param sdk - The initialized OpenAI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers.\n */\n constructor(\n sdk: OpenAI,\n config: OpenAIProviderConfig,\n context_transformers: ProviderContextTransformer[] = [],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, system_role, strict_tools, upstream_reasoning, ...api_extras } =\n this.#config;\n const emit_strict = resolve_strict_tools(model, strict_tools);\n const reasoning_mode = upstream_reasoning ?? \"inline\";\n const params: OpenAI.ChatCompletionCreateParamsStreaming = {\n ...api_extras,\n model,\n stream: true,\n max_tokens,\n ...(request.tools.length > 0\n ? {\n tool_choice: \"auto\",\n tools: request.tools.map((t) => to_openai_tool(t, emit_strict)),\n }\n : {}),\n messages: [\n ...get_system_context(model, request.system, system_role),\n ...request.messages.flatMap((m) => to_openai_messages(m, reasoning_mode)),\n ],\n stream_options: {\n include_usage: true,\n },\n };\n\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const stream = await this.#sdk.chat.completions.create(params);\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(stream, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new OpenAIProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: OpenAI.Chat.Completions.ChatCompletionChunk | undefined;\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { choices: choices_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n choices: response?.choices ?? [],\n };\n\n for (const choice_chunk of choices_chunk) {\n if (!response.choices[choice_chunk.index]) {\n response.choices[choice_chunk.index] = choice_chunk;\n const message = from_openai_completion(response_chunk, choice_chunk);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage: {} });\n }\n receiver.start_message({ message, usage: {} });\n continue;\n }\n\n const { delta: delta_chunk, ...rest } = choice_chunk;\n const choice = (response.choices[choice_chunk.index] = {\n ...response.choices[choice_chunk.index],\n ...rest,\n delta: {\n ...response.choices[choice_chunk.index]?.delta,\n },\n });\n\n if (delta_chunk.role) {\n choice.delta.role = delta_chunk.role;\n }\n if (delta_chunk.refusal) {\n if (!choice.delta.refusal) {\n choice.delta.refusal = \"\";\n }\n choice.delta.refusal += delta_chunk.refusal;\n }\n const reasoning_delta = get_openai_reasoning_delta(delta_chunk);\n if (reasoning_delta) {\n const choice_delta = choice.delta as OpenAIReasoningDelta;\n const existing = choice_delta[reasoning_delta.key];\n if (!existing) {\n choice_delta[reasoning_delta.key] = reasoning_delta.thought;\n receiver.start_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice_delta[reasoning_delta.key] = existing + reasoning_delta.thought;\n receiver.update_content({\n content: from_openai_thinking(choice_delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.content) {\n if (!choice.delta.content) {\n choice.delta.content = delta_chunk.content;\n receiver.start_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n choice.delta.content += delta_chunk.content;\n receiver.update_content({\n content: from_openai_content(choice.delta) as AssistantContent,\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n if (delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls) {\n choice.delta.tool_calls = [];\n }\n for (const tool_call_chunk of delta_chunk.tool_calls) {\n if (!choice.delta.tool_calls[tool_call_chunk.index]) {\n choice.delta.tool_calls[tool_call_chunk.index] = tool_call_chunk;\n receiver.start_content({\n content: from_openai_tool_call(tool_call_chunk),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n } else {\n const tool_call = choice.delta.tool_calls[tool_call_chunk.index];\n\n if (tool_call_chunk.id) {\n tool_call.id = tool_call_chunk.id;\n }\n if (tool_call_chunk.type) {\n tool_call.type = tool_call_chunk.type;\n }\n if (tool_call_chunk.function) {\n if (!tool_call.function) {\n tool_call.function = tool_call_chunk.function;\n } else {\n if (tool_call_chunk.function.name) {\n tool_call.function.name = tool_call_chunk.function.name;\n }\n if (tool_call_chunk.function.arguments) {\n if (!tool_call.function.arguments) {\n tool_call.function.arguments = \"\";\n }\n tool_call.function.arguments += tool_call_chunk.function.arguments;\n }\n }\n }\n receiver.update_content({\n content: from_openai_tool_call(tool_call),\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n receiver.update_message({\n message: from_openai_completion(response_chunk, choice),\n usage: response?.usage ? from_openai_usage(response.usage) : {},\n });\n }\n }\n }\n }\n }\n if (!response || !response.choices?.[0]) {\n throw new Error(\"no data\");\n }\n receiver.response_raw({ ...response });\n\n const message = from_openai_completion(response, response.choices[0]);\n const usage = response?.usage ? from_openai_usage(response.usage) : {};\n for (const content of message.content) {\n receiver.complete_content({ content, message, usage });\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction get_system_context(\n model: string,\n system: string | undefined,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): OpenAI.ChatCompletionMessageParam[] {\n if (!system) {\n return [];\n }\n const role = resolve_system_role(model, system_role);\n if (role === \"developer\") {\n return [\n {\n role: \"developer\",\n content: system,\n } as OpenAI.ChatCompletionDeveloperMessageParam,\n ];\n }\n return [\n {\n role: \"system\",\n content: system,\n } as OpenAI.ChatCompletionSystemMessageParam,\n ];\n}\n\nfunction resolve_system_role(\n model: string,\n system_role: OpenAIProviderConfig[\"system_role\"] = \"auto\",\n): \"system\" | \"developer\" {\n if (system_role === \"system\" || system_role === \"developer\") {\n return system_role;\n }\n if (model.startsWith(\"gpt\")) {\n return \"system\";\n }\n if (is_openai_reasoning_model(model)) {\n return \"developer\";\n }\n return \"system\";\n}\n\nfunction resolve_strict_tools(\n model: string,\n strict_tools: OpenAIProviderConfig[\"strict_tools\"] = \"auto\",\n): boolean {\n if (strict_tools === \"never\") {\n return false;\n }\n return model.startsWith(\"gpt\") || is_openai_reasoning_model(model);\n}\n\n// Best-effort match for OpenAI's o-series reasoning model ids (o1, o3,\n// o4-mini, etc.). The leading non-zero digit and end-of-string-or-hyphen\n// anchor narrow the pattern to what OpenAI actually ships. Two known\n// failure modes: a non-OpenAI vendor whose model id happens to follow the\n// same shape (e.g. `o2-fast`) gets matched as o-series, and a relay-style\n// id like `openai/o3` is NOT matched because the regex anchors at start\n// of string. Operators in either situation should set `system_role` and\n// `strict_tools` explicitly — the heuristic is a default, not a constraint.\nfunction is_openai_reasoning_model(model: string): boolean {\n return /^o[1-9]\\d*(-|$)/.test(model);\n}\n\nfunction to_openai_tool(tool: ToolDefinition, strict: boolean): OpenAI.Chat.ChatCompletionTool {\n function map_parameter_type(\n parameter: Prettify<ParameterType & { description?: string }>,\n ): OpenAI.FunctionParameters {\n switch (parameter.type) {\n case \"object\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n properties: Object.fromEntries(\n Object.entries(parameter.properties).map(([k, v]) => [k, map_parameter_type(v)]),\n ),\n additionalProperties: false,\n required: Object.entries(parameter.properties).map(([k]) => k),\n };\n case \"array\":\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description: parameter.description,\n items: map_parameter_type(parameter.items),\n };\n default:\n return {\n type: parameter.required ? parameter.type : [parameter.type, \"null\"],\n description:\n parameter.default !== undefined\n ? parameter.description\n ? `${parameter.description} (default: ${parameter.default})`\n : `default: ${parameter.default}`\n : parameter.description,\n enum: \"enum\" in parameter ? parameter.enum : undefined,\n };\n }\n }\n return {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: map_parameter_type({\n type: \"object\",\n required: true,\n properties: Object.fromEntries(\n tool.parameters.map(({ name, ...parameter }) => [name, parameter]),\n ),\n }),\n ...(strict ? { strict: true } : {}),\n },\n };\n}\n\nfunction from_openai_completion(\n completion: OpenAI.Chat.Completions.ChatCompletionChunk,\n choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice,\n) {\n let contents: Content[] = [];\n const thinking = from_openai_thinking(choice.delta);\n if (thinking) {\n contents = [...contents, thinking];\n }\n const delta_record = choice.delta as Record<string, unknown>;\n for (const key of Object.keys(choice.delta)) {\n if (key === \"role\") {\n continue;\n }\n if (is_openai_reasoning_delta_key(key)) {\n continue;\n }\n if (key === \"content\") {\n if (choice.delta.content) {\n contents = [...contents, from_openai_content(choice.delta)];\n }\n continue;\n }\n if (key === \"refusal\") {\n if (choice.delta.refusal) {\n contents = [...contents, from_openai_refusal(choice.delta)];\n }\n continue;\n }\n if (key === \"tool_calls\") {\n if (choice.delta.tool_calls) {\n contents = [...contents, ...choice.delta.tool_calls.map((t) => from_openai_tool_call(t))];\n }\n continue;\n }\n if (delta_record[key] !== undefined && delta_record[key] !== null) {\n const data = delta_record[key];\n contents = [\n ...contents,\n {\n type: \"raw\",\n model_kind: \"openai\",\n data: JSON.stringify({ [key]: data }),\n },\n ];\n }\n }\n return {\n id: completion.id,\n timestamp: completion.created,\n role: map_role(choice),\n content: contents,\n } as AssistantMessage;\n}\n\nfunction get_openai_reasoning_delta(delta: OpenAICompletionDelta) {\n const record = delta as Partial<Record<OpenAIReasoningDeltaKey, unknown>>;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n const thought = record[key];\n if (typeof thought === \"string\" && thought.length > 0) {\n return { key, thought };\n }\n }\n return undefined;\n}\n\nfunction from_openai_thinking(content: OpenAICompletionDelta) {\n const reasoning = get_openai_reasoning_delta(content);\n if (!reasoning) {\n return undefined;\n }\n const extended = get_openai_delta_extended(content);\n return {\n type: \"thinking\",\n thought: reasoning.thought,\n extended: {\n ...extended,\n openai_reasoning_field: reasoning.key,\n },\n } as Content;\n}\n\nfunction is_openai_reasoning_delta_key(key: string): key is OpenAIReasoningDeltaKey {\n return OPENAI_REASONING_DELTA_KEYS.includes(key as OpenAIReasoningDeltaKey);\n}\n\nfunction from_openai_refusal(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.refusal,\n extended: {\n ...get_openai_delta_extended(content),\n openai_refusal: true,\n },\n } as Content;\n}\n\nfunction from_openai_content(content: OpenAICompletionDelta) {\n return {\n type: \"text\",\n text: content.content,\n extended: get_openai_delta_extended(content),\n } as Content;\n}\n\nfunction get_openai_delta_extended(content: OpenAICompletionDelta) {\n const extended = { ...(content as Record<string, unknown>) };\n delete extended.content;\n delete extended.tool_calls;\n delete extended.function_call;\n delete extended.refusal;\n delete extended.role;\n for (const key of OPENAI_REASONING_DELTA_KEYS) {\n delete extended[key];\n }\n return extended;\n}\n\nfunction from_openai_tool_call(\n tool_call: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall,\n) {\n const { id: tool_request_id, function: fn, type: _, index: __, ...extended } = tool_call;\n let params: unknown;\n try {\n params = JSON.parse(fn?.arguments ?? \"{}\");\n } catch {\n params = fn?.arguments;\n }\n return {\n tool_request_id,\n type: \"tool\",\n tool: fn?.name,\n params,\n extended,\n } as ToolContent;\n}\n\nfunction to_openai_messages(\n message: Message,\n upstream_reasoning: NonNullable<OpenAIProviderConfig[\"upstream_reasoning\"]>,\n) {\n if (message.role === \"assistant\") {\n return [to_openai_assistant_message(message, upstream_reasoning)];\n }\n // Partition content so tool_result blocks come before non-tool_result blocks.\n // OpenAI requires all tool-role messages immediately after the assistant message\n // containing the corresponding tool_calls; interleaving user messages between\n // tool messages causes a validation error.\n const tool_result_content = message.content.filter((c) => c.type === \"tool_result\");\n const other_content = message.content.filter((c) => c.type !== \"tool_result\");\n const ordered_content = [...tool_result_content, ...other_content];\n\n const results: OpenAI.ChatCompletionMessageParam[] = [];\n let result: OpenAI.ChatCompletionMessageParam | undefined;\n for (const content of ordered_content) {\n if (content.type === \"text\") {\n if (!result) {\n result = {\n role: \"user\",\n content: content.text,\n };\n } else if (result.role === \"tool\") {\n results.push(result);\n result = {\n role: \"user\",\n content: content.text,\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = [\n {\n type: \"text\",\n text: content.text,\n },\n ];\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n } else if (content.type === \"tool_result\") {\n if (!result) {\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else if (result.role !== \"tool\" || result.tool_call_id !== content.tool_request_id) {\n results.push(result);\n result = {\n role: \"tool\",\n tool_call_id: content.tool_request_id,\n content: JSON.stringify(content.result),\n };\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n result.content.push({\n type: \"text\",\n text: JSON.stringify(content.result),\n });\n }\n } else if (content.type === \"raw\") {\n result = {\n ...(result ?? {}),\n ...JSON.parse(content.data),\n };\n }\n }\n if (result) {\n results.push(result);\n }\n return results;\n}\n\nfunction to_openai_assistant_message(\n message: AssistantMessage,\n upstream_reasoning: NonNullable<OpenAIProviderConfig[\"upstream_reasoning\"]>,\n) {\n let result: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n };\n for (const content of message.content) {\n switch (content.type) {\n case \"text\":\n if (content.extended && content.extended.openai_refusal === true) {\n result.refusal = content.text;\n } else {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.text;\n } else {\n result.content.push({\n type: \"text\",\n text: content.text,\n });\n }\n }\n break;\n case \"tool\":\n if (!result.tool_calls) {\n result.tool_calls = [];\n }\n result.tool_calls.push({\n id: content.tool_request_id,\n type: \"function\",\n function: {\n name: content.tool,\n arguments: JSON.stringify(content.params),\n },\n });\n break;\n case \"raw\":\n if (content.model_kind !== \"openai\") {\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.data;\n } else {\n result.content.push({\n type: \"text\",\n text: content.data,\n });\n }\n break;\n }\n result = {\n ...result,\n ...JSON.parse(content.data),\n };\n break;\n case \"thinking\":\n if (upstream_reasoning === \"drop\") {\n break;\n }\n if (upstream_reasoning === \"field\") {\n const widened = result as OpenAI.ChatCompletionAssistantMessageParam & {\n reasoning_content?: string;\n };\n widened.reasoning_content =\n widened.reasoning_content !== undefined\n ? widened.reasoning_content + \"\\n\" + content.thought\n : content.thought;\n break;\n }\n if (typeof result.content === \"string\") {\n result.content = [\n {\n type: \"text\",\n text: result.content,\n },\n ];\n }\n if (!result.content) {\n result.content = content.thought;\n } else {\n result.content.push({\n type: \"text\",\n text: content.thought,\n });\n }\n break;\n default:\n throw new Error(\"unexpected content type\");\n }\n }\n return result;\n}\n\nfunction from_openai_usage(usage: OpenAI.CompletionUsage | null | undefined) {\n return {\n input_tokens: usage?.prompt_tokens,\n output_tokens: usage?.completion_tokens,\n } as Usage;\n}\n\nfunction map_stop_reason(\n completion: OpenAI.ChatCompletionChunk,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const choice of completion.choices) {\n switch (choice.finish_reason) {\n case \"content_filter\":\n return {\n stop_reason: \"error\",\n stop_details: choice.finish_reason,\n };\n case \"function_call\":\n return {\n stop_reason: \"tool_use\",\n };\n case \"length\":\n return {\n stop_reason: \"max_tokens\",\n };\n case \"stop\":\n return {\n stop_reason: \"end_turn\",\n };\n case \"tool_calls\":\n return {\n stop_reason: \"tool_use\",\n };\n default:\n return {\n stop_reason: \"other\",\n stop_details: `${choice.finish_reason}`,\n };\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n\nfunction map_role(choice: OpenAI.Chat.Completions.ChatCompletionChunk.Choice) {\n switch (choice.delta.role) {\n case \"user\":\n case \"developer\":\n case \"system\":\n return \"user\";\n case \"assistant\":\n case \"tool\":\n return \"assistant\";\n default:\n throw new Error(\"invalid role\");\n }\n}\n"],"mappings":"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","names":["message","rest"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simulacra-ai/openai",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "OpenAI provider for the Simulacra conversation engine",
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "test:watch": "vitest"
26
26
  },
27
27
  "peerDependencies": {
28
- "@simulacra-ai/core": "0.0.12",
28
+ "@simulacra-ai/core": "0.0.13",
29
29
  "openai": ">=4.0.0 <7.0.0"
30
30
  },
31
31
  "devDependencies": {