@deepstrike/sdk 0.1.15 → 0.2.0
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/dist/collaboration/harness.d.ts +4 -1
- package/dist/collaboration/harness.js +20 -6
- package/dist/collaboration/modes/creator-verifier.d.ts +8 -2
- package/dist/collaboration/modes/creator-verifier.js +9 -3
- package/dist/collaboration/pool.d.ts +24 -3
- package/dist/collaboration/pool.js +65 -5
- package/dist/harness/harness.d.ts +5 -1
- package/dist/harness/harness.js +23 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +5 -0
- package/dist/kernel.d.ts +12 -43
- package/dist/kernel.js +1 -1
- package/dist/providers/anthropic.js +7 -2
- package/dist/providers/base.d.ts +12 -0
- package/dist/providers/base.js +75 -0
- package/dist/providers/catalog.d.ts +3 -2
- package/dist/providers/catalog.js +61 -13
- package/dist/providers/deepseek.js +1 -1
- package/dist/providers/gemini.d.ts +3 -0
- package/dist/providers/gemini.js +26 -6
- package/dist/providers/glm.d.ts +9 -0
- package/dist/providers/glm.js +21 -0
- package/dist/providers/kimi.js +2 -0
- package/dist/providers/minimax.js +5 -0
- package/dist/providers/openai-responses.js +9 -0
- package/dist/providers/openai.js +52 -6
- package/dist/providers/profiles.d.ts +1304 -242
- package/dist/providers/profiles.js +429 -26
- package/dist/providers/qwen.d.ts +3 -1
- package/dist/providers/qwen.js +43 -13
- package/dist/runtime/archive.d.ts +15 -0
- package/dist/runtime/archive.js +35 -0
- package/dist/runtime/execution-plane.js +14 -4
- package/dist/runtime/filtered-plane.d.ts +14 -0
- package/dist/runtime/filtered-plane.js +45 -0
- package/dist/runtime/kernel-step.d.ts +88 -0
- package/dist/runtime/kernel-step.js +262 -0
- package/dist/runtime/process-sandbox-plane.d.ts +4 -4
- package/dist/runtime/process-sandbox-plane.js +5 -5
- package/dist/runtime/provider-replay.js +37 -3
- package/dist/runtime/replay-sanitize.d.ts +5 -0
- package/dist/runtime/replay-sanitize.js +25 -0
- package/dist/runtime/runner.d.ts +60 -4
- package/dist/runtime/runner.js +589 -86
- package/dist/runtime/session-log.d.ts +93 -1
- package/dist/runtime/session-repair.d.ts +37 -0
- package/dist/runtime/session-repair.js +77 -0
- package/dist/runtime/sub-agent-orchestrator.d.ts +19 -0
- package/dist/runtime/sub-agent-orchestrator.js +114 -0
- package/dist/skills/watcher.d.ts +19 -0
- package/dist/skills/watcher.js +38 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.js +82 -11
- package/dist/types/agent.d.ts +68 -0
- package/dist/types/agent.js +78 -0
- package/dist/types.d.ts +27 -0
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AnthropicProvider } from "./anthropic.js";
|
|
1
2
|
import { OpenAIChatProvider } from "./openai.js";
|
|
2
3
|
import { DeepSeekProvider } from "./deepseek.js";
|
|
3
4
|
import { KimiProvider } from "./kimi.js";
|
|
@@ -5,20 +6,35 @@ import { OpenAIResponsesProvider } from "./openai-responses.js";
|
|
|
5
6
|
import { MiniMaxProvider } from "./minimax.js";
|
|
6
7
|
import { QwenProvider } from "./qwen.js";
|
|
7
8
|
import { GeminiProvider } from "./gemini.js";
|
|
8
|
-
import {
|
|
9
|
+
import { GLMProvider } from "./glm.js";
|
|
10
|
+
import { endpointProfiles, getModelProfile, modelProfiles } from "./profiles.js";
|
|
9
11
|
export function createProvider(options) {
|
|
10
|
-
const profile = getModelProfile(options.model);
|
|
11
|
-
const
|
|
12
|
+
const profile = isModelProfileId(options.model) ? getModelProfile(options.model) : undefined;
|
|
13
|
+
const parsedProviderId = providerPrefix(options.model);
|
|
14
|
+
const endpointId = (options.endpoint ?? profile?.defaultEndpointId ?? defaultEndpointForProvider(options.provider ?? parsedProviderId));
|
|
15
|
+
if (!endpointId) {
|
|
16
|
+
throw new Error(`Unknown model profile: ${options.model}. Pass provider or endpoint for custom model names.`);
|
|
17
|
+
}
|
|
12
18
|
const endpoint = endpointProfiles[endpointId];
|
|
13
19
|
if (!endpoint) {
|
|
14
20
|
throw new Error(`Unknown endpoint profile: ${endpointId}`);
|
|
15
21
|
}
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
const providerId = profile?.providerId ?? options.provider ?? parsedProviderId ?? endpoint.providerId;
|
|
23
|
+
if (profile && options.provider && options.provider !== profile.providerId) {
|
|
24
|
+
throw new Error(`Model ${profile.id} belongs to provider ${profile.providerId}, not ${options.provider}`);
|
|
25
|
+
}
|
|
26
|
+
if (parsedProviderId && options.provider && parsedProviderId !== options.provider) {
|
|
27
|
+
throw new Error(`Model ${options.model} uses provider prefix ${parsedProviderId}, not ${options.provider}`);
|
|
28
|
+
}
|
|
29
|
+
if (endpoint.providerId !== providerId) {
|
|
30
|
+
throw new Error(`Endpoint ${endpoint.id} does not belong to provider ${providerId}`);
|
|
18
31
|
}
|
|
19
|
-
const model = options.model
|
|
32
|
+
const model = modelNameForProvider(options.model, providerId);
|
|
20
33
|
const baseURL = options.baseURL ?? endpoint.baseURL;
|
|
21
|
-
if (
|
|
34
|
+
if (providerId === "anthropic" && endpoint.protocol === "anthropic-messages") {
|
|
35
|
+
return new AnthropicProvider(options.apiKey, model, options.retry, { baseURL });
|
|
36
|
+
}
|
|
37
|
+
if (providerId === "openai") {
|
|
22
38
|
if (endpoint.protocol === "openai-chat") {
|
|
23
39
|
return new OpenAIChatProvider(options.apiKey, model, options.retry, baseURL);
|
|
24
40
|
}
|
|
@@ -26,20 +42,52 @@ export function createProvider(options) {
|
|
|
26
42
|
return new OpenAIResponsesProvider(options.apiKey, model, options.retry, baseURL);
|
|
27
43
|
}
|
|
28
44
|
}
|
|
29
|
-
if (
|
|
45
|
+
if (providerId === "minimax" && endpoint.protocol === "anthropic-messages") {
|
|
30
46
|
return new MiniMaxProvider(options.apiKey, model, options.retry, baseURL);
|
|
31
47
|
}
|
|
32
|
-
if (
|
|
48
|
+
if (providerId === "deepseek" && endpoint.protocol === "openai-chat") {
|
|
33
49
|
return new DeepSeekProvider(options.apiKey, model, options.retry, baseURL);
|
|
34
50
|
}
|
|
35
|
-
if (
|
|
51
|
+
if (providerId === "kimi" && endpoint.protocol === "openai-chat") {
|
|
36
52
|
return new KimiProvider(options.apiKey, model, options.retry, baseURL);
|
|
37
53
|
}
|
|
38
|
-
if (
|
|
54
|
+
if (providerId === "qwen" && endpoint.protocol === "openai-chat") {
|
|
39
55
|
return new QwenProvider(options.apiKey, model, options.retry, baseURL);
|
|
40
56
|
}
|
|
41
|
-
if (
|
|
57
|
+
if (providerId === "gemini" && endpoint.protocol === "gemini") {
|
|
42
58
|
return new GeminiProvider(options.apiKey, model, options.retry, baseURL);
|
|
43
59
|
}
|
|
44
|
-
|
|
60
|
+
if (providerId === "glm" && endpoint.protocol === "openai-chat") {
|
|
61
|
+
return new GLMProvider(options.apiKey, model, options.retry, baseURL);
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`No Node provider factory for ${options.model} on ${endpoint.id}`);
|
|
64
|
+
}
|
|
65
|
+
function isModelProfileId(model) {
|
|
66
|
+
return Object.prototype.hasOwnProperty.call(modelProfiles, model);
|
|
67
|
+
}
|
|
68
|
+
function providerPrefix(model) {
|
|
69
|
+
const [prefix] = model.split("/", 1);
|
|
70
|
+
return providerIds().includes(prefix) ? prefix : undefined;
|
|
71
|
+
}
|
|
72
|
+
function providerIds() {
|
|
73
|
+
return Array.from(new Set(Object.values(endpointProfiles).map(endpoint => endpoint.providerId)));
|
|
74
|
+
}
|
|
75
|
+
function defaultEndpointForProvider(providerId) {
|
|
76
|
+
if (!providerId)
|
|
77
|
+
return undefined;
|
|
78
|
+
const defaults = {
|
|
79
|
+
anthropic: "anthropic.messages",
|
|
80
|
+
openai: "openai.chat",
|
|
81
|
+
minimax: "minimax.anthropic",
|
|
82
|
+
deepseek: "deepseek.openai",
|
|
83
|
+
kimi: "kimi.openai",
|
|
84
|
+
qwen: "qwen.dashscope",
|
|
85
|
+
gemini: "gemini.google",
|
|
86
|
+
glm: "glm.openai",
|
|
87
|
+
};
|
|
88
|
+
return defaults[providerId];
|
|
89
|
+
}
|
|
90
|
+
function modelNameForProvider(model, providerId) {
|
|
91
|
+
const prefix = `${providerId}/`;
|
|
92
|
+
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
|
|
45
93
|
}
|
|
@@ -91,7 +91,7 @@ export class DeepSeekProvider extends OpenAIChatProvider {
|
|
|
91
91
|
const toolCalls = Object.values(toolCallBufs).map(tb => ({
|
|
92
92
|
id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
|
|
93
93
|
}));
|
|
94
|
-
if (toolCalls.length) {
|
|
94
|
+
if (toolCalls.length || reasoningContent) {
|
|
95
95
|
this.chat.rememberReplayFields({ content: finalText, toolCalls }, { reasoning_content: reasoningContent });
|
|
96
96
|
}
|
|
97
97
|
for (const [index, tb] of Object.entries(toolCallBufs)) {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { type Content } from "@google/generative-ai";
|
|
1
2
|
import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
|
|
3
|
+
export declare function buildContents(turns: Message[]): Content[];
|
|
2
4
|
export declare class GeminiProvider implements LLMProvider {
|
|
3
5
|
private readonly model;
|
|
4
6
|
private genAI;
|
|
5
7
|
private circuit;
|
|
6
8
|
private maxRetries;
|
|
7
9
|
private baseDelay;
|
|
10
|
+
private requestOptions;
|
|
8
11
|
constructor(apiKey: string, model?: string, retry?: {
|
|
9
12
|
maxRetries: number;
|
|
10
13
|
baseDelay: number;
|
package/dist/providers/gemini.js
CHANGED
|
@@ -4,6 +4,9 @@ import { CircuitBreaker, normalizeToolCall } from "./base.js";
|
|
|
4
4
|
import { endpointProfiles } from "./profiles.js";
|
|
5
5
|
const GEMINI_BASE = endpointProfiles["gemini.google"].baseURL;
|
|
6
6
|
const GEMINI_POLICIES = {
|
|
7
|
+
"gemini-3-pro-preview": { maxTurns: 50 },
|
|
8
|
+
"gemini-3-flash-preview": { maxTurns: 25 },
|
|
9
|
+
"gemini-3.5-flash": { maxTurns: 30 },
|
|
7
10
|
"gemini-2.5-pro": { maxTurns: 35 },
|
|
8
11
|
"gemini-2.5-flash": { maxTurns: 20 },
|
|
9
12
|
"gemini-2.0-flash": { maxTurns: 15 },
|
|
@@ -11,15 +14,30 @@ const GEMINI_POLICIES = {
|
|
|
11
14
|
"gemini-1.5-pro": { maxTurns: 30 },
|
|
12
15
|
"gemini-1.5-flash": { maxTurns: 15 },
|
|
13
16
|
};
|
|
14
|
-
function buildContents(turns) {
|
|
17
|
+
export function buildContents(turns) {
|
|
15
18
|
const contents = [];
|
|
16
19
|
for (const msg of turns) {
|
|
17
20
|
if (msg.role === "tool") {
|
|
18
21
|
const parts = (msg.contentParts ?? [])
|
|
19
22
|
.filter(p => p.type === "tool_result")
|
|
20
|
-
.map(p =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
.map(p => {
|
|
24
|
+
if (p.type !== "tool_result")
|
|
25
|
+
return { text: "" };
|
|
26
|
+
let toolName = p.callId;
|
|
27
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
28
|
+
const turn = turns[i];
|
|
29
|
+
if (turn.role === "assistant" && turn.toolCalls) {
|
|
30
|
+
const matched = turn.toolCalls.find(tc => tc.id === p.callId);
|
|
31
|
+
if (matched) {
|
|
32
|
+
toolName = matched.name;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
functionResponse: { name: toolName, response: { output: p.output } },
|
|
39
|
+
};
|
|
40
|
+
});
|
|
23
41
|
if (parts.length)
|
|
24
42
|
contents.push({ role: "user", parts });
|
|
25
43
|
continue;
|
|
@@ -62,12 +80,14 @@ export class GeminiProvider {
|
|
|
62
80
|
circuit;
|
|
63
81
|
maxRetries;
|
|
64
82
|
baseDelay;
|
|
83
|
+
requestOptions;
|
|
65
84
|
constructor(apiKey, model = "gemini-2.0-flash", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = GEMINI_BASE) {
|
|
66
85
|
this.model = model;
|
|
67
86
|
this.genAI = withServerRuntimeGuard(() => new GoogleGenerativeAI(apiKey));
|
|
68
87
|
this.circuit = new CircuitBreaker();
|
|
69
88
|
this.maxRetries = retry.maxRetries;
|
|
70
89
|
this.baseDelay = retry.baseDelay;
|
|
90
|
+
this.requestOptions = { baseUrl: baseURL };
|
|
71
91
|
}
|
|
72
92
|
runtimePolicy() {
|
|
73
93
|
return GEMINI_POLICIES[this.model] ?? {};
|
|
@@ -86,7 +106,7 @@ export class GeminiProvider {
|
|
|
86
106
|
model: this.model,
|
|
87
107
|
...(system ? { systemInstruction: system } : {}),
|
|
88
108
|
...(geminiTools.length ? { tools: geminiTools } : {}),
|
|
89
|
-
});
|
|
109
|
+
}, this.requestOptions);
|
|
90
110
|
const resp = await m.generateContent({ contents });
|
|
91
111
|
this.circuit.recordSuccess();
|
|
92
112
|
const candidate = resp.response.candidates?.[0];
|
|
@@ -127,7 +147,7 @@ export class GeminiProvider {
|
|
|
127
147
|
model: this.model,
|
|
128
148
|
...(system ? { systemInstruction: system } : {}),
|
|
129
149
|
...(geminiTools.length ? { tools: geminiTools } : {}),
|
|
130
|
-
});
|
|
150
|
+
}, this.requestOptions);
|
|
131
151
|
const result = await m.generateContentStream({ contents });
|
|
132
152
|
const toolCalls = [];
|
|
133
153
|
for await (const chunk of result.stream) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RuntimePolicy } from "../types.js";
|
|
2
|
+
import { OpenAIChatProvider } from "./openai.js";
|
|
3
|
+
export declare class GLMProvider extends OpenAIChatProvider {
|
|
4
|
+
constructor(apiKey: string, model?: string, retry?: {
|
|
5
|
+
maxRetries: number;
|
|
6
|
+
baseDelay: number;
|
|
7
|
+
}, baseURL?: string);
|
|
8
|
+
runtimePolicy(): RuntimePolicy;
|
|
9
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { OpenAIChatProvider } from "./openai.js";
|
|
2
|
+
import { endpointProfiles } from "./profiles.js";
|
|
3
|
+
const GLM_BASE = endpointProfiles["glm.openai"].baseURL;
|
|
4
|
+
const GLM_POLICIES = {
|
|
5
|
+
"glm-5.1": { maxTurns: 50 },
|
|
6
|
+
"glm/glm-5.1": { maxTurns: 50 },
|
|
7
|
+
"glm-4-plus": { maxTurns: 35 },
|
|
8
|
+
"glm/glm-4-plus": { maxTurns: 35 },
|
|
9
|
+
"glm-4-flash": { maxTurns: 15 },
|
|
10
|
+
"glm/glm-4-flash": { maxTurns: 15 },
|
|
11
|
+
"glm-4-air": { maxTurns: 20 },
|
|
12
|
+
"glm/glm-4-air": { maxTurns: 20 },
|
|
13
|
+
};
|
|
14
|
+
export class GLMProvider extends OpenAIChatProvider {
|
|
15
|
+
constructor(apiKey, model = "glm-5.1", retry, baseURL = GLM_BASE) {
|
|
16
|
+
super(apiKey, model, retry, baseURL);
|
|
17
|
+
}
|
|
18
|
+
runtimePolicy() {
|
|
19
|
+
return GLM_POLICIES[this.model] ?? {};
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/providers/kimi.js
CHANGED
|
@@ -7,6 +7,8 @@ const KIMI_POLICIES = {
|
|
|
7
7
|
"moonshot-v1-128k": { maxTurns: 30 },
|
|
8
8
|
"kimi-k2.5": { maxTurns: 30 },
|
|
9
9
|
"kimi-k2.6": { maxTurns: 35 },
|
|
10
|
+
"kimi-k2-thinking": { maxTurns: 50 },
|
|
11
|
+
"kimi-k2-thinking-turbo": { maxTurns: 40 },
|
|
10
12
|
};
|
|
11
13
|
export class KimiProvider extends OpenAIChatProvider {
|
|
12
14
|
constructor(apiKey, model = "kimi-k2.6", retry, baseURL = MOONSHOT_BASE) {
|
|
@@ -2,7 +2,12 @@ import { AnthropicProvider } from "./anthropic.js";
|
|
|
2
2
|
import { endpointProfiles } from "./profiles.js";
|
|
3
3
|
const MINIMAX_POLICIES = {
|
|
4
4
|
"MiniMax-M2.7": { maxTurns: 35 },
|
|
5
|
+
"MiniMax-M2.7-highspeed": { maxTurns: 35 },
|
|
5
6
|
"MiniMax-M2.5": { maxTurns: 25 },
|
|
7
|
+
"MiniMax-M2.5-highspeed": { maxTurns: 25 },
|
|
8
|
+
"MiniMax-M2.1": { maxTurns: 25 },
|
|
9
|
+
"MiniMax-M2.1-highspeed": { maxTurns: 25 },
|
|
10
|
+
"MiniMax-M2": { maxTurns: 20 },
|
|
6
11
|
"MiniMax-Text-01": { maxTurns: 20 },
|
|
7
12
|
};
|
|
8
13
|
export class MiniMaxProvider extends AnthropicProvider {
|
|
@@ -115,11 +115,20 @@ export class OpenAIResponsesProvider {
|
|
|
115
115
|
}
|
|
116
116
|
runtimePolicy() {
|
|
117
117
|
const table = {
|
|
118
|
+
"gpt-5.5": { maxTurns: 60 },
|
|
119
|
+
"gpt-5.4": { maxTurns: 50 },
|
|
120
|
+
"gpt-5.4-mini": { maxTurns: 25 },
|
|
121
|
+
"gpt-5.4-nano": { maxTurns: 15 },
|
|
122
|
+
"gpt-5.2": { maxTurns: 50 },
|
|
123
|
+
"gpt-5.2-pro": { maxTurns: 60 },
|
|
124
|
+
"gpt-5.1": { maxTurns: 50 },
|
|
118
125
|
"gpt-4.1": { maxTurns: 35 },
|
|
119
126
|
"gpt-4.1-mini": { maxTurns: 20 },
|
|
120
127
|
"gpt-4.1-nano": { maxTurns: 15 },
|
|
121
128
|
"gpt-5": { maxTurns: 50 },
|
|
129
|
+
"gpt-5-pro": { maxTurns: 60 },
|
|
122
130
|
"gpt-5-mini": { maxTurns: 25 },
|
|
131
|
+
"gpt-5-nano": { maxTurns: 15 },
|
|
123
132
|
"o3": { maxTurns: 50 },
|
|
124
133
|
"o3-mini": { maxTurns: 25 },
|
|
125
134
|
"o4-mini": { maxTurns: 25 },
|
package/dist/providers/openai.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
2
|
import { withServerRuntimeGuard } from "../runtime/server.js";
|
|
3
|
-
import { CircuitBreaker, omitExtensionKeys } from "./base.js";
|
|
3
|
+
import { CircuitBreaker, omitExtensionKeys, ThinkingTagStreamExtractor } from "./base.js";
|
|
4
4
|
import { OpenAIChatAdapter } from "./openai-chat.js";
|
|
5
5
|
const OPENAI_POLICIES = {
|
|
6
|
+
"gpt-5.5": { maxTurns: 60 },
|
|
7
|
+
"gpt-5.4": { maxTurns: 50 },
|
|
8
|
+
"gpt-5.4-mini": { maxTurns: 25 },
|
|
9
|
+
"gpt-5.4-nano": { maxTurns: 15 },
|
|
10
|
+
"gpt-5.2": { maxTurns: 50 },
|
|
11
|
+
"gpt-5.2-pro": { maxTurns: 60 },
|
|
12
|
+
"gpt-5.1": { maxTurns: 50 },
|
|
6
13
|
"gpt-4o": { maxTurns: 25 },
|
|
7
14
|
"gpt-4o-mini": { maxTurns: 15 },
|
|
8
15
|
"gpt-4.1": { maxTurns: 35 },
|
|
9
16
|
"gpt-4.1-mini": { maxTurns: 20 },
|
|
10
17
|
"gpt-4.1-nano": { maxTurns: 15 },
|
|
11
18
|
"gpt-5": { maxTurns: 50 },
|
|
19
|
+
"gpt-5-pro": { maxTurns: 60 },
|
|
12
20
|
"gpt-5-mini": { maxTurns: 25 },
|
|
21
|
+
"gpt-5-nano": { maxTurns: 15 },
|
|
13
22
|
"o1": { maxTurns: 50 },
|
|
14
23
|
"o1-mini": { maxTurns: 25 },
|
|
15
24
|
"o3": { maxTurns: 50 },
|
|
@@ -35,12 +44,12 @@ export class OpenAIChatProvider {
|
|
|
35
44
|
}
|
|
36
45
|
peekProviderReplay(message) {
|
|
37
46
|
const fields = this.chat.peekReplayFields(message);
|
|
38
|
-
if (!fields
|
|
47
|
+
if (!fields || !("reasoning_content" in fields))
|
|
39
48
|
return undefined;
|
|
40
|
-
return { reasoning_content: String(fields.reasoning_content) };
|
|
49
|
+
return { reasoning_content: String(fields.reasoning_content ?? "") };
|
|
41
50
|
}
|
|
42
51
|
seedProviderReplay(message, replay) {
|
|
43
|
-
if (replay.reasoning_content) {
|
|
52
|
+
if (replay.reasoning_content !== undefined) {
|
|
44
53
|
this.chat.rememberReplayFields(message, { reasoning_content: replay.reasoning_content });
|
|
45
54
|
}
|
|
46
55
|
}
|
|
@@ -75,6 +84,9 @@ export class OpenAIChatProvider {
|
|
|
75
84
|
const msgs = this.chat.buildMessages(context);
|
|
76
85
|
const toolCallBufs = {};
|
|
77
86
|
const emittedToolCallIndexes = new Set();
|
|
87
|
+
const extractor = new ThinkingTagStreamExtractor();
|
|
88
|
+
let accumulatedReasoning = "";
|
|
89
|
+
let accumulatedContent = "";
|
|
78
90
|
const stream = await this.client.chat.completions.create({
|
|
79
91
|
...this.requestExtensions(extensions),
|
|
80
92
|
model: this.model,
|
|
@@ -93,8 +105,22 @@ export class OpenAIChatProvider {
|
|
|
93
105
|
if (!choice)
|
|
94
106
|
continue;
|
|
95
107
|
const delta = choice.delta;
|
|
96
|
-
if (delta.
|
|
97
|
-
|
|
108
|
+
if (delta.reasoning_content) {
|
|
109
|
+
accumulatedReasoning += delta.reasoning_content;
|
|
110
|
+
yield { type: "thinking_delta", delta: delta.reasoning_content };
|
|
111
|
+
}
|
|
112
|
+
if (delta.content) {
|
|
113
|
+
for (const part of extractor.feed(delta.content)) {
|
|
114
|
+
if (part.type === "thinking") {
|
|
115
|
+
accumulatedReasoning += part.content;
|
|
116
|
+
yield { type: "thinking_delta", delta: part.content };
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
accumulatedContent += part.content;
|
|
120
|
+
yield { type: "text_delta", delta: part.content };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
98
124
|
for (const tc of delta.tool_calls ?? []) {
|
|
99
125
|
const idx = tc.index;
|
|
100
126
|
if (!toolCallBufs[idx])
|
|
@@ -104,6 +130,10 @@ export class OpenAIChatProvider {
|
|
|
104
130
|
toolCallBufs[idx].argsBuf += tc.function?.arguments ?? "";
|
|
105
131
|
}
|
|
106
132
|
if (choice.finish_reason === "tool_calls") {
|
|
133
|
+
const toolCalls = Object.values(toolCallBufs).map(tb => ({
|
|
134
|
+
id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
|
|
135
|
+
}));
|
|
136
|
+
this.chat.rememberReplayFields({ content: accumulatedContent, toolCalls }, { reasoning_content: accumulatedReasoning });
|
|
107
137
|
for (const [index, tb] of Object.entries(toolCallBufs)) {
|
|
108
138
|
const idx = Number(index);
|
|
109
139
|
if (emittedToolCallIndexes.has(idx))
|
|
@@ -120,6 +150,22 @@ export class OpenAIChatProvider {
|
|
|
120
150
|
}
|
|
121
151
|
}
|
|
122
152
|
}
|
|
153
|
+
for (const part of extractor.flush()) {
|
|
154
|
+
if (part.type === "thinking") {
|
|
155
|
+
accumulatedReasoning += part.content;
|
|
156
|
+
yield { type: "thinking_delta", delta: part.content };
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
accumulatedContent += part.content;
|
|
160
|
+
yield { type: "text_delta", delta: part.content };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const toolCalls = Object.values(toolCallBufs).map(tb => ({
|
|
164
|
+
id: tb.id, name: tb.name, arguments: tb.argsBuf || "{}",
|
|
165
|
+
}));
|
|
166
|
+
if (toolCalls.length || accumulatedReasoning) {
|
|
167
|
+
this.chat.rememberReplayFields({ content: accumulatedContent, toolCalls }, { reasoning_content: accumulatedReasoning });
|
|
168
|
+
}
|
|
123
169
|
for (const [index, tb] of Object.entries(toolCallBufs)) {
|
|
124
170
|
const idx = Number(index);
|
|
125
171
|
if (emittedToolCallIndexes.has(idx))
|