@deepstrike/sdk 0.2.52 → 0.2.60

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.
Files changed (148) hide show
  1. package/README.md +28 -28
  2. package/dist/agent-ir.d.ts +103 -0
  3. package/dist/agent-ir.js +134 -0
  4. package/dist/agent.d.ts +67 -0
  5. package/dist/agent.js +36 -0
  6. package/dist/collaboration/harness.js +1 -1
  7. package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
  8. package/dist/collaboration/modes/creator-verifier.js +4 -6
  9. package/dist/collaboration/pool.d.ts +8 -20
  10. package/dist/collaboration/pool.js +27 -97
  11. package/dist/compat/anthropic/mcp.d.ts +15 -0
  12. package/dist/compat/anthropic/mcp.js +10 -0
  13. package/dist/compat/openai/agent.d.ts +34 -0
  14. package/dist/compat/openai/agent.js +24 -0
  15. package/dist/governance.d.ts +1 -17
  16. package/dist/governance.js +1 -34
  17. package/dist/guardrail.d.ts +6 -0
  18. package/dist/guardrail.js +1 -0
  19. package/dist/handoff-target.d.ts +12 -0
  20. package/dist/handoff-target.js +1 -0
  21. package/dist/harness/manifest.js +0 -4
  22. package/dist/index.d.ts +19 -7
  23. package/dist/index.js +8 -5
  24. package/dist/kernel.d.ts +2 -20
  25. package/dist/knowledge/public.d.ts +29 -0
  26. package/dist/knowledge/public.js +1 -0
  27. package/dist/mcp-server.d.ts +28 -0
  28. package/dist/mcp-server.js +1 -0
  29. package/dist/memory/agent.d.ts +2 -2
  30. package/dist/memory/agent.js +2 -2
  31. package/dist/memory/durable.d.ts +16 -0
  32. package/dist/memory/durable.js +46 -0
  33. package/dist/memory/in-memory-store.d.ts +9 -7
  34. package/dist/memory/in-memory-store.js +8 -2
  35. package/dist/memory/protocols.d.ts +22 -4
  36. package/dist/memory/public.d.ts +4 -3
  37. package/dist/memory/public.js +3 -2
  38. package/dist/providers/anthropic-adapter.d.ts +47 -0
  39. package/dist/providers/anthropic-adapter.js +444 -0
  40. package/dist/providers/anthropic-compatible.d.ts +2 -3
  41. package/dist/providers/anthropic-compatible.js +8 -5
  42. package/dist/providers/anthropic.d.ts +19 -23
  43. package/dist/providers/anthropic.js +169 -395
  44. package/dist/providers/base.js +43 -3
  45. package/dist/providers/capability-router.d.ts +29 -0
  46. package/dist/providers/capability-router.js +43 -0
  47. package/dist/providers/catalog.d.ts +16 -4
  48. package/dist/providers/catalog.js +112 -21
  49. package/dist/providers/content-normalization.d.ts +57 -0
  50. package/dist/providers/content-normalization.js +238 -0
  51. package/dist/providers/content-policy.d.ts +16 -0
  52. package/dist/providers/content-policy.js +39 -0
  53. package/dist/providers/credentials.d.ts +83 -0
  54. package/dist/providers/credentials.js +190 -0
  55. package/dist/providers/endpoints.d.ts +137 -0
  56. package/dist/providers/endpoints.js +128 -0
  57. package/dist/providers/factories.js +9 -3
  58. package/dist/providers/gemini-adapter.d.ts +33 -0
  59. package/dist/providers/gemini-adapter.js +272 -0
  60. package/dist/providers/gemini.d.ts +16 -3
  61. package/dist/providers/gemini.js +97 -195
  62. package/dist/providers/model-catalog.d.ts +37 -0
  63. package/dist/providers/model-catalog.js +62 -0
  64. package/dist/providers/model-registry.d.ts +98 -0
  65. package/dist/providers/model-registry.js +315 -0
  66. package/dist/providers/ollama-adapter.d.ts +65 -0
  67. package/dist/providers/ollama-adapter.js +188 -0
  68. package/dist/providers/ollama.d.ts +9 -4
  69. package/dist/providers/ollama.js +96 -109
  70. package/dist/providers/openai-chat-dialects.d.ts +154 -0
  71. package/dist/providers/openai-chat-dialects.js +179 -0
  72. package/dist/providers/openai-chat.d.ts +46 -18
  73. package/dist/providers/openai-chat.js +418 -51
  74. package/dist/providers/openai-responses-adapter.d.ts +42 -0
  75. package/dist/providers/openai-responses-adapter.js +341 -0
  76. package/dist/providers/openai-responses.d.ts +14 -33
  77. package/dist/providers/openai-responses.js +131 -264
  78. package/dist/providers/openai.d.ts +29 -76
  79. package/dist/providers/openai.js +195 -292
  80. package/dist/providers/protocol-adapter.d.ts +34 -0
  81. package/dist/providers/protocol-adapter.js +9 -0
  82. package/dist/providers/protocol-capabilities.d.ts +34 -0
  83. package/dist/providers/protocol-capabilities.js +44 -0
  84. package/dist/providers/provider-error.d.ts +31 -0
  85. package/dist/providers/provider-error.js +149 -0
  86. package/dist/providers/public.d.ts +26 -3
  87. package/dist/providers/public.js +13 -1
  88. package/dist/providers/registry.d.ts +7 -6
  89. package/dist/providers/registry.js +47 -20
  90. package/dist/providers/request-plan.d.ts +86 -0
  91. package/dist/providers/request-plan.js +175 -0
  92. package/dist/providers/usage-normalizer.d.ts +48 -0
  93. package/dist/providers/usage-normalizer.js +96 -0
  94. package/dist/providers/vendor-profiles.d.ts +2 -15
  95. package/dist/providers/vendor-profiles.js +14 -60
  96. package/dist/runtime/canonical-kernel-step.d.ts +1 -2
  97. package/dist/runtime/canonical-kernel-step.js +47 -12
  98. package/dist/runtime/context-policy.d.ts +10 -12
  99. package/dist/runtime/context-policy.js +6 -8
  100. package/dist/runtime/durable-content.d.ts +50 -0
  101. package/dist/runtime/durable-content.js +159 -0
  102. package/dist/runtime/execution-plane.d.ts +2 -2
  103. package/dist/runtime/execution-plane.js +2 -2
  104. package/dist/runtime/kernel-event-log.js +0 -1
  105. package/dist/runtime/kernel-step.d.ts +0 -1
  106. package/dist/runtime/kernel-step.js +4 -2
  107. package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
  108. package/dist/runtime/mcp-proxy-plane.js +44 -6
  109. package/dist/runtime/output-schema.d.ts +1 -2
  110. package/dist/runtime/provider-replay.d.ts +1 -1
  111. package/dist/runtime/provider-replay.js +12 -27
  112. package/dist/runtime/reactive-session.d.ts +1 -1
  113. package/dist/runtime/reactive-session.js +2 -3
  114. package/dist/runtime/run-group.d.ts +1 -1
  115. package/dist/runtime/runner.d.ts +26 -40
  116. package/dist/runtime/runner.js +145 -63
  117. package/dist/runtime/session-log.d.ts +8 -1
  118. package/dist/runtime/session-log.js +42 -2
  119. package/dist/runtime/session-repair.d.ts +1 -1
  120. package/dist/runtime/session-repair.js +1 -1
  121. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  122. package/dist/runtime/sub-agent-orchestrator.js +8 -11
  123. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  124. package/dist/runtime/workflow-control-flow.js +0 -16
  125. package/dist/session.d.ts +11 -0
  126. package/dist/session.js +1 -0
  127. package/dist/skill.d.ts +17 -0
  128. package/dist/skill.js +16 -0
  129. package/dist/skills/loader.d.ts +3 -0
  130. package/dist/tools/errors.d.ts +1 -3
  131. package/dist/tools/errors.js +1 -3
  132. package/dist/tools/index.d.ts +3 -0
  133. package/dist/types/agent.d.ts +21 -9
  134. package/dist/types/agent.js +30 -4
  135. package/dist/types.d.ts +128 -13
  136. package/package.json +3 -3
  137. package/dist/providers/deepseek.d.ts +0 -46
  138. package/dist/providers/deepseek.js +0 -97
  139. package/dist/providers/glm.d.ts +0 -25
  140. package/dist/providers/glm.js +0 -48
  141. package/dist/providers/kimi.d.ts +0 -23
  142. package/dist/providers/kimi.js +0 -30
  143. package/dist/providers/minimax.d.ts +0 -49
  144. package/dist/providers/minimax.js +0 -98
  145. package/dist/providers/profiles.d.ts +0 -1992
  146. package/dist/providers/profiles.js +0 -796
  147. package/dist/providers/qwen.d.ts +0 -38
  148. package/dist/providers/qwen.js +0 -97
