@deepstrike/sdk 0.2.52 → 0.2.61
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/os/public.d.ts +1 -1
- package/dist/os/public.js +1 -1
- package/dist/providers/anthropic-adapter.d.ts +59 -0
- package/dist/providers/anthropic-adapter.js +530 -0
- package/dist/providers/anthropic-compatible.d.ts +2 -3
- package/dist/providers/anthropic-compatible.js +8 -5
- package/dist/providers/anthropic.d.ts +20 -23
- package/dist/providers/anthropic.js +176 -395
- package/dist/providers/base.d.ts +2 -2
- package/dist/providers/base.js +50 -8
- 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 -36
- 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 +25 -9
- package/dist/providers/gemini-adapter.d.ts +33 -0
- package/dist/providers/gemini-adapter.js +264 -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 +119 -0
- package/dist/providers/model-registry.js +379 -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 +416 -51
- package/dist/providers/openai-responses-adapter.d.ts +42 -0
- package/dist/providers/openai-responses-adapter.js +343 -0
- package/dist/providers/openai-responses.d.ts +19 -33
- package/dist/providers/openai-responses.js +164 -264
- package/dist/providers/openai.d.ts +29 -76
- package/dist/providers/openai.js +195 -292
- package/dist/providers/protocol-adapter.d.ts +39 -0
- package/dist/providers/protocol-adapter.js +13 -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 +153 -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 +89 -0
- package/dist/providers/request-plan.js +199 -0
- package/dist/providers/usage-normalizer.d.ts +48 -0
- package/dist/providers/usage-normalizer.js +139 -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 +1 -2
- package/dist/runtime/canonical-kernel-step.js +47 -12
- 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 +5 -1
- package/dist/runtime/provider-replay.js +26 -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 +31 -45
- package/dist/runtime/runner.js +178 -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 +135 -17
- package/package.json +4 -4
- 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
package/dist/providers/ollama.js
CHANGED
|
@@ -1,129 +1,116 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
["qwq", { maxTurns: 35 }],
|
|
6
|
-
["llama3.3", { maxTurns: 25 }],
|
|
7
|
-
["llama3.2", { maxTurns: 20 }],
|
|
8
|
-
["llama3.1", { maxTurns: 20 }],
|
|
9
|
-
["llama3", { maxTurns: 20 }],
|
|
10
|
-
["mistral", { maxTurns: 20 }],
|
|
11
|
-
["gemma2", { maxTurns: 20 }],
|
|
12
|
-
["phi4", { maxTurns: 20 }],
|
|
13
|
-
["phi3", { maxTurns: 15 }],
|
|
14
|
-
["codellama", { maxTurns: 20 }],
|
|
15
|
-
];
|
|
1
|
+
import { normalizeCanonicalAdapterInput, } from "./content-normalization.js";
|
|
2
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
3
|
+
import { OllamaAdapter } from "./ollama-adapter.js";
|
|
4
|
+
import { classifyProviderError, ProviderError } from "./provider-error.js";
|
|
16
5
|
export class OllamaProvider {
|
|
17
6
|
model;
|
|
18
7
|
baseUrl;
|
|
19
|
-
|
|
8
|
+
resolvedRuntimePolicy;
|
|
9
|
+
resolvedRuntime;
|
|
10
|
+
adapter = new OllamaAdapter();
|
|
11
|
+
constructor(model = "llama3", baseUrl = "http://localhost:11434", resolvedRuntimePolicy = {}, resolvedRuntime) {
|
|
20
12
|
this.model = model;
|
|
21
13
|
this.baseUrl = baseUrl;
|
|
14
|
+
this.resolvedRuntimePolicy = resolvedRuntimePolicy;
|
|
15
|
+
this.resolvedRuntime = resolvedRuntime;
|
|
22
16
|
}
|
|
23
17
|
runtimePolicy() {
|
|
24
|
-
|
|
25
|
-
for (const [prefix, policy] of OLLAMA_PREFIX_POLICIES) {
|
|
26
|
-
if (m.startsWith(prefix))
|
|
27
|
-
return policy;
|
|
28
|
-
}
|
|
29
|
-
return { maxTurns: 20 };
|
|
18
|
+
return this.resolvedRuntimePolicy;
|
|
30
19
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
for (const m of turnsWithStateAppended(context)) {
|
|
36
|
-
const images = [];
|
|
37
|
-
if (m.contentParts?.length) {
|
|
38
|
-
for (const p of m.contentParts) {
|
|
39
|
-
if (p.type === "image" && p.data)
|
|
40
|
-
images.push(p.data);
|
|
41
|
-
else if (p.type === "audio")
|
|
42
|
-
throw new UnsupportedModalityError("audio", "ollama");
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
result.push({ role: m.role, content: m.content, ...(images.length ? { images } : {}) });
|
|
20
|
+
bindResolvedRuntime(resolved) {
|
|
21
|
+
if (resolved.identity.protocol !== "ollama-chat"
|
|
22
|
+
|| resolved.identity.modelId !== this.model) {
|
|
23
|
+
throw new Error("OllamaProvider received a mismatched resolved runtime");
|
|
46
24
|
}
|
|
47
|
-
|
|
25
|
+
this.resolvedRuntime = resolved;
|
|
48
26
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
27
|
+
adapterInput(context, tools, extensions) {
|
|
28
|
+
const resolved = this.resolvedRuntime ?? {
|
|
29
|
+
identity: {
|
|
30
|
+
providerId: "ollama",
|
|
31
|
+
modelId: this.model,
|
|
32
|
+
endpointId: "ollama.local",
|
|
33
|
+
protocol: "ollama-chat",
|
|
34
|
+
},
|
|
35
|
+
model: { id: `ollama/${this.model}`, providerId: "ollama", kind: "generation", intrinsic: {} },
|
|
36
|
+
endpoint: endpointProfiles["ollama.local"],
|
|
37
|
+
adapter: this,
|
|
38
|
+
effectiveCapabilities: {
|
|
39
|
+
inputModalities: Object.fromEntries(["text", "image", "audio", "video", "file"].map(modality => [modality, { state: modality === "audio" || modality === "video" || modality === "file" ? "unsupported" : "unknown", evidence: [] }])),
|
|
40
|
+
outputModalities: Object.fromEntries(["text", "image", "audio", "embedding"].map(modality => [modality, { state: "unknown", evidence: [] }])),
|
|
41
|
+
tools: { state: "unknown", evidence: [] },
|
|
42
|
+
reasoning: { state: "unknown", evidence: [] },
|
|
43
|
+
parallelToolCalls: { state: "unknown", evidence: [] },
|
|
44
|
+
structuredOutput: { state: "unknown", evidence: [] },
|
|
45
|
+
promptCaching: { state: "unknown", evidence: [] },
|
|
46
|
+
nativeTokenCounting: { state: "unknown", evidence: [] },
|
|
47
|
+
mediaForms: Object.fromEntries(["imageUrl", "imageBase64", "fileId", "audioUrl", "audioBase64"].map(form => [form, { state: "unknown", evidence: [] }])),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
return normalizeCanonicalAdapterInput({ context, tools, resolved, extensions });
|
|
57
51
|
}
|
|
58
52
|
async complete(context, tools, extensions) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
53
|
+
try {
|
|
54
|
+
const input = this.adapterInput(context, tools, extensions);
|
|
55
|
+
const body = { ...this.adapter.buildRequest(input), stream: false };
|
|
56
|
+
const resp = await fetch(`${this.baseUrl}/api/chat`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify(body),
|
|
60
|
+
});
|
|
61
|
+
if (!resp.ok)
|
|
62
|
+
throw ollamaHttpError(resp.status);
|
|
63
|
+
const data = await resp.json();
|
|
64
|
+
return this.adapter.decodeComplete(data, { input }).message;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw classifyProviderError("ollama", error);
|
|
68
|
+
}
|
|
74
69
|
}
|
|
75
70
|
async *stream(context, tools, extensions) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (chunk.message?.content)
|
|
106
|
-
yield { type: "text_delta", delta: chunk.message.content };
|
|
107
|
-
for (const tc of chunk.message?.tool_calls ?? []) {
|
|
108
|
-
const norm = normalizeToolCall("", tc.function.name, tc.function.arguments);
|
|
109
|
-
if (!norm)
|
|
110
|
-
continue;
|
|
111
|
-
const args = JSON.parse(norm.arguments);
|
|
112
|
-
const key = `${norm.name}:${norm.arguments}`;
|
|
113
|
-
if (!pendingToolCalls.has(key)) {
|
|
114
|
-
pendingToolCalls.set(key, {
|
|
115
|
-
id: `call_${pendingToolCalls.size + 1}`,
|
|
116
|
-
name: norm.name,
|
|
117
|
-
arguments: args,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
71
|
+
try {
|
|
72
|
+
const input = this.adapterInput(context, tools, extensions);
|
|
73
|
+
const body = { ...this.adapter.buildRequest(input), stream: true };
|
|
74
|
+
const resp = await fetch(`${this.baseUrl}/api/chat`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: { "Content-Type": "application/json" },
|
|
77
|
+
body: JSON.stringify(body),
|
|
78
|
+
});
|
|
79
|
+
if (!resp.ok)
|
|
80
|
+
throw ollamaHttpError(resp.status);
|
|
81
|
+
if (!resp.body) {
|
|
82
|
+
throw new ProviderError({
|
|
83
|
+
provider: "ollama",
|
|
84
|
+
kind: "protocol",
|
|
85
|
+
retryable: false,
|
|
86
|
+
message: "Ollama stream response has no body",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const reader = resp.body.getReader();
|
|
90
|
+
const decoder = new TextDecoder();
|
|
91
|
+
const ndjson = this.adapter.createNdjsonDecoder();
|
|
92
|
+
const state = this.adapter.createStreamState({ input });
|
|
93
|
+
while (true) {
|
|
94
|
+
const { done, value } = await reader.read();
|
|
95
|
+
if (done)
|
|
96
|
+
break;
|
|
97
|
+
for (const chunk of ndjson.push(decoder.decode(value, { stream: true }))) {
|
|
98
|
+
for (const event of this.adapter.pushStreamChunk(chunk, state).events)
|
|
99
|
+
yield event;
|
|
121
100
|
}
|
|
122
|
-
catch { /* skip malformed lines */ }
|
|
123
101
|
}
|
|
102
|
+
for (const chunk of ndjson.finish(decoder.decode())) {
|
|
103
|
+
for (const event of this.adapter.pushStreamChunk(chunk, state).events)
|
|
104
|
+
yield event;
|
|
105
|
+
}
|
|
106
|
+
for (const event of this.adapter.finishStream(state, state.finalChunk).events)
|
|
107
|
+
yield event;
|
|
124
108
|
}
|
|
125
|
-
|
|
126
|
-
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw classifyProviderError("ollama", error);
|
|
127
111
|
}
|
|
128
112
|
}
|
|
129
113
|
}
|
|
114
|
+
function ollamaHttpError(status) {
|
|
115
|
+
return classifyProviderError("ollama", Object.assign(new Error(`Ollama error: ${status}`), { status }));
|
|
116
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { ProviderDescriptor, ProviderReplay, ToolCall } from "../types.js";
|
|
2
|
+
import type { EndpointProfileId, ProviderId } from "./endpoints.js";
|
|
3
|
+
export interface OpenAIChatTurnReasoning {
|
|
4
|
+
reasoningContent: string;
|
|
5
|
+
reasoningDetails?: unknown;
|
|
6
|
+
nativeToolCalls: unknown[];
|
|
7
|
+
}
|
|
8
|
+
export type OpenAIChatReplayStrategy = "none" | "generic_stream" | "deepseek" | "minimax";
|
|
9
|
+
export interface OpenAIChatWireDialect {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly providerId: ProviderId;
|
|
12
|
+
readonly endpointId: EndpointProfileId;
|
|
13
|
+
readonly descriptor: {
|
|
14
|
+
reasoning: ProviderDescriptor["reasoning"];
|
|
15
|
+
};
|
|
16
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => Record<string, unknown>;
|
|
17
|
+
readonly serverTools?: (extensions: Readonly<Record<string, unknown>>) => unknown[];
|
|
18
|
+
readonly cacheKey: "openai" | "none";
|
|
19
|
+
readonly inlineThinkingTags: boolean;
|
|
20
|
+
readonly exposeReasoning: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
21
|
+
readonly requireReasoningReplay: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
22
|
+
readonly replay: OpenAIChatReplayStrategy;
|
|
23
|
+
}
|
|
24
|
+
export declare const openAIChatDialects: {
|
|
25
|
+
readonly openai: {
|
|
26
|
+
readonly id: "openai";
|
|
27
|
+
readonly providerId: "openai";
|
|
28
|
+
readonly endpointId: "openai.chat";
|
|
29
|
+
readonly descriptor: {
|
|
30
|
+
readonly reasoning: {
|
|
31
|
+
supported: boolean;
|
|
32
|
+
preserveAcrossToolTurns: boolean;
|
|
33
|
+
requiresReplayForToolTurns?: boolean;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => Record<string, unknown>;
|
|
37
|
+
readonly cacheKey: "openai";
|
|
38
|
+
readonly inlineThinkingTags: true;
|
|
39
|
+
readonly exposeReasoning: () => boolean;
|
|
40
|
+
readonly requireReasoningReplay: () => boolean;
|
|
41
|
+
readonly replay: "generic_stream";
|
|
42
|
+
};
|
|
43
|
+
readonly deepseek: {
|
|
44
|
+
readonly id: "deepseek";
|
|
45
|
+
readonly providerId: "deepseek";
|
|
46
|
+
readonly endpointId: "deepseek.openai";
|
|
47
|
+
readonly descriptor: {
|
|
48
|
+
readonly reasoning: {
|
|
49
|
+
supported: boolean;
|
|
50
|
+
preserveAcrossToolTurns: boolean;
|
|
51
|
+
requiresReplayForToolTurns?: boolean;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => {
|
|
55
|
+
__deepstrikeThinkingEnabled: boolean;
|
|
56
|
+
reasoning_effort: string;
|
|
57
|
+
extra_body: {
|
|
58
|
+
thinking: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
degradeMissingReasoningReplay?: boolean | undefined;
|
|
63
|
+
};
|
|
64
|
+
readonly cacheKey: "none";
|
|
65
|
+
readonly inlineThinkingTags: false;
|
|
66
|
+
readonly exposeReasoning: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
67
|
+
readonly requireReasoningReplay: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
68
|
+
readonly replay: "deepseek";
|
|
69
|
+
};
|
|
70
|
+
readonly kimi: {
|
|
71
|
+
readonly id: "kimi";
|
|
72
|
+
readonly providerId: "kimi";
|
|
73
|
+
readonly endpointId: "kimi.openai";
|
|
74
|
+
readonly descriptor: {
|
|
75
|
+
readonly reasoning: {
|
|
76
|
+
supported: boolean;
|
|
77
|
+
preserveAcrossToolTurns: boolean;
|
|
78
|
+
requiresReplayForToolTurns?: boolean;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => Record<string, unknown>;
|
|
82
|
+
readonly cacheKey: "openai";
|
|
83
|
+
readonly inlineThinkingTags: true;
|
|
84
|
+
readonly exposeReasoning: () => boolean;
|
|
85
|
+
readonly requireReasoningReplay: () => boolean;
|
|
86
|
+
readonly replay: "generic_stream";
|
|
87
|
+
};
|
|
88
|
+
readonly qwen: {
|
|
89
|
+
readonly id: "qwen";
|
|
90
|
+
readonly providerId: "qwen";
|
|
91
|
+
readonly endpointId: "qwen.dashscope";
|
|
92
|
+
readonly descriptor: {
|
|
93
|
+
readonly reasoning: {
|
|
94
|
+
supported: boolean;
|
|
95
|
+
preserveAcrossToolTurns: boolean;
|
|
96
|
+
requiresReplayForToolTurns?: boolean;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => {
|
|
100
|
+
extra_body?: Record<string, unknown> | undefined;
|
|
101
|
+
};
|
|
102
|
+
readonly cacheKey: "none";
|
|
103
|
+
readonly inlineThinkingTags: false;
|
|
104
|
+
readonly exposeReasoning: () => boolean;
|
|
105
|
+
readonly requireReasoningReplay: () => boolean;
|
|
106
|
+
readonly replay: "generic_stream";
|
|
107
|
+
};
|
|
108
|
+
readonly glm: {
|
|
109
|
+
readonly id: "glm";
|
|
110
|
+
readonly providerId: "glm";
|
|
111
|
+
readonly endpointId: "glm.openai";
|
|
112
|
+
readonly descriptor: {
|
|
113
|
+
readonly reasoning: {
|
|
114
|
+
supported: boolean;
|
|
115
|
+
preserveAcrossToolTurns: boolean;
|
|
116
|
+
requiresReplayForToolTurns?: boolean;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => Record<string, unknown>;
|
|
120
|
+
readonly serverTools: (extensions: Readonly<Record<string, unknown>>) => {
|
|
121
|
+
type: string;
|
|
122
|
+
web_search: object;
|
|
123
|
+
}[];
|
|
124
|
+
readonly cacheKey: "openai";
|
|
125
|
+
readonly inlineThinkingTags: true;
|
|
126
|
+
readonly exposeReasoning: () => boolean;
|
|
127
|
+
readonly requireReasoningReplay: () => boolean;
|
|
128
|
+
readonly replay: "generic_stream";
|
|
129
|
+
};
|
|
130
|
+
readonly minimax: {
|
|
131
|
+
readonly id: "minimax";
|
|
132
|
+
readonly providerId: "minimax";
|
|
133
|
+
readonly endpointId: "minimax.openai";
|
|
134
|
+
readonly descriptor: {
|
|
135
|
+
readonly reasoning: {
|
|
136
|
+
supported: boolean;
|
|
137
|
+
preserveAcrossToolTurns: boolean;
|
|
138
|
+
requiresReplayForToolTurns?: boolean;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
readonly prepareExtensions: (extensions: Readonly<Record<string, unknown>>) => {
|
|
142
|
+
__deepstrikeThinkingEnabled: boolean;
|
|
143
|
+
reasoning_split: boolean;
|
|
144
|
+
degradeMissingReasoningReplay?: boolean | undefined;
|
|
145
|
+
};
|
|
146
|
+
readonly cacheKey: "none";
|
|
147
|
+
readonly inlineThinkingTags: false;
|
|
148
|
+
readonly exposeReasoning: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
149
|
+
readonly requireReasoningReplay: (extensions: Readonly<Record<string, unknown>>) => boolean;
|
|
150
|
+
readonly replay: "minimax";
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
export type OpenAIChatDialectId = keyof typeof openAIChatDialects;
|
|
154
|
+
export declare function replayForTurn(dialect: OpenAIChatWireDialect, phase: "complete" | "stream", model: string, content: string, toolCalls: ToolCall[], reasoning: OpenAIChatTurnReasoning): ProviderReplay | undefined;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
function omit(extensions, keys) {
|
|
2
|
+
const blocked = new Set([
|
|
3
|
+
...keys,
|
|
4
|
+
"model", "messages", "tools", "stream", "stream_options",
|
|
5
|
+
"__deepstrikeThinkingEnabled", "degradeMissingReasoningReplay",
|
|
6
|
+
]);
|
|
7
|
+
return Object.fromEntries(Object.entries(extensions).filter(([key]) => !blocked.has(key)));
|
|
8
|
+
}
|
|
9
|
+
const portableReasoning = {
|
|
10
|
+
supported: true,
|
|
11
|
+
preserveAcrossToolTurns: false,
|
|
12
|
+
};
|
|
13
|
+
const outOfBandReasoning = {
|
|
14
|
+
supported: true,
|
|
15
|
+
preserveAcrossToolTurns: true,
|
|
16
|
+
};
|
|
17
|
+
const strictReasoning = {
|
|
18
|
+
supported: true,
|
|
19
|
+
preserveAcrossToolTurns: true,
|
|
20
|
+
requiresReplayForToolTurns: true,
|
|
21
|
+
};
|
|
22
|
+
const passthrough = (extensions) => omit(extensions, []);
|
|
23
|
+
const never = () => false;
|
|
24
|
+
const always = () => true;
|
|
25
|
+
export const openAIChatDialects = {
|
|
26
|
+
openai: {
|
|
27
|
+
id: "openai",
|
|
28
|
+
providerId: "openai",
|
|
29
|
+
endpointId: "openai.chat",
|
|
30
|
+
descriptor: { reasoning: portableReasoning },
|
|
31
|
+
prepareExtensions: passthrough,
|
|
32
|
+
cacheKey: "openai",
|
|
33
|
+
inlineThinkingTags: true,
|
|
34
|
+
exposeReasoning: always,
|
|
35
|
+
requireReasoningReplay: never,
|
|
36
|
+
replay: "generic_stream",
|
|
37
|
+
},
|
|
38
|
+
deepseek: {
|
|
39
|
+
id: "deepseek",
|
|
40
|
+
providerId: "deepseek",
|
|
41
|
+
endpointId: "deepseek.openai",
|
|
42
|
+
descriptor: { reasoning: strictReasoning },
|
|
43
|
+
prepareExtensions: extensions => {
|
|
44
|
+
const thinking = extensions.thinking === false ? "disabled" : "enabled";
|
|
45
|
+
return {
|
|
46
|
+
...omit(extensions, ["thinking", "reasoningEffort", "exposeReasoning", "extra_body", "reasoning_effort"]),
|
|
47
|
+
...(extensions.degradeMissingReasoningReplay === true
|
|
48
|
+
? { degradeMissingReasoningReplay: true }
|
|
49
|
+
: {}),
|
|
50
|
+
__deepstrikeThinkingEnabled: thinking !== "disabled",
|
|
51
|
+
reasoning_effort: extensions.reasoningEffort === "max" ? "max" : "high",
|
|
52
|
+
extra_body: { thinking: { type: thinking } },
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
cacheKey: "none",
|
|
56
|
+
inlineThinkingTags: false,
|
|
57
|
+
exposeReasoning: extensions => extensions.exposeReasoning === true,
|
|
58
|
+
requireReasoningReplay: extensions => extensions.__deepstrikeThinkingEnabled !== false && extensions.thinking !== false,
|
|
59
|
+
replay: "deepseek",
|
|
60
|
+
},
|
|
61
|
+
kimi: {
|
|
62
|
+
id: "kimi",
|
|
63
|
+
providerId: "kimi",
|
|
64
|
+
endpointId: "kimi.openai",
|
|
65
|
+
descriptor: { reasoning: portableReasoning },
|
|
66
|
+
prepareExtensions: passthrough,
|
|
67
|
+
cacheKey: "openai",
|
|
68
|
+
inlineThinkingTags: true,
|
|
69
|
+
exposeReasoning: always,
|
|
70
|
+
requireReasoningReplay: never,
|
|
71
|
+
replay: "generic_stream",
|
|
72
|
+
},
|
|
73
|
+
qwen: {
|
|
74
|
+
id: "qwen",
|
|
75
|
+
providerId: "qwen",
|
|
76
|
+
endpointId: "qwen.dashscope",
|
|
77
|
+
descriptor: { reasoning: outOfBandReasoning },
|
|
78
|
+
prepareExtensions: extensions => {
|
|
79
|
+
const enableThinking = Boolean(extensions.enableThinking ?? extensions.enable_thinking);
|
|
80
|
+
const thinkingBudget = extensions.thinkingBudget ?? extensions.thinking_budget;
|
|
81
|
+
const extraBody = {};
|
|
82
|
+
if (enableThinking) {
|
|
83
|
+
extraBody.enable_thinking = true;
|
|
84
|
+
if (typeof thinkingBudget === "number")
|
|
85
|
+
extraBody.thinking_budget = thinkingBudget;
|
|
86
|
+
}
|
|
87
|
+
if (extensions.enable_search) {
|
|
88
|
+
extraBody.enable_search = true;
|
|
89
|
+
if (extensions.search_options != null)
|
|
90
|
+
extraBody.search_options = extensions.search_options;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
...omit(extensions, [
|
|
94
|
+
"extra_body", "enableThinking", "enable_thinking", "thinkingBudget", "thinking_budget",
|
|
95
|
+
"enable_search", "search_options",
|
|
96
|
+
]),
|
|
97
|
+
...(Object.keys(extraBody).length ? { extra_body: extraBody } : {}),
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
cacheKey: "none",
|
|
101
|
+
inlineThinkingTags: false,
|
|
102
|
+
exposeReasoning: always,
|
|
103
|
+
requireReasoningReplay: never,
|
|
104
|
+
replay: "generic_stream",
|
|
105
|
+
},
|
|
106
|
+
glm: {
|
|
107
|
+
id: "glm",
|
|
108
|
+
providerId: "glm",
|
|
109
|
+
endpointId: "glm.openai",
|
|
110
|
+
descriptor: { reasoning: portableReasoning },
|
|
111
|
+
prepareExtensions: extensions => omit(extensions, ["web_search"]),
|
|
112
|
+
serverTools: extensions => extensions.web_search
|
|
113
|
+
? [{
|
|
114
|
+
type: "web_search",
|
|
115
|
+
web_search: typeof extensions.web_search === "object" ? extensions.web_search : {},
|
|
116
|
+
}]
|
|
117
|
+
: [],
|
|
118
|
+
cacheKey: "openai",
|
|
119
|
+
inlineThinkingTags: true,
|
|
120
|
+
exposeReasoning: always,
|
|
121
|
+
requireReasoningReplay: never,
|
|
122
|
+
replay: "generic_stream",
|
|
123
|
+
},
|
|
124
|
+
minimax: {
|
|
125
|
+
id: "minimax",
|
|
126
|
+
providerId: "minimax",
|
|
127
|
+
endpointId: "minimax.openai",
|
|
128
|
+
descriptor: { reasoning: strictReasoning },
|
|
129
|
+
prepareExtensions: extensions => {
|
|
130
|
+
const reasoningSplit = extensions.reasoning_split !== false;
|
|
131
|
+
return {
|
|
132
|
+
...omit(extensions, ["reasoning_split", "exposeReasoning"]),
|
|
133
|
+
...(extensions.degradeMissingReasoningReplay === true
|
|
134
|
+
? { degradeMissingReasoningReplay: true }
|
|
135
|
+
: {}),
|
|
136
|
+
__deepstrikeThinkingEnabled: reasoningSplit,
|
|
137
|
+
reasoning_split: reasoningSplit,
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
cacheKey: "none",
|
|
141
|
+
inlineThinkingTags: false,
|
|
142
|
+
exposeReasoning: extensions => extensions.exposeReasoning === true,
|
|
143
|
+
requireReasoningReplay: extensions => extensions.__deepstrikeThinkingEnabled !== false && extensions.reasoning_split !== false,
|
|
144
|
+
replay: "minimax",
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
export function replayForTurn(dialect, phase, model, content, toolCalls, reasoning) {
|
|
148
|
+
switch (dialect.replay) {
|
|
149
|
+
case "none": return undefined;
|
|
150
|
+
case "generic_stream":
|
|
151
|
+
return phase === "stream" && (toolCalls.length > 0 || reasoning.reasoningContent)
|
|
152
|
+
? { protocol: "openai-chat", reasoning_content: reasoning.reasoningContent }
|
|
153
|
+
: undefined;
|
|
154
|
+
case "deepseek":
|
|
155
|
+
if (!reasoning.reasoningContent.trim())
|
|
156
|
+
return undefined;
|
|
157
|
+
return {
|
|
158
|
+
provider: dialect.providerId,
|
|
159
|
+
protocol: "openai-chat",
|
|
160
|
+
model,
|
|
161
|
+
reasoning_content: reasoning.reasoningContent,
|
|
162
|
+
...(reasoning.nativeToolCalls.length ? { tool_calls: reasoning.nativeToolCalls } : {}),
|
|
163
|
+
};
|
|
164
|
+
case "minimax": {
|
|
165
|
+
const hasReasoning = reasoning.reasoningContent.trim().length > 0;
|
|
166
|
+
const hasDetails = reasoning.reasoningDetails !== undefined && reasoning.reasoningDetails !== null;
|
|
167
|
+
if (!hasReasoning && !hasDetails)
|
|
168
|
+
return undefined;
|
|
169
|
+
return {
|
|
170
|
+
provider: dialect.providerId,
|
|
171
|
+
protocol: "openai-chat",
|
|
172
|
+
model,
|
|
173
|
+
...(hasReasoning ? { reasoning_content: reasoning.reasoningContent } : {}),
|
|
174
|
+
...(hasDetails ? { reasoning_details: reasoning.reasoningDetails } : {}),
|
|
175
|
+
...(reasoning.nativeToolCalls.length ? { tool_calls: reasoning.nativeToolCalls } : {}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -1,19 +1,55 @@
|
|
|
1
1
|
import type OpenAI from "openai";
|
|
2
|
-
import type { Message, ProviderDescriptor, RenderedContext, ToolSchema } from "../types.js";
|
|
2
|
+
import type { Message, ProviderDescriptor, ProviderReplay, ProviderUsage, RenderedContext, ToolCall, ToolSchema } from "../types.js";
|
|
3
|
+
import { ThinkingTagStreamExtractor } from "./base.js";
|
|
4
|
+
import type { CanonicalAdapterInput } from "./content-normalization.js";
|
|
3
5
|
import { type ReplayabilityAssessment } from "./replay-validator.js";
|
|
6
|
+
import { type AdapterDecodeInput, type AdapterOutput, type AdapterStreamInput, type CanonicalStopReason, type ProtocolAdapter } from "./protocol-adapter.js";
|
|
7
|
+
import { type OpenAIChatWireDialect } from "./openai-chat-dialects.js";
|
|
4
8
|
export interface OpenAIChatBuildMessageOptions {
|
|
5
9
|
descriptor?: ProviderDescriptor;
|
|
6
10
|
requireNonEmptyReasoningForToolCalls?: boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Degrade (rather than throw) when a reasoning-requiring tool-call turn has
|
|
9
|
-
* no stored reasoning replay: a placeholder reasoning is injected so the
|
|
10
|
-
* request still goes out in degraded form.
|
|
11
|
-
*/
|
|
12
11
|
degradeMissingReasoning?: boolean;
|
|
13
12
|
}
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export interface OpenAIChatRequestPlan {
|
|
14
|
+
params: Record<string, unknown>;
|
|
15
|
+
preparedExtensions: Record<string, unknown>;
|
|
16
|
+
dialect: OpenAIChatWireDialect;
|
|
17
|
+
}
|
|
18
|
+
export type OpenAIChatStreamChunk = Record<string, any>;
|
|
19
|
+
export interface OpenAIChatStreamState {
|
|
20
|
+
readonly input: CanonicalAdapterInput;
|
|
21
|
+
readonly dialect: OpenAIChatWireDialect;
|
|
22
|
+
readonly toolCallBuffers: Record<number, {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
argsBuffer: string;
|
|
26
|
+
}>;
|
|
27
|
+
readonly emittedToolCallIndexes: Set<number>;
|
|
28
|
+
readonly extractor: ThinkingTagStreamExtractor;
|
|
29
|
+
accumulatedReasoning: string;
|
|
30
|
+
accumulatedReasoningDetails?: unknown;
|
|
31
|
+
accumulatedContent: string;
|
|
32
|
+
totalTokens: number;
|
|
33
|
+
inputTokens: number;
|
|
34
|
+
outputTokens: number;
|
|
35
|
+
cacheReadTokens: number;
|
|
36
|
+
finishReason?: string;
|
|
37
|
+
rawUsage?: unknown;
|
|
38
|
+
}
|
|
39
|
+
export declare class OpenAIChatAdapter implements ProtocolAdapter<OpenAIChatRequestPlan, Record<string, any>, OpenAIChatStreamChunk, OpenAIChatStreamState, undefined> {
|
|
40
|
+
readonly protocol: "openai-chat";
|
|
41
|
+
readonly protocolCapabilities: import("./protocol-capabilities.js").ProtocolRuntimeCapabilities;
|
|
42
|
+
buildRequest(input: CanonicalAdapterInput, dialect?: OpenAIChatWireDialect): OpenAIChatRequestPlan;
|
|
43
|
+
decodeComplete(raw: Record<string, any>, input: AdapterDecodeInput, dialect?: OpenAIChatWireDialect): {
|
|
44
|
+
message: Message;
|
|
45
|
+
replay?: ProviderReplay;
|
|
46
|
+
};
|
|
47
|
+
createStreamState(input: AdapterStreamInput, dialect?: OpenAIChatWireDialect): OpenAIChatStreamState;
|
|
48
|
+
pushStreamChunk(chunk: OpenAIChatStreamChunk, state: OpenAIChatStreamState): AdapterOutput;
|
|
49
|
+
finishStream(state: OpenAIChatStreamState): AdapterOutput;
|
|
50
|
+
normalizeUsage(raw: unknown): ProviderUsage | undefined;
|
|
51
|
+
normalizeStopReason(raw: string | undefined): CanonicalStopReason | undefined;
|
|
52
|
+
buildTools(tools: readonly ToolSchema[]): {
|
|
17
53
|
type: "function";
|
|
18
54
|
function: {
|
|
19
55
|
name: string;
|
|
@@ -22,16 +58,8 @@ export declare class OpenAIChatAdapter {
|
|
|
22
58
|
};
|
|
23
59
|
}[];
|
|
24
60
|
buildMessages(context: RenderedContext, options?: OpenAIChatBuildMessageOptions): OpenAI.ChatCompletionMessageParam[];
|
|
25
|
-
/**
|
|
26
|
-
* Throw-free pre-flight check: which assistant tool-call turns in `context`
|
|
27
|
-
* lack the non-empty reasoning replay a reasoning-requiring provider needs.
|
|
28
|
-
*/
|
|
29
61
|
assessReasoning(context: RenderedContext): ReplayabilityAssessment;
|
|
30
|
-
normalizeToolCalls(toolCalls?: OpenAI.ChatCompletionMessageToolCall[]):
|
|
31
|
-
id: string;
|
|
32
|
-
name: string;
|
|
33
|
-
arguments: string;
|
|
34
|
-
}>;
|
|
62
|
+
normalizeToolCalls(toolCalls?: OpenAI.ChatCompletionMessageToolCall[]): ToolCall[];
|
|
35
63
|
rememberReplayFields(message: Pick<Message, "content" | "toolCalls">, fields: Record<string, unknown>): void;
|
|
36
64
|
peekReplayFields(message: Pick<Message, "content" | "toolCalls">): Record<string, unknown> | undefined;
|
|
37
65
|
}
|