@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,12 +1,404 @@
|
|
|
1
1
|
import { assistantReplayKey } from "../runtime/provider-replay.js";
|
|
2
|
-
import {
|
|
2
|
+
import { openAICachedPromptTokens, stablePromptCacheKey, ThinkingTagStreamExtractor, } from "./base.js";
|
|
3
|
+
import { normalizeCanonicalContext, projectToolOutputToText } from "./content-normalization.js";
|
|
4
|
+
import { normalizeToolCall } from "./base.js";
|
|
3
5
|
import { DEGRADED_REASONING_PLACEHOLDER, assessReasoningReplay, validateOpenAIChatReplay, } from "./replay-validator.js";
|
|
6
|
+
import { ProtocolResponseError, } from "./protocol-adapter.js";
|
|
7
|
+
import { OPENAI_CHAT_PROTOCOL_CAPABILITIES } from "./protocol-capabilities.js";
|
|
8
|
+
import { openAIChatDialects, replayForTurn, } from "./openai-chat-dialects.js";
|
|
9
|
+
const COMPATIBILITY_REPLAY = new WeakMap();
|
|
10
|
+
function compatibilityReplayStore(adapter) {
|
|
11
|
+
let store = COMPATIBILITY_REPLAY.get(adapter);
|
|
12
|
+
if (!store) {
|
|
13
|
+
store = new Map();
|
|
14
|
+
COMPATIBILITY_REPLAY.set(adapter, store);
|
|
15
|
+
}
|
|
16
|
+
return store;
|
|
17
|
+
}
|
|
18
|
+
function wireReplay(replay) {
|
|
19
|
+
if (!replay)
|
|
20
|
+
return undefined;
|
|
21
|
+
const fields = {};
|
|
22
|
+
if (typeof replay.reasoning_content === "string")
|
|
23
|
+
fields.reasoning_content = replay.reasoning_content;
|
|
24
|
+
if (replay.reasoning_details !== undefined)
|
|
25
|
+
fields.reasoning_details = replay.reasoning_details;
|
|
26
|
+
return Object.keys(fields).length ? fields : undefined;
|
|
27
|
+
}
|
|
28
|
+
function blockContent(message) {
|
|
29
|
+
const content = [];
|
|
30
|
+
for (const block of message.blocks) {
|
|
31
|
+
if (block.type === "tool_result")
|
|
32
|
+
continue;
|
|
33
|
+
if (block.type === "text")
|
|
34
|
+
content.push({ type: "text", text: block.text });
|
|
35
|
+
else if (block.type === "image") {
|
|
36
|
+
const url = block.source.kind === "url"
|
|
37
|
+
? block.source.url
|
|
38
|
+
: block.source.kind === "base64"
|
|
39
|
+
? `data:${block.mediaType ?? "image/png"};base64,${block.source.data}`
|
|
40
|
+
: undefined;
|
|
41
|
+
if (url)
|
|
42
|
+
content.push({
|
|
43
|
+
type: "image_url",
|
|
44
|
+
image_url: {
|
|
45
|
+
url,
|
|
46
|
+
...(block.providerOptions?.openai_detail
|
|
47
|
+
? { detail: block.providerOptions.openai_detail }
|
|
48
|
+
: {}),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else if (block.type === "audio" && block.source.kind === "base64") {
|
|
53
|
+
const subtype = (block.mediaType ?? "audio/wav").split("/")[1] ?? "wav";
|
|
54
|
+
content.push({
|
|
55
|
+
type: "input_audio",
|
|
56
|
+
input_audio: {
|
|
57
|
+
data: block.source.data,
|
|
58
|
+
format: subtype === "mpeg" ? "mp3" : subtype,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return message.contentForm !== "blocks" && content.length === 1 && content[0].type === "text"
|
|
64
|
+
? String(content[0].text ?? "")
|
|
65
|
+
: content;
|
|
66
|
+
}
|
|
67
|
+
function validateCanonicalReplay(input, dialect, prepared) {
|
|
68
|
+
let pending;
|
|
69
|
+
let completed = new Set();
|
|
70
|
+
const assertComplete = () => {
|
|
71
|
+
const missing = pending ? [...pending].filter(id => !completed.has(id)) : [];
|
|
72
|
+
if (missing.length)
|
|
73
|
+
throw new Error(`OpenAI-compatible replay has assistant tool_calls with no tool result for ${missing.join(", ")}`);
|
|
74
|
+
};
|
|
75
|
+
for (const message of input.context.turns) {
|
|
76
|
+
if (message.role === "assistant") {
|
|
77
|
+
assertComplete();
|
|
78
|
+
pending = message.toolCalls?.length ? new Set(message.toolCalls.map(call => call.id)) : undefined;
|
|
79
|
+
completed = new Set();
|
|
80
|
+
}
|
|
81
|
+
else if (message.role === "tool") {
|
|
82
|
+
for (const block of message.blocks) {
|
|
83
|
+
if (block.type !== "tool_result")
|
|
84
|
+
continue;
|
|
85
|
+
if (!pending?.has(block.callId))
|
|
86
|
+
throw new Error(`OpenAI-compatible replay has orphan tool result ${block.callId}`);
|
|
87
|
+
if (completed.has(block.callId))
|
|
88
|
+
throw new Error(`OpenAI-compatible replay has duplicate tool result ${block.callId}`);
|
|
89
|
+
completed.add(block.callId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
assertComplete();
|
|
94
|
+
pending = undefined;
|
|
95
|
+
completed = new Set();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
assertComplete();
|
|
99
|
+
if (dialect.requireReasoningReplay(prepared) && prepared.degradeMissingReasoningReplay !== true) {
|
|
100
|
+
const missing = input.context.turns.flatMap(message => message.role === "assistant" && message.toolCalls?.length
|
|
101
|
+
&& !(typeof message.providerReplay?.reasoning_content === "string" && message.providerReplay.reasoning_content.trim())
|
|
102
|
+
? message.toolCalls.map(call => call.id)
|
|
103
|
+
: []);
|
|
104
|
+
if (missing.length) {
|
|
105
|
+
throw new Error(`${dialect.providerId}/${input.resolved.identity.modelId} replay requires non-empty reasoning_content for assistant tool call turn ${missing.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function messages(input, dialect, prepared) {
|
|
110
|
+
validateCanonicalReplay(input, dialect, prepared);
|
|
111
|
+
const output = [];
|
|
112
|
+
if (input.context.systemText)
|
|
113
|
+
output.push({ role: "system", content: input.context.systemText });
|
|
114
|
+
const turns = input.context.stateTurn
|
|
115
|
+
? [...input.context.turns, input.context.stateTurn]
|
|
116
|
+
: input.context.turns;
|
|
117
|
+
for (const message of turns) {
|
|
118
|
+
if (message.role === "tool") {
|
|
119
|
+
for (const block of message.blocks) {
|
|
120
|
+
if (block.type !== "tool_result")
|
|
121
|
+
continue;
|
|
122
|
+
output.push({
|
|
123
|
+
role: "tool",
|
|
124
|
+
tool_call_id: block.callId,
|
|
125
|
+
content: projectToolOutputToText(block.blocks),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const next = { role: message.role, content: blockContent(message) };
|
|
131
|
+
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
132
|
+
next.tool_calls = message.toolCalls.map(call => ({
|
|
133
|
+
id: call.id,
|
|
134
|
+
type: "function",
|
|
135
|
+
function: { name: call.name, arguments: call.arguments },
|
|
136
|
+
}));
|
|
137
|
+
const replay = wireReplay(message.providerReplay)
|
|
138
|
+
?? (dialect.requireReasoningReplay(prepared) && prepared.degradeMissingReasoningReplay === true
|
|
139
|
+
? { reasoning_content: DEGRADED_REASONING_PLACEHOLDER }
|
|
140
|
+
: undefined);
|
|
141
|
+
if (replay)
|
|
142
|
+
Object.assign(next, replay);
|
|
143
|
+
}
|
|
144
|
+
output.push(next);
|
|
145
|
+
}
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
function nativeToolCalls(buffers) {
|
|
149
|
+
return Object.values(buffers).map(call => ({
|
|
150
|
+
id: call.id,
|
|
151
|
+
type: "function",
|
|
152
|
+
function: { name: call.name, arguments: call.argsBuffer || "{}" },
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
function finalToolCalls(state) {
|
|
156
|
+
return Object.values(state.toolCallBuffers).map(call => ({
|
|
157
|
+
id: call.id,
|
|
158
|
+
name: call.name,
|
|
159
|
+
arguments: call.argsBuffer || "{}",
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
function streamReplay(state) {
|
|
163
|
+
return replayForTurn(state.dialect, "stream", state.input.resolved.identity.modelId, state.accumulatedContent, finalToolCalls(state), {
|
|
164
|
+
reasoningContent: state.accumulatedReasoning,
|
|
165
|
+
reasoningDetails: state.accumulatedReasoningDetails,
|
|
166
|
+
nativeToolCalls: nativeToolCalls(state.toolCallBuffers),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function pendingToolEvents(state) {
|
|
170
|
+
const events = [];
|
|
171
|
+
for (const [rawIndex, call] of Object.entries(state.toolCallBuffers)) {
|
|
172
|
+
const index = Number(rawIndex);
|
|
173
|
+
if (state.emittedToolCallIndexes.has(index))
|
|
174
|
+
continue;
|
|
175
|
+
let args = {};
|
|
176
|
+
try {
|
|
177
|
+
args = JSON.parse(call.argsBuffer || "{}");
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
args = {};
|
|
181
|
+
}
|
|
182
|
+
state.emittedToolCallIndexes.add(index);
|
|
183
|
+
events.push({ type: "tool_call", id: call.id, name: call.name, arguments: args });
|
|
184
|
+
}
|
|
185
|
+
return events;
|
|
186
|
+
}
|
|
187
|
+
function numberField(raw, key) {
|
|
188
|
+
const value = raw[key];
|
|
189
|
+
if (value === undefined || value === null)
|
|
190
|
+
return undefined;
|
|
191
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
192
|
+
throw new ProtocolResponseError("openai-chat", `usage.${key} must be a non-negative finite number`);
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
4
196
|
export class OpenAIChatAdapter {
|
|
5
|
-
|
|
197
|
+
// Responses are decoded from the official Chat Completions message/chunk shapes. The adapter
|
|
198
|
+
// preserves pre-A-09 raw finish reasons; canonical stop mapping is exposed separately.
|
|
199
|
+
// Source: https://platform.openai.com/docs/api-reference/chat/create
|
|
200
|
+
protocol = "openai-chat";
|
|
201
|
+
protocolCapabilities = OPENAI_CHAT_PROTOCOL_CAPABILITIES;
|
|
202
|
+
buildRequest(input, dialect = openAIChatDialects.openai) {
|
|
203
|
+
const prepared = dialect.prepareExtensions(input.extensions);
|
|
204
|
+
const tools = [
|
|
205
|
+
...this.buildTools(input.tools),
|
|
206
|
+
...(dialect.serverTools?.(input.extensions) ?? []),
|
|
207
|
+
];
|
|
208
|
+
const cache = dialect.cacheKey === "openai"
|
|
209
|
+
? { prompt_cache_key: stablePromptCacheKey([
|
|
210
|
+
input.context.systemText,
|
|
211
|
+
input.tools.map(tool => tool.name).join(","),
|
|
212
|
+
]) }
|
|
213
|
+
: {};
|
|
214
|
+
return {
|
|
215
|
+
dialect,
|
|
216
|
+
preparedExtensions: prepared,
|
|
217
|
+
params: {
|
|
218
|
+
...cache,
|
|
219
|
+
...Object.fromEntries(Object.entries(prepared).filter(([key]) => key !== "__deepstrikeThinkingEnabled" && key !== "degradeMissingReasoningReplay")),
|
|
220
|
+
model: input.resolved.identity.modelId,
|
|
221
|
+
messages: messages(input, dialect, prepared),
|
|
222
|
+
...(tools.length ? { tools } : {}),
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
decodeComplete(raw, input, dialect = openAIChatDialects.openai) {
|
|
227
|
+
const choice = raw.choices?.[0]?.message ?? {};
|
|
228
|
+
const nativeCalls = choice.tool_calls ?? [];
|
|
229
|
+
const toolCalls = this.normalizeToolCalls(nativeCalls);
|
|
230
|
+
const content = choice.content ?? "";
|
|
231
|
+
const usage = raw.usage;
|
|
232
|
+
if (usage)
|
|
233
|
+
this.normalizeUsage(usage);
|
|
234
|
+
const message = {
|
|
235
|
+
role: "assistant",
|
|
236
|
+
content,
|
|
237
|
+
...(usage ? {
|
|
238
|
+
tokenCount: numberField(usage, "completion_tokens") ?? numberField(usage, "total_tokens"),
|
|
239
|
+
} : {}),
|
|
240
|
+
toolCalls,
|
|
241
|
+
};
|
|
242
|
+
const replay = replayForTurn(dialect, "complete", input.input.resolved.identity.modelId, content, toolCalls, {
|
|
243
|
+
reasoningContent: typeof choice.reasoning_content === "string" ? choice.reasoning_content : "",
|
|
244
|
+
reasoningDetails: choice.reasoning_details,
|
|
245
|
+
nativeToolCalls: nativeCalls,
|
|
246
|
+
});
|
|
247
|
+
return { message, ...(replay ? { replay } : {}) };
|
|
248
|
+
}
|
|
249
|
+
createStreamState(input, dialect = openAIChatDialects.openai) {
|
|
250
|
+
return {
|
|
251
|
+
input: input.input,
|
|
252
|
+
dialect,
|
|
253
|
+
toolCallBuffers: {},
|
|
254
|
+
emittedToolCallIndexes: new Set(),
|
|
255
|
+
extractor: new ThinkingTagStreamExtractor(),
|
|
256
|
+
accumulatedReasoning: "",
|
|
257
|
+
accumulatedContent: "",
|
|
258
|
+
totalTokens: 0,
|
|
259
|
+
inputTokens: 0,
|
|
260
|
+
outputTokens: 0,
|
|
261
|
+
cacheReadTokens: 0,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
pushStreamChunk(chunk, state) {
|
|
265
|
+
if (chunk.usage) {
|
|
266
|
+
state.totalTokens = chunk.usage.total_tokens;
|
|
267
|
+
state.inputTokens = chunk.usage.prompt_tokens ?? 0;
|
|
268
|
+
state.outputTokens = chunk.usage.completion_tokens ?? 0;
|
|
269
|
+
state.cacheReadTokens = openAICachedPromptTokens(chunk.usage);
|
|
270
|
+
state.rawUsage = chunk.usage;
|
|
271
|
+
return { events: [] };
|
|
272
|
+
}
|
|
273
|
+
const choice = chunk.choices?.[0];
|
|
274
|
+
if (!choice)
|
|
275
|
+
return { events: [] };
|
|
276
|
+
if (choice.finish_reason)
|
|
277
|
+
state.finishReason = choice.finish_reason;
|
|
278
|
+
const delta = choice.delta;
|
|
279
|
+
if (!delta)
|
|
280
|
+
return { events: [] };
|
|
281
|
+
const events = [];
|
|
282
|
+
if (delta.reasoning_content) {
|
|
283
|
+
state.accumulatedReasoning += String(delta.reasoning_content);
|
|
284
|
+
if (state.dialect.exposeReasoning(state.input.extensions)) {
|
|
285
|
+
events.push({ type: "thinking_delta", delta: String(delta.reasoning_content) });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (delta.reasoning_details !== undefined && delta.reasoning_details !== null) {
|
|
289
|
+
state.accumulatedReasoningDetails = delta.reasoning_details;
|
|
290
|
+
}
|
|
291
|
+
if (delta.content) {
|
|
292
|
+
if (state.dialect.inlineThinkingTags) {
|
|
293
|
+
for (const part of state.extractor.feed(String(delta.content))) {
|
|
294
|
+
if (part.type === "thinking") {
|
|
295
|
+
state.accumulatedReasoning += part.content;
|
|
296
|
+
events.push({ type: "thinking_delta", delta: part.content });
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
state.accumulatedContent += part.content;
|
|
300
|
+
events.push({ type: "text_delta", delta: part.content });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
state.accumulatedContent += String(delta.content);
|
|
306
|
+
events.push({ type: "text_delta", delta: String(delta.content) });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const call of delta.tool_calls ?? []) {
|
|
310
|
+
const index = call.index;
|
|
311
|
+
if (!state.toolCallBuffers[index]) {
|
|
312
|
+
state.toolCallBuffers[index] = { id: call.id ?? "", name: "", argsBuffer: "" };
|
|
313
|
+
}
|
|
314
|
+
if (call.function?.name)
|
|
315
|
+
state.toolCallBuffers[index].name += call.function.name;
|
|
316
|
+
state.toolCallBuffers[index].argsBuffer += call.function?.arguments ?? "";
|
|
317
|
+
}
|
|
318
|
+
if (choice.finish_reason === "tool_calls") {
|
|
319
|
+
events.push(...pendingToolEvents(state));
|
|
320
|
+
const replay = streamReplay(state);
|
|
321
|
+
return { events, ...(replay ? { replay } : {}) };
|
|
322
|
+
}
|
|
323
|
+
return { events };
|
|
324
|
+
}
|
|
325
|
+
finishStream(state) {
|
|
326
|
+
const events = [];
|
|
327
|
+
if (state.dialect.inlineThinkingTags) {
|
|
328
|
+
for (const part of state.extractor.flush()) {
|
|
329
|
+
if (part.type === "thinking") {
|
|
330
|
+
state.accumulatedReasoning += part.content;
|
|
331
|
+
events.push({ type: "thinking_delta", delta: part.content });
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
state.accumulatedContent += part.content;
|
|
335
|
+
events.push({ type: "text_delta", delta: part.content });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
events.push(...pendingToolEvents(state));
|
|
340
|
+
if (state.totalTokens > 0) {
|
|
341
|
+
const providerUsage = this.normalizeUsage(state.rawUsage);
|
|
342
|
+
const stopReason = this.normalizeStopReason(state.finishReason);
|
|
343
|
+
events.push({
|
|
344
|
+
type: "usage",
|
|
345
|
+
totalTokens: state.totalTokens,
|
|
346
|
+
inputTokens: state.inputTokens,
|
|
347
|
+
outputTokens: state.outputTokens,
|
|
348
|
+
...(state.cacheReadTokens > 0 ? { cacheReadInputTokens: state.cacheReadTokens } : {}),
|
|
349
|
+
...(stopReason ? { stopReason } : {}),
|
|
350
|
+
...(state.finishReason ? { rawStopReason: state.finishReason } : {}),
|
|
351
|
+
...(providerUsage ? { providerUsage } : {}),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
const replay = streamReplay(state);
|
|
355
|
+
return { events, ...(replay ? { replay } : {}) };
|
|
356
|
+
}
|
|
357
|
+
normalizeUsage(raw) {
|
|
358
|
+
if (raw === undefined || raw === null)
|
|
359
|
+
return undefined;
|
|
360
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
361
|
+
throw new ProtocolResponseError("openai-chat", "usage must be an object");
|
|
362
|
+
}
|
|
363
|
+
const usage = raw;
|
|
364
|
+
const inputTokens = numberField(usage, "prompt_tokens");
|
|
365
|
+
const outputTokens = numberField(usage, "completion_tokens");
|
|
366
|
+
numberField(usage, "total_tokens");
|
|
367
|
+
if (inputTokens === undefined && outputTokens === undefined)
|
|
368
|
+
return undefined;
|
|
369
|
+
const cacheReadInputTokens = openAICachedPromptTokens(usage);
|
|
370
|
+
const details = usage.completion_tokens_details;
|
|
371
|
+
const reasoningTokens = details && typeof details === "object"
|
|
372
|
+
? numberField(details, "reasoning_tokens")
|
|
373
|
+
: undefined;
|
|
374
|
+
return {
|
|
375
|
+
inputTokens: inputTokens ?? 0,
|
|
376
|
+
outputTokens: outputTokens ?? 0,
|
|
377
|
+
...(cacheReadInputTokens > 0 ? { cacheReadInputTokens } : {}),
|
|
378
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
normalizeStopReason(raw) {
|
|
382
|
+
if (raw === undefined)
|
|
383
|
+
return undefined;
|
|
384
|
+
if (raw === "length")
|
|
385
|
+
return "max_tokens";
|
|
386
|
+
if (raw === "stop")
|
|
387
|
+
return "end_turn";
|
|
388
|
+
if (raw === "tool_calls" || raw === "function_call")
|
|
389
|
+
return "tool_use";
|
|
390
|
+
if (raw === "content_filter")
|
|
391
|
+
return "content_filter";
|
|
392
|
+
return "other";
|
|
393
|
+
}
|
|
6
394
|
buildTools(tools) {
|
|
7
|
-
return tools.map(
|
|
395
|
+
return tools.map(tool => ({
|
|
8
396
|
type: "function",
|
|
9
|
-
function: {
|
|
397
|
+
function: {
|
|
398
|
+
name: tool.name,
|
|
399
|
+
description: tool.description,
|
|
400
|
+
parameters: JSON.parse(tool.parameters),
|
|
401
|
+
},
|
|
10
402
|
}));
|
|
11
403
|
}
|
|
12
404
|
buildMessages(context, options = {}) {
|
|
@@ -14,64 +406,39 @@ export class OpenAIChatAdapter {
|
|
|
14
406
|
descriptor: options.descriptor,
|
|
15
407
|
requireNonEmptyReasoningForToolCalls: options.requireNonEmptyReasoningForToolCalls,
|
|
16
408
|
degradeMissingReasoning: options.degradeMissingReasoning,
|
|
17
|
-
replayForAssistant: message => this.
|
|
409
|
+
replayForAssistant: message => compatibilityReplayStore(this).get(assistantReplayKey(message)),
|
|
18
410
|
});
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const replay = this.replayFields.get(assistantReplayKey(source));
|
|
32
|
-
let wireReplay = openAIChatWireReplayFields(replay);
|
|
33
|
-
if (!wireReplay && degradeReasoning && source.toolCalls?.length) {
|
|
34
|
-
// Reasoning-requiring provider, no stored reasoning for this tool-call
|
|
35
|
-
// turn, caller opted into degradation: inject a placeholder so the
|
|
36
|
-
// wire message stays well-formed instead of failing the whole request.
|
|
37
|
-
wireReplay = { reasoning_content: DEGRADED_REASONING_PLACEHOLDER };
|
|
38
|
-
}
|
|
39
|
-
if (wireReplay)
|
|
40
|
-
serialized[cursor] = { ...serialized[cursor], ...wireReplay };
|
|
41
|
-
}
|
|
42
|
-
cursor += 1;
|
|
43
|
-
}
|
|
44
|
-
return serialized;
|
|
411
|
+
const canonical = normalizeCanonicalContext(context, message => compatibilityReplayStore(this).get(assistantReplayKey(message)));
|
|
412
|
+
const dialect = {
|
|
413
|
+
...openAIChatDialects.openai,
|
|
414
|
+
descriptor: { reasoning: options.descriptor?.reasoning ?? openAIChatDialects.openai.descriptor.reasoning },
|
|
415
|
+
requireReasoningReplay: () => options.requireNonEmptyReasoningForToolCalls === true,
|
|
416
|
+
};
|
|
417
|
+
return messages({
|
|
418
|
+
context: canonical,
|
|
419
|
+
tools: [],
|
|
420
|
+
resolved: { identity: { modelId: options.descriptor?.model ?? "compat" } },
|
|
421
|
+
extensions: options.degradeMissingReasoning ? { degradeMissingReasoningReplay: true } : {},
|
|
422
|
+
}, dialect, options.degradeMissingReasoning ? { degradeMissingReasoningReplay: true } : {});
|
|
45
423
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Throw-free pre-flight check: which assistant tool-call turns in `context`
|
|
48
|
-
* lack the non-empty reasoning replay a reasoning-requiring provider needs.
|
|
49
|
-
*/
|
|
50
424
|
assessReasoning(context) {
|
|
51
425
|
return assessReasoningReplay(context.turns, {
|
|
52
|
-
replayForAssistant: message => this.
|
|
426
|
+
replayForAssistant: message => compatibilityReplayStore(this).get(assistantReplayKey(message)),
|
|
53
427
|
});
|
|
54
428
|
}
|
|
55
429
|
normalizeToolCalls(toolCalls = []) {
|
|
56
430
|
return toolCalls
|
|
57
|
-
.filter((
|
|
58
|
-
.map(
|
|
59
|
-
.filter(
|
|
431
|
+
.filter((call) => call.type === "function")
|
|
432
|
+
.map(call => normalizeToolCall(call.id, call.function.name, call.function.arguments))
|
|
433
|
+
.filter((call) => call !== null);
|
|
60
434
|
}
|
|
61
435
|
rememberReplayFields(message, fields) {
|
|
62
|
-
this.
|
|
436
|
+
compatibilityReplayStore(this).set(assistantReplayKey(message), {
|
|
437
|
+
protocol: "openai-chat",
|
|
438
|
+
...fields,
|
|
439
|
+
});
|
|
63
440
|
}
|
|
64
441
|
peekReplayFields(message) {
|
|
65
|
-
return this.
|
|
442
|
+
return compatibilityReplayStore(this).get(assistantReplayKey(message));
|
|
66
443
|
}
|
|
67
444
|
}
|
|
68
|
-
function openAIChatWireReplayFields(replay) {
|
|
69
|
-
if (!replay)
|
|
70
|
-
return undefined;
|
|
71
|
-
const fields = {};
|
|
72
|
-
if (typeof replay.reasoning_content === "string")
|
|
73
|
-
fields.reasoning_content = replay.reasoning_content;
|
|
74
|
-
if (replay.reasoning_details !== undefined)
|
|
75
|
-
fields.reasoning_details = replay.reasoning_details;
|
|
76
|
-
return Object.keys(fields).length ? fields : undefined;
|
|
77
|
-
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Message, ProviderUsage, RenderedContext, ToolCall, ToolSchema } from "../types.js";
|
|
2
|
+
import type { CanonicalAdapterInput } from "./content-normalization.js";
|
|
3
|
+
import { type AdapterDecodeInput, type AdapterOutput, type AdapterStreamInput, type CanonicalStopReason, type ProtocolAdapter } from "./protocol-adapter.js";
|
|
4
|
+
export interface OpenAIResponsesRunState {
|
|
5
|
+
previousResponseId?: string;
|
|
6
|
+
coveredMessageCount: number;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface OpenAIResponsesRequestPlan {
|
|
10
|
+
params: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export type OpenAIResponsesStreamChunk = Record<string, any>;
|
|
13
|
+
export interface OpenAIResponsesStreamState {
|
|
14
|
+
readonly input: CanonicalAdapterInput;
|
|
15
|
+
readonly functionCalls: Map<number, {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
argsBuffer: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
export declare class OpenAIResponsesAdapter implements ProtocolAdapter<OpenAIResponsesRequestPlan, Record<string, any>, OpenAIResponsesStreamChunk, OpenAIResponsesStreamState, undefined> {
|
|
22
|
+
readonly protocol: "openai-responses";
|
|
23
|
+
readonly protocolCapabilities: import("./protocol-capabilities.js").ProtocolRuntimeCapabilities;
|
|
24
|
+
buildRequest(input: CanonicalAdapterInput, state?: OpenAIResponsesRunState): OpenAIResponsesRequestPlan;
|
|
25
|
+
decodeComplete(raw: Record<string, any>, _input: AdapterDecodeInput): {
|
|
26
|
+
message: Message;
|
|
27
|
+
};
|
|
28
|
+
createStreamState(input: AdapterStreamInput, _state?: OpenAIResponsesRunState): OpenAIResponsesStreamState;
|
|
29
|
+
pushStreamChunk(chunk: OpenAIResponsesStreamChunk, state: OpenAIResponsesStreamState): AdapterOutput;
|
|
30
|
+
finishStream(_state: OpenAIResponsesStreamState): AdapterOutput;
|
|
31
|
+
normalizeUsage(raw: unknown): ProviderUsage | undefined;
|
|
32
|
+
normalizeStopReason(raw: string | undefined): CanonicalStopReason | undefined;
|
|
33
|
+
buildTools(tools: readonly ToolSchema[]): Array<Record<string, unknown>>;
|
|
34
|
+
buildInstructions(context: RenderedContext): string | undefined;
|
|
35
|
+
buildInput(context: RenderedContext, state?: OpenAIResponsesRunState): Array<Record<string, unknown>>;
|
|
36
|
+
decodeOutput(output: Array<Record<string, unknown>>): {
|
|
37
|
+
content: string;
|
|
38
|
+
toolCalls: ToolCall[];
|
|
39
|
+
};
|
|
40
|
+
builtinTools(extensions?: Record<string, unknown>): Record<string, unknown>[];
|
|
41
|
+
requestExtensions(extensions?: Record<string, unknown>): Record<string, unknown>;
|
|
42
|
+
}
|