@@ -1,137 +1,11 @@
1
1
  import OpenAI from "openai";
2
2
  import { withServerRuntimeGuard } from "../runtime/server.js";
3
- import { CircuitBreaker, omitExtensionKeys } from "./base.js";
4
- import { normalizeToolCall } from "./base.js";
5
- import { UnsupportedModalityError } from "./base.js";
6
- export class OpenAIResponsesAdapter {
7
- buildTools(tools) {
8
- return tools.map(t => ({
9
- type: "function",
10
- name: t.name,
11
- description: t.description,
12
- parameters: JSON.parse(t.parameters),
13
- }));
14
- }
15
- buildInstructions(context) {
16
- return context.systemText || undefined;
17
- }
18
- buildInput(context, state) {
19
- const input = [];
20
- const turns = context.turns;
21
- const uncoveredMessages = state?.previousResponseId
22
- ? turns.slice(state.coveredMessageCount)
23
- : turns;
24
- for (const message of uncoveredMessages) {
25
- if (message.role === "assistant" && message.toolCalls?.length) {
26
- if (message.content || message.contentParts?.length) {
27
- input.push({
28
- role: "assistant",
29
- content: this.buildMessageContent(message),
30
- });
31
- }
32
- for (const tc of message.toolCalls) {
33
- input.push({
34
- type: "function_call",
35
- call_id: tc.id,
36
- name: tc.name,
37
- arguments: tc.arguments,
38
- });
39
- }
40
- continue;
41
- }
42
- if (message.role === "tool") {
43
- for (const part of message.contentParts ?? []) {
44
- if (part.type !== "tool_result")
45
- continue;
46
- input.push({
47
- type: "function_call_output",
48
- call_id: part.callId,
49
- output: part.output,
50
- });
51
- }
52
- continue;
53
- }
54
- input.push({
55
- role: message.role,
56
- content: this.buildMessageContent(message),
57
- });
58
- }
59
- // The volatile State turn is sent every turn (it changes each call and is
60
- // never "covered" by previous_response_id). Absent on un-rebuilt bindings,
61
- // where the state is already inside the covered/uncovered history.
62
- // Rendered through the same assistant-toolCalls / tool-result branches above
63
- // so tool_use blocks are not silently dropped.
64
- if (context.stateTurn) {
65
- const st = context.stateTurn;
66
- if (st.role === "assistant" && st.toolCalls?.length) {
67
- if (st.content || st.contentParts?.length) {
68
- input.push({ role: "assistant", content: this.buildMessageContent(st) });
69
- }
70
- for (const tc of st.toolCalls) {
71
- input.push({ type: "function_call", call_id: tc.id, name: tc.name, arguments: tc.arguments });
72
- }
73
- }
74
- else if (st.role === "tool") {
75
- for (const part of st.contentParts ?? []) {
76
- if (part.type !== "tool_result")
77
- continue;
78
- input.push({ type: "function_call_output", call_id: part.callId, output: part.output });
79
- }
80
- }
81
- else {
82
- input.push({ role: st.role, content: this.buildMessageContent(st) });
83
- }
84
- }
85
- return input;
86
- }
87
- decodeOutput(output) {
88
- let content = "";
89
- const toolCalls = [];
90
- for (const item of output) {
91
- if (item.type === "message") {
92
- for (const part of item.content ?? []) {
93
- if (part.type === "output_text")
94
- content += String(part.text ?? "");
95
- }
96
- }
97
- else if (item.type === "function_call") {
98
- const toolCall = normalizeToolCall(String(item.call_id ?? item.id ?? ""), String(item.name ?? ""), item.arguments ?? "{}");
99
- if (toolCall)
100
- toolCalls.push(toolCall);
101
- }
102
- }
103
- return { content, toolCalls };
104
- }
105
- buildMessageContent(message) {
106
- if (!message.contentParts?.length)
107
- return message.content;
108
- const content = [];
109
- for (const part of message.contentParts) {
110
- if (part.type === "text") {
111
- content.push({ type: "input_text", text: part.text });
112
- continue;
113
- }
114
- if (part.type === "image") {
115
- // Default the MIME type (like every other serializer) so a data-only image is
116
- // not silently dropped; only a part with neither url nor data yields undefined.
117
- const imageUrl = part.url ?? (part.data
118
- ? `data:${part.mediaType ?? "image/png"};base64,${part.data}`
119
- : undefined);
120
- if (imageUrl)
121
- content.push({
122
- type: "input_image",
123
- detail: part.detail ?? "auto",
124
- image_url: imageUrl,
125
- });
126
- continue;
127
- }
128
- if (part.type === "audio") {
129
- throw new UnsupportedModalityError("audio", "openai-responses");
130
- }
131
- }
132
- return content;
133
- }
134
- }
3
+ import { CircuitBreaker } from "./base.js";
4
+ import { normalizeCanonicalAdapterInput, } from "./content-normalization.js";
5
+ import { endpointProfiles } from "./endpoints.js";
6
+ import { OpenAIResponsesAdapter, } from "./openai-responses-adapter.js";
7
+ import { circuitOpenError, classifyProviderError } from "./provider-error.js";
8
+ export { OpenAIResponsesAdapter } from "./openai-responses-adapter.js";
135
9
  export class OpenAIResponsesProvider {
136
10
  model;
137
11
  client;
@@ -139,167 +13,160 @@ export class OpenAIResponsesProvider {
139
13
  maxRetries;
140
14
  baseDelay;
141
15
  responses = new OpenAIResponsesAdapter();
142
- constructor(apiKey, model = "gpt-4.1", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = "https://api.openai.com/v1") {
16
+ resolvedRuntimePolicy;
17
+ resolvedRuntime;
18
+ constructor(apiKey, model = "gpt-4.1", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = "https://api.openai.com/v1", runtimePolicy = {}, authMode = "api_key") {
143
19
  this.model = model;
144
- this.client = withServerRuntimeGuard(() => new OpenAI({ apiKey, baseURL }));
20
+ this.client = withServerRuntimeGuard(() => new OpenAI({
21
+ apiKey,
22
+ baseURL,
23
+ ...(authMode === "bearer" ? { defaultHeaders: { Authorization: `Bearer ${apiKey}` } } : {}),
24
+ }));
145
25
  this.circuit = new CircuitBreaker();
146
26
  this.maxRetries = retry.maxRetries;
147
27
  this.baseDelay = retry.baseDelay;
28
+ this.resolvedRuntimePolicy = runtimePolicy;
148
29
  }
149
30
  runtimePolicy() {
150
- const table = {
151
- "gpt-5.5": { maxTurns: 60 },
152
- "gpt-5.4": { maxTurns: 50 },
153
- "gpt-5.4-mini": { maxTurns: 25 },
154
- "gpt-5.4-nano": { maxTurns: 15 },
155
- "gpt-5.2": { maxTurns: 50 },
156
- "gpt-5.2-pro": { maxTurns: 60 },
157
- "gpt-5.1": { maxTurns: 50 },
158
- "gpt-4.1": { maxTurns: 35 },
159
- "gpt-4.1-mini": { maxTurns: 20 },
160
- "gpt-4.1-nano": { maxTurns: 15 },
161
- "gpt-5": { maxTurns: 50 },
162
- "gpt-5-pro": { maxTurns: 60 },
163
- "gpt-5-mini": { maxTurns: 25 },
164
- "gpt-5-nano": { maxTurns: 15 },
165
- "o3": { maxTurns: 50 },
166
- "o3-mini": { maxTurns: 25 },
167
- "o4-mini": { maxTurns: 25 },
168
- };
169
- return table[this.model] ?? {};
31
+ return this.resolvedRuntimePolicy;
32
+ }
33
+ bindResolvedRuntime(resolved) {
34
+ if (resolved.identity.protocol !== "openai-responses"
35
+ || resolved.identity.providerId !== "openai"
36
+ || resolved.identity.modelId !== this.model) {
37
+ throw new Error("OpenAIResponsesProvider received a mismatched resolved runtime");
38
+ }
39
+ this.resolvedRuntime = resolved;
170
40
  }
171
41
  createRunState() {
172
42
  return { coveredMessageCount: 0 };
173
43
  }
44
+ adapterInput(context, tools, extensions) {
45
+ const resolved = this.resolvedRuntime ?? {
46
+ identity: {
47
+ providerId: "openai",
48
+ modelId: this.model,
49
+ endpointId: "openai.responses",
50
+ protocol: "openai-responses",
51
+ },
52
+ model: {
53
+ id: `openai/${this.model}`,
54
+ providerId: "openai",
55
+ kind: "generation",
56
+ intrinsic: {},
57
+ },
58
+ endpoint: endpointProfiles["openai.responses"],
59
+ adapter: this,
60
+ effectiveCapabilities: compatibilityCapabilities(),
61
+ };
62
+ return normalizeCanonicalAdapterInput({ context, tools, resolved, extensions });
63
+ }
174
64
  async complete(context, tools, extensions) {
175
65
  if (this.circuit.isOpen())
176
- throw new Error("Circuit breaker open");
177
- let lastErr;
178
- for (let i = 0; i < this.maxRetries; i++) {
66
+ throw circuitOpenError("openai");
67
+ let input;
68
+ let plan;
69
+ try {
70
+ input = this.adapterInput(context, tools, extensions);
71
+ plan = this.responses.buildRequest(input);
72
+ }
73
+ catch (error) {
74
+ throw classifyProviderError("openai", error);
75
+ }
76
+ let lastError;
77
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
179
78
  try {
180
- const instructions = this.responses.buildInstructions(context);
181
- const resp = await this.client.responses.create({
182
- ...this.requestExtensions(extensions),
183
- model: this.model,
184
- input: this.responses.buildInput(context),
185
- ...(instructions ? { instructions } : {}),
186
- ...((t => t ? { tools: t } : {})(this.allTools(tools, extensions))),
187
- });
79
+ const response = await this.client.responses.create(plan.params);
188
80
  this.circuit.recordSuccess();
189
- const decoded = this.responses.decodeOutput(resp.output);
190
- return {
191
- role: "assistant",
192
- content: decoded.content,
193
- toolCalls: decoded.toolCalls,
194
- tokenCount: resp.usage?.output_tokens ?? resp.usage?.total_tokens,
195
- };
81
+ return this.responses.decodeComplete(response, { input }).message;
196
82
  }
197
- catch (err) {
198
- lastErr = err;
83
+ catch (error) {
84
+ lastError = error;
199
85
  this.circuit.recordFailure();
200
- if (i < this.maxRetries - 1)
201
- await new Promise(r => setTimeout(r, this.baseDelay * 2 ** i));
86
+ if (attempt < this.maxRetries - 1) {
87
+ await new Promise(resolve => setTimeout(resolve, this.baseDelay * 2 ** attempt));
88
+ }
202
89
  }
203
90
  }
204
- throw lastErr;
91
+ throw classifyProviderError("openai", lastError);
205
92
  }
206
- async *stream(context, tools, extensions, state) {
207
- const runState = this.asRunState(state);
208
- const functionCalls = new Map();
209
- const instructions = this.responses.buildInstructions(context);
210
- const stream = await this.client.responses.create({
211
- ...this.requestExtensions(extensions),
212
- model: this.model,
213
- input: this.responses.buildInput(context, runState),
214
- ...(instructions ? { instructions } : {}),
215
- ...(runState.previousResponseId ? { previous_response_id: runState.previousResponseId } : {}),
216
- ...((t => t ? { tools: t } : {})(this.allTools(tools, extensions))),
217
- stream: true,
218
- });
219
- for await (const evt of stream) {
220
- if (evt.type === "response.output_text.delta") {
221
- yield { type: "text_delta", delta: evt.delta };
222
- }
223
- else if (evt.type === "response.output_item.added" && evt.item.type === "function_call") {
224
- functionCalls.set(evt.output_index, {
225
- id: evt.item.call_id,
226
- name: evt.item.name,
227
- argsBuf: evt.item.arguments ?? "",
228
- });
229
- }
230
- else if (evt.type === "response.function_call_arguments.delta") {
231
- const call = functionCalls.get(evt.output_index);
232
- if (call)
233
- call.argsBuf += evt.delta;
234
- }
235
- else if (evt.type === "response.function_call_arguments.done") {
236
- const call = functionCalls.get(evt.output_index);
237
- if (call)
238
- call.argsBuf = evt.arguments;
239
- }
240
- else if (evt.type === "response.output_item.done" && evt.item.type === "function_call") {
241
- const call = functionCalls.get(evt.output_index) ?? {
242
- id: evt.item.call_id,
243
- name: evt.item.name,
244
- argsBuf: evt.item.arguments ?? "{}",
245
- };
246
- let args = {};
247
- try {
248
- args = JSON.parse(call.argsBuf || "{}");
249
- }
250
- catch {
251
- args = {};
93
+ async *stream(context, tools, extensions, state, signal) {
94
+ try {
95
+ const runState = this.asRunState(state);
96
+ const input = this.adapterInput(context, tools, extensions);
97
+ const plan = this.responses.buildRequest(input, runState);
98
+ const streamState = this.responses.createStreamState({ input }, runState);
99
+ const stream = await this.client.responses.create({ ...plan.params, stream: true }, signal ? { signal } : undefined);
100
+ for await (const chunk of stream) {
101
+ const output = this.responses.pushStreamChunk(chunk, streamState);
102
+ for (const event of output.events)
103
+ yield event;
104
+ if (output.runStatePatch) {
105
+ Object.assign(runState, output.runStatePatch);
106
+ if (state)
107
+ Object.assign(state, output.runStatePatch);
252
108
  }
253
- yield { type: "tool_call", id: call.id, name: call.name, arguments: args };
254
109
  }
255
- else if (evt.type === "response.completed") {
256
- runState.previousResponseId = evt.response.id;
257
- runState.coveredMessageCount = context.turns.length + 1;
258
- if (evt.response.usage?.total_tokens) {
259
- // Responses API reports prompt-cache hits as input_tokens_details.cached_tokens,
260
- // a subset of input_tokens (the full prompt, kept for accounting).
261
- const cachedTokens = evt.response.usage.input_tokens_details?.cached_tokens ?? 0;
262
- yield {
263
- type: "usage",
264
- totalTokens: evt.response.usage.total_tokens,
265
- ...(evt.response.usage.input_tokens ? { inputTokens: evt.response.usage.input_tokens } : {}),
266
- ...(evt.response.usage.output_tokens ? { outputTokens: evt.response.usage.output_tokens } : {}),
267
- ...(cachedTokens > 0 ? { cacheReadInputTokens: cachedTokens } : {}),
268
- };
269
- }
110
+ const final = this.responses.finishStream(streamState);
111
+ for (const event of final.events)
112
+ yield event;
113
+ if (final.runStatePatch) {
114
+ Object.assign(runState, final.runStatePatch);
115
+ if (state)
116
+ Object.assign(state, final.runStatePatch);
270
117
  }
271
118
  }
119
+ catch (error) {
120
+ throw classifyProviderError("openai", error);
121
+ }
272
122
  }
273
- requestExtensions(extensions) {
274
- return omitExtensionKeys(extensions, [
275
- "model", "input", "instructions", "tools", "stream", "previous_response_id",
276
- "web_search", "builtin_tools",
277
- ]);
278
- }
279
- /** Responses API built-in server tools from extensions (live in the same tools[] as function tools):
280
- * `web_search: true` (or a config object), plus a `builtin_tools` list passed through verbatim for
281
- * file_search / code_interpreter. They run server-side; results return inline. Mirrors py. */
123
+ // White-box test seams. Protocol request shaping belongs to the adapter.
282
124
  builtinTools(extensions) {
283
- const ext = extensions ?? {};
284
- const out = [];
285
- const ws = ext.web_search;
286
- if (ws)
287
- out.push(typeof ws === "object" ? { type: "web_search", ...ws } : { type: "web_search" });
288
- if (Array.isArray(ext.builtin_tools))
289
- out.push(...ext.builtin_tools);
290
- return out;
125
+ return this.responses.builtinTools(extensions);
291
126
  }
292
- /** Function tools + built-in server tools merged into the wire tools[] (undefined when empty). */
293
- allTools(tools, extensions) {
294
- const fnTools = tools.length ? this.responses.buildTools(tools) : [];
295
- const all = [...fnTools, ...this.builtinTools(extensions)];
296
- return all.length ? all : undefined;
127
+ requestExtensions(extensions) {
128
+ return this.responses.requestExtensions(extensions);
297
129
  }
298
130
  asRunState(state) {
299
131
  if (!state)
300
132
  return this.createRunState();
301
- if (typeof state.coveredMessageCount !== "number")
302
- state.coveredMessageCount = 0;
303
- return state;
133
+ return {
134
+ ...state,
135
+ coveredMessageCount: typeof state.coveredMessageCount === "number"
136
+ ? state.coveredMessageCount
137
+ : 0,
138
+ };
304
139
  }
305
140
  }
141
+ function compatibilityCapabilities() {
142
+ const unknown = { state: "unknown", evidence: [] };
143
+ const unsupported = { state: "unsupported", evidence: ["protocol"] };
144
+ return {
145
+ inputModalities: {
146
+ text: unknown,
147
+ image: unknown,
148
+ audio: unsupported,
149
+ video: unsupported,
150
+ file: unknown,
151
+ },
152
+ outputModalities: {
153
+ text: unknown,
154
+ image: unsupported,
155
+ audio: unsupported,
156
+ embedding: unsupported,
157
+ },
158
+ tools: unknown,
159
+ reasoning: unknown,
160
+ parallelToolCalls: unknown,
161
+ structuredOutput: unknown,
162
+ promptCaching: unknown,
163
+ nativeTokenCounting: unknown,
164
+ mediaForms: {
165
+ imageUrl: unknown,
166
+ imageBase64: unknown,
167
+ fileId: unknown,
168
+ audioUrl: unsupported,
169
+ audioBase64: unsupported,
170
+ },
171
+ };
172
+ }
@@ -1,10 +1,10 @@
1
1
  import OpenAI from "openai";
2
- import type { Message, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
+ import type { LLMProvider, Message, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext, ReplayabilityAssessment, RuntimePolicy, StreamEvent, ToolSchema } from "../types.js";
3
3
  import { CircuitBreaker } from "./base.js";
4
+ import { type CanonicalAdapterInput } from "./content-normalization.js";
4
5
  import { OpenAIChatAdapter } from "./openai-chat.js";
5
- import type { ReplayabilityAssessment } from "./replay-validator.js";
6
- /** Options-object form for `OpenAIProvider` the recommended way to construct an OpenAI-compatible
7
- * provider (custom `baseURL` no longer needs a positional hole). */
6
+ import { type OpenAIChatTurnReasoning, type OpenAIChatWireDialect } from "./openai-chat-dialects.js";
7
+ /** Canonical constructor contract for OpenAI-chat providers. */
8
8
  export interface OpenAIProviderOptions {
9
9
  apiKey: string;
10
10
  model?: string;
@@ -12,23 +12,13 @@ export interface OpenAIProviderOptions {
12
12
  maxRetries: number;
13
13
  baseDelay: number;
14
14
  };
15
- /** Custom OpenAI-compatible endpoint (MiMo, DeepSeek, Kimi, …). Defaults to the OpenAI API. */
16
15
  baseURL?: string;
16
+ runtimePolicy?: RuntimePolicy;
17
+ dialect?: OpenAIChatWireDialect;
18
+ authMode?: "api_key" | "bearer";
17
19
  }
18
- /** Reasoning captured from a single model turn, handed to the replay-remember hooks so an
19
- * OpenAI-compatible subclass can persist whatever replay envelope its wire requires. */
20
- export interface OpenAIChatTurnReasoning {
21
- reasoningContent: string;
22
- reasoningDetails?: unknown;
23
- nativeToolCalls: unknown[];
24
- }
25
- /** Rebuild OpenAI-native `tool_calls` blocks from the streamed buffers — needed by reasoning
26
- * vendors (DeepSeek/MiniMax) that persist the native blocks in their replay envelope. */
27
- export declare function nativeToolCallsFromBuffers(toolCallBufs: Record<number, {
28
- id: string;
29
- name: string;
30
- argsBuf: string;
31
- }>): Array<Record<string, unknown>>;
20
+ export type { OpenAIChatTurnReasoning } from "./openai-chat-dialects.js";
21
+ type ResolvedOpenAIChatRuntime = CanonicalAdapterInput["resolved"];
32
22
  export declare class OpenAIChatProvider implements LLMProvider {
33
23
  protected client: OpenAI;
34
24
  protected circuit: CircuitBreaker;
@@ -36,72 +26,35 @@ export declare class OpenAIChatProvider implements LLMProvider {
36
26
  protected baseDelay: number;
37
27
  protected readonly model: string;
38
28
  protected readonly chat: OpenAIChatAdapter;
39
- constructor(apiKeyOrOptions: string | OpenAIProviderOptions, model?: string, retry?: {
40
- maxRetries: number;
41
- baseDelay: number;
42
- }, baseURL?: string);
29
+ protected readonly dialect: OpenAIChatWireDialect;
30
+ private readonly replayStore;
31
+ private readonly resolvedRuntimePolicy;
32
+ private resolvedRuntime?;
33
+ constructor(options: OpenAIProviderOptions);
43
34
  runtimePolicy(): RuntimePolicy;
44
35
  descriptor(): ProviderDescriptor;
45
- protected requireNonEmptyReasoningReplayForToolTurns(_extensions?: Record<string, unknown>): boolean;
46
- protected degradeMissingReasoningReplay(extensions?: Record<string, unknown>): boolean;
47
- protected buildChatMessages(context: RenderedContext, extensions?: Record<string, unknown>): OpenAI.Chat.Completions.ChatCompletionMessageParam[];
48
- /** Pre-process caller extensions before they reach buildChatMessages + the wire request
49
- * (e.g. set `__deepstrikeThinkingEnabled`). Default: pass through unchanged. */
50
- protected prepareExtensions(extensions?: Record<string, unknown>): Record<string, unknown> | undefined;
51
- /** Extra top-level request-body fields merged into the chat.completions call (vendor thinking
52
- * knobs like `reasoning_effort`, `extra_body`, `reasoning_split`). Default: none. */
53
- protected requestBodyExtras(_extensions?: Record<string, unknown>): Record<string, unknown>;
54
- /** Vendor server tools (e.g. web search) injected into the `tools[]` array alongside the function
55
- * tools, driven by caller `extensions`. These run server-side — the model invokes them and the
56
- * results come back inline, with no client tool-loop round-trip. Default: none. Vendors that ship
57
- * built-in tools (GLM web_search, ) override this and strip the consumed key in `prepareExtensions`
58
- * so it does not also leak into the request body. */
59
- protected serverTools(_extensions?: Record<string, unknown>): unknown[];
60
- /** Merge function tools + vendor server tools into the wire `tools[]` (undefined when empty). Server
61
- * tools (e.g. web_search) are non-standard wire entries, so the array is cast to the SDK tool type. */
62
- protected assembleTools(tools: ToolSchema[], extensions?: Record<string, unknown>): OpenAI.Chat.Completions.ChatCompletionTool[] | undefined;
63
- /** Request-body params controlling prompt caching. Default sends OpenAI's `prompt_cache_key`;
64
- * vendors whose endpoints reject unknown params (e.g. DeepSeek 400s) override to `{}`. */
65
- protected cacheKeyParams(context: RenderedContext, tools: ToolSchema[]): Record<string, unknown>;
66
- /** Whether streamed `content` may carry inline `<thinking>…</thinking>` tags to split out.
67
- * Default true (OpenAI). Reasoning vendors emit reasoning out-of-band, so they return false. */
68
- protected usesInlineThinkingTags(): boolean;
69
- /** Whether to surface streamed `reasoning_content` as thinking_delta events. Default true;
70
- * vendors gate this behind an `exposeReasoning` extension. */
71
- protected exposeReasoningDelta(_extensions?: Record<string, unknown>): boolean;
72
- /** Persist replay after a non-streaming turn. Default: nothing (plain OpenAI has no reasoning
73
- * to replay). Reasoning vendors override to store their envelope. */
36
+ bindResolvedRuntime(resolved: ResolvedOpenAIChatRuntime): void;
37
+ assessReplayability(context: RenderedContext, extensions?: Record<string, unknown>): ReplayabilityAssessment;
38
+ peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
39
+ seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
40
+ private rememberReplay;
41
+ private adapterInput;
42
+ complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
43
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, _state?: ProviderRunState, signal?: AbortSignal): AsyncIterable<StreamEvent>;
44
+ protected prepareExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;
45
+ protected requestBodyExtras(extensions?: Record<string, unknown>): Record<string, unknown>;
46
+ protected serverTools(extensions?: Record<string, unknown>): unknown[];
47
+ protected requestExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;
48
+ protected promptCacheKey(context: RenderedContext, tools: ToolSchema[]): string;
74
49
  protected rememberCompleteReplay(_content: string, _toolCalls: Array<{
75
50
  id: string;
76
51
  name: string;
77
52
  arguments: string;
78
53
  }>, _reasoning: OpenAIChatTurnReasoning): void;
79
- /** Persist replay after a streamed turn. Default: store `{ reasoning_content }` when there is a
80
- * tool-call turn or captured reasoning (the prior base behavior). Vendors override. */
81
- protected rememberStreamReplay(content: string, toolCalls: Array<{
54
+ protected rememberStreamReplay(_content: string, _toolCalls: Array<{
82
55
  id: string;
83
56
  name: string;
84
57
  arguments: string;
85
- }>, reasoning: OpenAIChatTurnReasoning): void;
86
- /**
87
- * Pre-flight query: would this history validate against this provider with the
88
- * given extensions, without sending the request? Lets an embedder route around
89
- * a reasoning-replay failure (keep thinking on, disable it, or skip this
90
- * candidate) before issuing the request. `ok: true` when this provider does
91
- * not require reasoning replay for the current extensions.
92
- */
93
- assessReplayability(context: RenderedContext, extensions?: Record<string, unknown>): ReplayabilityAssessment;
94
- peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
95
- seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
96
- complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
97
- stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, _state?: ProviderRunState, signal?: AbortSignal): AsyncIterable<StreamEvent>;
98
- /**
99
- * Default `prompt_cache_key` derived from the cacheable prefix (system prompt +
100
- * tool names) so requests for the same agent config route to the same cache.
101
- * A caller-supplied `prompt_cache_key` in extensions overrides it (it is spread
102
- * after this default). Unknown to non-OpenAI compatible endpoints, which ignore it.
103
- */
104
- protected promptCacheKey(context: RenderedContext, tools: ToolSchema[]): string;
105
- protected requestExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;
58
+ }>, _reasoning: OpenAIChatTurnReasoning): void;
106
59
  }
107
60
  export { OpenAIChatProvider as OpenAIProvider };