@deepstrike/sdk 0.2.51 → 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.
- package/README.md +28 -28
- package/dist/agent-ir.d.ts +103 -0
- package/dist/agent-ir.js +134 -0
- package/dist/agent.d.ts +67 -0
- package/dist/agent.js +36 -0
- package/dist/collaboration/harness.js +1 -1
- package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
- package/dist/collaboration/modes/creator-verifier.js +4 -6
- package/dist/collaboration/pool.d.ts +8 -20
- package/dist/collaboration/pool.js +27 -97
- package/dist/compat/anthropic/mcp.d.ts +15 -0
- package/dist/compat/anthropic/mcp.js +10 -0
- package/dist/compat/openai/agent.d.ts +34 -0
- package/dist/compat/openai/agent.js +24 -0
- package/dist/governance.d.ts +1 -17
- package/dist/governance.js +1 -34
- package/dist/guardrail.d.ts +6 -0
- package/dist/guardrail.js +1 -0
- package/dist/handoff-target.d.ts +12 -0
- package/dist/handoff-target.js +1 -0
- package/dist/harness/manifest.js +0 -4
- package/dist/index.d.ts +19 -7
- package/dist/index.js +8 -5
- package/dist/kernel.d.ts +2 -20
- package/dist/knowledge/public.d.ts +29 -0
- package/dist/knowledge/public.js +1 -0
- package/dist/mcp-server.d.ts +28 -0
- package/dist/mcp-server.js +1 -0
- package/dist/memory/agent.d.ts +2 -2
- package/dist/memory/agent.js +2 -2
- package/dist/memory/durable.d.ts +16 -0
- package/dist/memory/durable.js +46 -0
- package/dist/memory/in-memory-store.d.ts +9 -7
- package/dist/memory/in-memory-store.js +8 -2
- package/dist/memory/protocols.d.ts +22 -4
- package/dist/memory/public.d.ts +4 -3
- package/dist/memory/public.js +3 -2
- package/dist/providers/anthropic-adapter.d.ts +47 -0
- package/dist/providers/anthropic-adapter.js +444 -0
- package/dist/providers/anthropic-compatible.d.ts +2 -3
- package/dist/providers/anthropic-compatible.js +8 -5
- package/dist/providers/anthropic.d.ts +19 -23
- package/dist/providers/anthropic.js +169 -395
- package/dist/providers/base.js +43 -3
- package/dist/providers/capability-router.d.ts +29 -0
- package/dist/providers/capability-router.js +43 -0
- package/dist/providers/catalog.d.ts +16 -4
- package/dist/providers/catalog.js +112 -21
- package/dist/providers/content-normalization.d.ts +57 -0
- package/dist/providers/content-normalization.js +238 -0
- package/dist/providers/content-policy.d.ts +16 -0
- package/dist/providers/content-policy.js +39 -0
- package/dist/providers/credentials.d.ts +83 -0
- package/dist/providers/credentials.js +190 -0
- package/dist/providers/endpoints.d.ts +137 -0
- package/dist/providers/endpoints.js +128 -0
- package/dist/providers/factories.js +9 -3
- package/dist/providers/gemini-adapter.d.ts +33 -0
- package/dist/providers/gemini-adapter.js +272 -0
- package/dist/providers/gemini.d.ts +16 -3
- package/dist/providers/gemini.js +97 -195
- package/dist/providers/model-catalog.d.ts +37 -0
- package/dist/providers/model-catalog.js +62 -0
- package/dist/providers/model-registry.d.ts +98 -0
- package/dist/providers/model-registry.js +315 -0
- package/dist/providers/ollama-adapter.d.ts +65 -0
- package/dist/providers/ollama-adapter.js +188 -0
- package/dist/providers/ollama.d.ts +9 -4
- package/dist/providers/ollama.js +96 -109
- package/dist/providers/openai-chat-dialects.d.ts +154 -0
- package/dist/providers/openai-chat-dialects.js +179 -0
- package/dist/providers/openai-chat.d.ts +46 -18
- package/dist/providers/openai-chat.js +418 -51
- package/dist/providers/openai-responses-adapter.d.ts +42 -0
- package/dist/providers/openai-responses-adapter.js +341 -0
- package/dist/providers/openai-responses.d.ts +14 -33
- package/dist/providers/openai-responses.js +131 -264
- package/dist/providers/openai.d.ts +29 -76
- package/dist/providers/openai.js +195 -292
- package/dist/providers/protocol-adapter.d.ts +34 -0
- package/dist/providers/protocol-adapter.js +9 -0
- package/dist/providers/protocol-capabilities.d.ts +34 -0
- package/dist/providers/protocol-capabilities.js +44 -0
- package/dist/providers/provider-error.d.ts +31 -0
- package/dist/providers/provider-error.js +149 -0
- package/dist/providers/public.d.ts +26 -3
- package/dist/providers/public.js +13 -1
- package/dist/providers/registry.d.ts +7 -6
- package/dist/providers/registry.js +47 -20
- package/dist/providers/request-plan.d.ts +86 -0
- package/dist/providers/request-plan.js +175 -0
- package/dist/providers/usage-normalizer.d.ts +48 -0
- package/dist/providers/usage-normalizer.js +96 -0
- package/dist/providers/vendor-profiles.d.ts +2 -15
- package/dist/providers/vendor-profiles.js +14 -60
- package/dist/runtime/canonical-kernel-step.d.ts +10 -2
- package/dist/runtime/canonical-kernel-step.js +106 -32
- package/dist/runtime/context-policy.d.ts +10 -12
- package/dist/runtime/context-policy.js +6 -8
- package/dist/runtime/durable-content.d.ts +50 -0
- package/dist/runtime/durable-content.js +159 -0
- package/dist/runtime/execution-plane.d.ts +2 -2
- package/dist/runtime/execution-plane.js +2 -2
- package/dist/runtime/kernel-event-log.js +0 -1
- package/dist/runtime/kernel-step.d.ts +0 -1
- package/dist/runtime/kernel-step.js +4 -2
- package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
- package/dist/runtime/mcp-proxy-plane.js +44 -6
- package/dist/runtime/output-schema.d.ts +1 -2
- package/dist/runtime/provider-replay.d.ts +1 -1
- package/dist/runtime/provider-replay.js +12 -27
- package/dist/runtime/reactive-session.d.ts +1 -1
- package/dist/runtime/reactive-session.js +2 -3
- package/dist/runtime/run-group.d.ts +1 -1
- package/dist/runtime/runner.d.ts +26 -40
- package/dist/runtime/runner.js +145 -63
- package/dist/runtime/session-log.d.ts +8 -1
- package/dist/runtime/session-log.js +42 -2
- package/dist/runtime/session-repair.d.ts +1 -1
- package/dist/runtime/session-repair.js +1 -1
- package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
- package/dist/runtime/sub-agent-orchestrator.js +8 -11
- package/dist/runtime/workflow-control-flow.d.ts +0 -4
- package/dist/runtime/workflow-control-flow.js +0 -16
- package/dist/session.d.ts +11 -0
- package/dist/session.js +1 -0
- package/dist/skill.d.ts +17 -0
- package/dist/skill.js +16 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/tools/errors.d.ts +1 -3
- package/dist/tools/errors.js +1 -3
- package/dist/tools/index.d.ts +3 -0
- package/dist/types/agent.d.ts +21 -9
- package/dist/types/agent.js +30 -4
- package/dist/types.d.ts +128 -13
- package/package.json +3 -3
- package/dist/providers/deepseek.d.ts +0 -46
- package/dist/providers/deepseek.js +0 -97
- package/dist/providers/glm.d.ts +0 -25
- package/dist/providers/glm.js +0 -48
- package/dist/providers/kimi.d.ts +0 -23
- package/dist/providers/kimi.js +0 -30
- package/dist/providers/minimax.d.ts +0 -49
- package/dist/providers/minimax.js +0 -98
- package/dist/providers/profiles.d.ts +0 -1992
- package/dist/providers/profiles.js +0 -796
- package/dist/providers/qwen.d.ts +0 -38
- 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
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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({
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"
|
|
157
|
-
|
|
158
|
-
|
|
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
|
|
177
|
-
let
|
|
178
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
198
|
-
|
|
83
|
+
catch (error) {
|
|
84
|
+
lastError = error;
|
|
199
85
|
this.circuit.recordFailure();
|
|
200
|
-
if (
|
|
201
|
-
await new Promise(
|
|
86
|
+
if (attempt < this.maxRetries - 1) {
|
|
87
|
+
await new Promise(resolve => setTimeout(resolve, this.baseDelay * 2 ** attempt));
|
|
88
|
+
}
|
|
202
89
|
}
|
|
203
90
|
}
|
|
204
|
-
throw
|
|
91
|
+
throw classifyProviderError("openai", lastError);
|
|
205
92
|
}
|
|
206
|
-
async *stream(context, tools, extensions, state) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
293
|
-
|
|
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
|
-
|
|
302
|
-
state
|
|
303
|
-
|
|
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,
|
|
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
|
|
6
|
-
/**
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
protected
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
}>,
|
|
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 };
|