@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/gemini.js
CHANGED
|
@@ -1,163 +1,98 @@
|
|
|
1
1
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
2
2
|
import { withServerRuntimeGuard } from "../runtime/server.js";
|
|
3
|
-
import { CircuitBreaker
|
|
4
|
-
import { endpointProfiles } from "./
|
|
5
|
-
import {
|
|
3
|
+
import { CircuitBreaker } from "./base.js";
|
|
4
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
5
|
+
import { normalizeCanonicalAdapterInput, normalizeCanonicalContext, } from "./content-normalization.js";
|
|
6
|
+
import { GeminiAdapter, canonicalGeminiContents, geminiVendorConfig } from "./gemini-adapter.js";
|
|
7
|
+
import { circuitOpenError, classifyProviderError } from "./provider-error.js";
|
|
6
8
|
const GEMINI_BASE = endpointProfiles["gemini.google"].baseURL;
|
|
7
|
-
const GEMINI_POLICIES = {
|
|
8
|
-
"gemini-3-pro-preview": { maxTurns: 50 },
|
|
9
|
-
"gemini-3-flash-preview": { maxTurns: 25 },
|
|
10
|
-
"gemini-3.5-flash": { maxTurns: 30 },
|
|
11
|
-
"gemini-2.5-pro": { maxTurns: 35 },
|
|
12
|
-
"gemini-2.5-flash": { maxTurns: 20 },
|
|
13
|
-
"gemini-2.0-flash": { maxTurns: 15 },
|
|
14
|
-
"gemini-2.0-flash-lite": { maxTurns: 10 },
|
|
15
|
-
"gemini-1.5-pro": { maxTurns: 30 },
|
|
16
|
-
"gemini-1.5-flash": { maxTurns: 15 },
|
|
17
|
-
};
|
|
18
9
|
export function buildContents(turns) {
|
|
19
|
-
|
|
20
|
-
for (const msg of turns) {
|
|
21
|
-
if (msg.role === "tool") {
|
|
22
|
-
const parts = (msg.contentParts ?? [])
|
|
23
|
-
.filter(p => p.type === "tool_result")
|
|
24
|
-
.map(p => {
|
|
25
|
-
if (p.type !== "tool_result")
|
|
26
|
-
return { text: "" };
|
|
27
|
-
let toolName = p.callId;
|
|
28
|
-
for (let i = turns.length - 1; i >= 0; i--) {
|
|
29
|
-
const turn = turns[i];
|
|
30
|
-
if (turn.role === "assistant" && turn.toolCalls) {
|
|
31
|
-
const matched = turn.toolCalls.find(tc => tc.id === p.callId);
|
|
32
|
-
if (matched) {
|
|
33
|
-
toolName = matched.name;
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return {
|
|
39
|
-
functionResponse: { name: toolName, response: { output: p.output } },
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
if (parts.length)
|
|
43
|
-
contents.push({ role: "user", parts });
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
const role = msg.role === "assistant" ? "model" : "user";
|
|
47
|
-
const parts = [];
|
|
48
|
-
if (msg.toolCalls?.length) {
|
|
49
|
-
for (const tc of msg.toolCalls) {
|
|
50
|
-
let args = {};
|
|
51
|
-
try {
|
|
52
|
-
args = JSON.parse(tc.arguments);
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
args = {};
|
|
56
|
-
}
|
|
57
|
-
parts.push({ functionCall: { name: tc.name, args } });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// Multimodal: render contentParts (text + image) when present, else the plain
|
|
61
|
-
// text body. Without this, image inputs to Gemini were silently dropped.
|
|
62
|
-
if (msg.contentParts?.length) {
|
|
63
|
-
for (const p of msg.contentParts) {
|
|
64
|
-
if (p.type === "text")
|
|
65
|
-
parts.push({ text: p.text });
|
|
66
|
-
else if (p.type === "image") {
|
|
67
|
-
if (p.data)
|
|
68
|
-
parts.push({ inlineData: { mimeType: p.mediaType ?? "image/png", data: p.data } });
|
|
69
|
-
else if (p.url)
|
|
70
|
-
parts.push({ fileData: { mimeType: p.mediaType ?? "image/png", fileUri: p.url } });
|
|
71
|
-
}
|
|
72
|
-
else if (p.type === "audio") {
|
|
73
|
-
if (!p.data)
|
|
74
|
-
throw new UnsupportedModalityError("audio", "gemini");
|
|
75
|
-
parts.push({ inlineData: { mimeType: p.mediaType ?? "audio/wav", data: p.data } });
|
|
76
|
-
}
|
|
77
|
-
else if (p.type === "tool_result") {
|
|
78
|
-
// tool results are handled via functionResponse on tool role messages
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
throw new UnsupportedModalityError(String(p.type ?? "unknown"), "gemini");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else if (msg.content) {
|
|
86
|
-
parts.push({ text: msg.content });
|
|
87
|
-
}
|
|
88
|
-
if (parts.length)
|
|
89
|
-
contents.push({ role, parts });
|
|
90
|
-
}
|
|
91
|
-
return contents;
|
|
92
|
-
}
|
|
93
|
-
function buildTools(tools) {
|
|
94
|
-
if (!tools.length)
|
|
95
|
-
return [];
|
|
96
|
-
return [{
|
|
97
|
-
functionDeclarations: tools.map(t => ({
|
|
98
|
-
name: t.name,
|
|
99
|
-
description: t.description,
|
|
100
|
-
parameters: JSON.parse(t.parameters),
|
|
101
|
-
})),
|
|
102
|
-
}];
|
|
10
|
+
return canonicalGeminiContents(normalizeCanonicalContext({ systemText: "", turns }));
|
|
103
11
|
}
|
|
104
12
|
export class GeminiProvider {
|
|
105
13
|
model;
|
|
14
|
+
resolvedRuntime;
|
|
106
15
|
genAI;
|
|
107
16
|
circuit;
|
|
108
17
|
maxRetries;
|
|
109
18
|
baseDelay;
|
|
110
19
|
requestOptions;
|
|
111
|
-
|
|
20
|
+
resolvedRuntimePolicy;
|
|
21
|
+
adapter = new GeminiAdapter();
|
|
22
|
+
constructor(apiKey, model = "gemini-2.0-flash", retry = { maxRetries: 3, baseDelay: 1000 }, baseURL = GEMINI_BASE, runtimePolicy = {}, resolvedRuntime) {
|
|
112
23
|
this.model = model;
|
|
24
|
+
this.resolvedRuntime = resolvedRuntime;
|
|
113
25
|
this.genAI = withServerRuntimeGuard(() => new GoogleGenerativeAI(apiKey));
|
|
114
26
|
this.circuit = new CircuitBreaker();
|
|
115
27
|
this.maxRetries = retry.maxRetries;
|
|
116
28
|
this.baseDelay = retry.baseDelay;
|
|
117
29
|
this.requestOptions = { baseUrl: baseURL };
|
|
30
|
+
this.resolvedRuntimePolicy = runtimePolicy;
|
|
118
31
|
}
|
|
119
32
|
runtimePolicy() {
|
|
120
|
-
return
|
|
33
|
+
return this.resolvedRuntimePolicy;
|
|
34
|
+
}
|
|
35
|
+
bindResolvedRuntime(resolved) {
|
|
36
|
+
if (resolved.identity.protocol !== "gemini"
|
|
37
|
+
|| resolved.identity.modelId !== this.model) {
|
|
38
|
+
throw new Error("GeminiProvider received a mismatched resolved runtime");
|
|
39
|
+
}
|
|
40
|
+
this.resolvedRuntime = resolved;
|
|
41
|
+
}
|
|
42
|
+
adapterInput(context, tools, extensions) {
|
|
43
|
+
if (!this.resolvedRuntime) {
|
|
44
|
+
// Direct class construction is a published compatibility path. A-07 replaces it with
|
|
45
|
+
// injected runtime profiles; until then this local descriptor contains no Registry lookup.
|
|
46
|
+
const resolved = {
|
|
47
|
+
identity: {
|
|
48
|
+
providerId: "gemini",
|
|
49
|
+
modelId: this.model,
|
|
50
|
+
endpointId: "gemini.google",
|
|
51
|
+
protocol: "gemini",
|
|
52
|
+
},
|
|
53
|
+
model: { id: `gemini/${this.model}`, providerId: "gemini", kind: "generation", intrinsic: {} },
|
|
54
|
+
endpoint: endpointProfiles["gemini.google"],
|
|
55
|
+
adapter: this,
|
|
56
|
+
effectiveCapabilities: {
|
|
57
|
+
inputModalities: Object.fromEntries(["text", "image", "audio", "video", "file"].map(modality => [modality, { state: modality === "video" || modality === "file" ? "unsupported" : "unknown", evidence: [] }])),
|
|
58
|
+
outputModalities: Object.fromEntries(["text", "image", "audio", "embedding"].map(modality => [modality, { state: "unknown", evidence: [] }])),
|
|
59
|
+
tools: { state: "unknown", evidence: [] },
|
|
60
|
+
reasoning: { state: "unknown", evidence: [] },
|
|
61
|
+
parallelToolCalls: { state: "unknown", evidence: [] },
|
|
62
|
+
structuredOutput: { state: "unknown", evidence: [] },
|
|
63
|
+
promptCaching: { state: "unknown", evidence: [] },
|
|
64
|
+
nativeTokenCounting: { state: "unknown", evidence: [] },
|
|
65
|
+
mediaForms: Object.fromEntries(["imageUrl", "imageBase64", "fileId", "audioUrl", "audioBase64"].map(form => [form, { state: "unknown", evidence: [] }])),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
return normalizeCanonicalAdapterInput({ context, tools, resolved, extensions });
|
|
69
|
+
}
|
|
70
|
+
return normalizeCanonicalAdapterInput({
|
|
71
|
+
context,
|
|
72
|
+
tools,
|
|
73
|
+
resolved: this.resolvedRuntime,
|
|
74
|
+
extensions,
|
|
75
|
+
});
|
|
121
76
|
}
|
|
122
77
|
async complete(context, tools, extensions) {
|
|
123
78
|
if (this.circuit.isOpen())
|
|
124
|
-
throw
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
79
|
+
throw circuitOpenError("gemini");
|
|
80
|
+
let input;
|
|
81
|
+
let plan;
|
|
82
|
+
try {
|
|
83
|
+
input = this.adapterInput(context, tools, extensions);
|
|
84
|
+
plan = this.adapter.buildRequest(input);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw classifyProviderError("gemini", error);
|
|
88
|
+
}
|
|
128
89
|
let lastErr;
|
|
129
90
|
for (let i = 0; i < this.maxRetries; i++) {
|
|
130
91
|
try {
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
const m = this.genAI.getGenerativeModel({
|
|
134
|
-
...this.modelExtensions(extensions),
|
|
135
|
-
model: this.model,
|
|
136
|
-
...(system ? { systemInstruction: system } : {}),
|
|
137
|
-
...(allTools.length ? { tools: allTools } : {}),
|
|
138
|
-
...(vc.generationConfig ? { generationConfig: vc.generationConfig } : {}),
|
|
139
|
-
}, this.requestOptions);
|
|
140
|
-
const resp = await m.generateContent({ contents });
|
|
92
|
+
const m = this.genAI.getGenerativeModel(plan.modelParams, this.requestOptions);
|
|
93
|
+
const resp = await m.generateContent(plan.request);
|
|
141
94
|
this.circuit.recordSuccess();
|
|
142
|
-
|
|
143
|
-
let content = "";
|
|
144
|
-
const toolCalls = [];
|
|
145
|
-
for (const part of candidate?.content.parts ?? []) {
|
|
146
|
-
if (part.text)
|
|
147
|
-
content += part.text;
|
|
148
|
-
else if (part.functionCall) {
|
|
149
|
-
const tc = normalizeToolCall(part.functionCall.name, part.functionCall.name, part.functionCall.args);
|
|
150
|
-
if (tc)
|
|
151
|
-
toolCalls.push(tc);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const usage = resp.response.usageMetadata;
|
|
155
|
-
return {
|
|
156
|
-
role: "assistant",
|
|
157
|
-
content,
|
|
158
|
-
tokenCount: usage?.candidatesTokenCount ?? usage?.totalTokenCount,
|
|
159
|
-
toolCalls,
|
|
160
|
-
};
|
|
95
|
+
return this.adapter.decodeComplete(resp.response, { input }).message;
|
|
161
96
|
}
|
|
162
97
|
catch (err) {
|
|
163
98
|
lastErr = err;
|
|
@@ -166,60 +101,40 @@ export class GeminiProvider {
|
|
|
166
101
|
await new Promise(r => setTimeout(r, this.baseDelay * 2 ** i));
|
|
167
102
|
}
|
|
168
103
|
}
|
|
169
|
-
throw lastErr;
|
|
104
|
+
throw classifyProviderError("gemini", lastErr);
|
|
170
105
|
}
|
|
171
106
|
async *stream(context, tools, extensions) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
...(allTools.length ? { tools: allTools } : {}),
|
|
182
|
-
...(vc.generationConfig ? { generationConfig: vc.generationConfig } : {}),
|
|
183
|
-
}, this.requestOptions);
|
|
184
|
-
const result = await m.generateContentStream({ contents });
|
|
185
|
-
const toolCalls = [];
|
|
186
|
-
for await (const chunk of result.stream) {
|
|
187
|
-
for (const part of chunk.candidates?.[0]?.content.parts ?? []) {
|
|
188
|
-
if (part.text)
|
|
189
|
-
yield { type: "text_delta", delta: part.text };
|
|
190
|
-
else if (part.functionCall) {
|
|
191
|
-
const { name, args } = part.functionCall;
|
|
192
|
-
toolCalls.push({ id: `call_${toolCalls.length + 1}`, name, args: args });
|
|
193
|
-
}
|
|
107
|
+
try {
|
|
108
|
+
const input = this.adapterInput(context, tools, extensions);
|
|
109
|
+
const plan = this.adapter.buildRequest(input);
|
|
110
|
+
const m = this.genAI.getGenerativeModel(plan.modelParams, this.requestOptions);
|
|
111
|
+
const result = await m.generateContentStream(plan.request);
|
|
112
|
+
const state = this.adapter.createStreamState({ input });
|
|
113
|
+
for await (const chunk of result.stream) {
|
|
114
|
+
for (const event of this.adapter.pushStreamChunk(chunk, state).events)
|
|
115
|
+
yield event;
|
|
194
116
|
}
|
|
117
|
+
for (const event of this.adapter.finishStream(state, await result.response).events)
|
|
118
|
+
yield event;
|
|
195
119
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
const usage = (await result.response).usageMetadata;
|
|
200
|
-
if (usage?.totalTokenCount) {
|
|
201
|
-
// Gemini implicit/explicit cache hits are reported as cachedContentTokenCount,
|
|
202
|
-
// a subset of promptTokenCount (which stays the full prompt for accounting).
|
|
203
|
-
const cachedTokens = usage.cachedContentTokenCount ?? 0;
|
|
204
|
-
yield {
|
|
205
|
-
type: "usage",
|
|
206
|
-
totalTokens: usage.totalTokenCount,
|
|
207
|
-
inputTokens: usage.promptTokenCount ?? 0,
|
|
208
|
-
outputTokens: usage.candidatesTokenCount ?? 0,
|
|
209
|
-
...(cachedTokens > 0 ? { cacheReadInputTokens: cachedTokens } : {}),
|
|
210
|
-
};
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw classifyProviderError("gemini", error);
|
|
211
122
|
}
|
|
212
123
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
return
|
|
124
|
+
/**
|
|
125
|
+
* spc_011-C-05: preflight native token count via `GenerativeModel.countTokens` — reuses the
|
|
126
|
+
* same contents/tools/vendorConfig construction `complete()` uses so the counted request and
|
|
127
|
+
* the sent request never diverge.
|
|
128
|
+
*/
|
|
129
|
+
async countTokens(context, tools, extensions) {
|
|
130
|
+
const plan = this.adapter.buildRequest(this.adapterInput(context, tools, extensions));
|
|
131
|
+
const m = this.genAI.getGenerativeModel(plan.modelParams, this.requestOptions);
|
|
132
|
+
const resp = await m.countTokens(plan.request);
|
|
133
|
+
return {
|
|
134
|
+
inputTokens: resp.totalTokens,
|
|
135
|
+
source: { kind: "native", provider: "gemini" },
|
|
136
|
+
confidence: "exact",
|
|
137
|
+
};
|
|
223
138
|
}
|
|
224
139
|
/**
|
|
225
140
|
* Gemini vendor features from extensions, mapped to the Node SDK shape (mirrors the Python provider's
|
|
@@ -230,19 +145,6 @@ export class GeminiProvider {
|
|
|
230
145
|
* pairing this with google_search).
|
|
231
146
|
*/
|
|
232
147
|
vendorConfig(extensions) {
|
|
233
|
-
|
|
234
|
-
const tools = [];
|
|
235
|
-
if (ext.google_search)
|
|
236
|
-
tools.push({ googleSearch: typeof ext.google_search === "object" ? ext.google_search : {} });
|
|
237
|
-
// Seed from any caller-provided raw generationConfig, then layer the named structured-output keys.
|
|
238
|
-
const gc = { ...ext.generationConfig };
|
|
239
|
-
if (ext.response_mime_type != null)
|
|
240
|
-
gc.responseMimeType = ext.response_mime_type;
|
|
241
|
-
if (ext.response_schema != null)
|
|
242
|
-
gc.responseSchema = ext.response_schema;
|
|
243
|
-
return {
|
|
244
|
-
...(tools.length ? { tools } : {}),
|
|
245
|
-
...(Object.keys(gc).length ? { generationConfig: gc } : {}),
|
|
246
|
-
};
|
|
148
|
+
return geminiVendorConfig(extensions ?? {});
|
|
247
149
|
}
|
|
248
150
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ModelRegistration } from "./model-registry.js";
|
|
2
|
+
export type { ModelRegistration } from "./model-registry.js";
|
|
3
|
+
/** A query-only model catalog. Catalogs describe models; selection policy belongs to CapabilityRouter. */
|
|
4
|
+
export interface ModelCatalog {
|
|
5
|
+
list(): Promise<readonly ModelRegistration[]>;
|
|
6
|
+
get(modelId: string): Promise<ModelRegistration | undefined>;
|
|
7
|
+
}
|
|
8
|
+
export interface ModelCatalogSource {
|
|
9
|
+
list(): Promise<readonly ModelRegistration[]>;
|
|
10
|
+
}
|
|
11
|
+
export type ModelCatalogRefreshResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
errorCode: "refresh_failed";
|
|
16
|
+
};
|
|
17
|
+
/** Immutable, deterministic model facts supplied by the SDK or an application. */
|
|
18
|
+
export declare class StaticModelCatalog implements ModelCatalog {
|
|
19
|
+
private readonly registrations;
|
|
20
|
+
private readonly byId;
|
|
21
|
+
constructor(registrations: readonly ModelRegistration[]);
|
|
22
|
+
list(): Promise<readonly ModelRegistration[]>;
|
|
23
|
+
get(modelId: string): Promise<ModelRegistration | undefined>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A host-owned discovery cache. Refresh never throws and never deletes the last good snapshot;
|
|
27
|
+
* callers can keep using the static catalog when a remote provider is unavailable.
|
|
28
|
+
*/
|
|
29
|
+
export declare class DynamicModelCatalog implements ModelCatalog {
|
|
30
|
+
private readonly source;
|
|
31
|
+
private readonly fallback;
|
|
32
|
+
private snapshot;
|
|
33
|
+
constructor(source: ModelCatalogSource, fallback?: ModelCatalog);
|
|
34
|
+
list(): Promise<readonly ModelRegistration[]>;
|
|
35
|
+
get(modelId: string): Promise<ModelRegistration | undefined>;
|
|
36
|
+
refresh(): Promise<ModelCatalogRefreshResult>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Immutable, deterministic model facts supplied by the SDK or an application. */
|
|
2
|
+
export class StaticModelCatalog {
|
|
3
|
+
registrations;
|
|
4
|
+
byId;
|
|
5
|
+
constructor(registrations) {
|
|
6
|
+
const byId = new Map();
|
|
7
|
+
for (const registration of registrations) {
|
|
8
|
+
const id = registration.descriptor.id;
|
|
9
|
+
if (byId.has(id))
|
|
10
|
+
throw new Error(`Duplicate model catalog entry: ${id}`);
|
|
11
|
+
byId.set(id, registration);
|
|
12
|
+
}
|
|
13
|
+
this.registrations = [...byId.values()].sort((a, b) => a.descriptor.id.localeCompare(b.descriptor.id));
|
|
14
|
+
this.byId = byId;
|
|
15
|
+
}
|
|
16
|
+
async list() {
|
|
17
|
+
return this.registrations;
|
|
18
|
+
}
|
|
19
|
+
async get(modelId) {
|
|
20
|
+
return this.byId.get(modelId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A host-owned discovery cache. Refresh never throws and never deletes the last good snapshot;
|
|
25
|
+
* callers can keep using the static catalog when a remote provider is unavailable.
|
|
26
|
+
*/
|
|
27
|
+
export class DynamicModelCatalog {
|
|
28
|
+
source;
|
|
29
|
+
fallback;
|
|
30
|
+
snapshot = new Map();
|
|
31
|
+
constructor(source, fallback = new StaticModelCatalog([])) {
|
|
32
|
+
this.source = source;
|
|
33
|
+
this.fallback = fallback;
|
|
34
|
+
}
|
|
35
|
+
async list() {
|
|
36
|
+
const merged = new Map();
|
|
37
|
+
for (const registration of await this.fallback.list())
|
|
38
|
+
merged.set(registration.descriptor.id, registration);
|
|
39
|
+
for (const registration of this.snapshot.values())
|
|
40
|
+
merged.set(registration.descriptor.id, registration);
|
|
41
|
+
return [...merged.values()].sort((a, b) => a.descriptor.id.localeCompare(b.descriptor.id));
|
|
42
|
+
}
|
|
43
|
+
async get(modelId) {
|
|
44
|
+
return this.snapshot.get(modelId) ?? await this.fallback.get(modelId);
|
|
45
|
+
}
|
|
46
|
+
async refresh() {
|
|
47
|
+
try {
|
|
48
|
+
const next = new Map();
|
|
49
|
+
for (const registration of await this.source.list()) {
|
|
50
|
+
const id = registration.descriptor.id;
|
|
51
|
+
if (next.has(id))
|
|
52
|
+
throw new Error("duplicate dynamic model catalog entry");
|
|
53
|
+
next.set(id, registration);
|
|
54
|
+
}
|
|
55
|
+
this.snapshot = next;
|
|
56
|
+
return { ok: true };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { ok: false, errorCode: "refresh_failed" };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { LLMProvider, RuntimePolicy } from "../types.js";
|
|
2
|
+
import { type EndpointProfile, type EndpointProfileId, type EndpointProtocol, type ProviderId } from "./endpoints.js";
|
|
3
|
+
import { type GenerationProtocol, type InputModality, type OutputModality, type ProtocolRuntimeCapabilities, type ProtocolRuntimeCapabilityOverrides } from "./protocol-capabilities.js";
|
|
4
|
+
export type { GenerationProtocol, InputModality, OutputModality, ProtocolRuntimeCapabilities, ProtocolRuntimeCapabilityOverrides, } from "./protocol-capabilities.js";
|
|
5
|
+
export type ModelKind = "generation" | "embedding";
|
|
6
|
+
export type CapabilityState = "supported" | "unsupported" | "unknown";
|
|
7
|
+
export declare const MODEL_CAPABILITY_STATES: readonly CapabilityState[];
|
|
8
|
+
export interface ModelDescriptor {
|
|
9
|
+
id: string;
|
|
10
|
+
providerId: string;
|
|
11
|
+
kind: ModelKind;
|
|
12
|
+
contextWindow?: number;
|
|
13
|
+
maxOutputTokens?: number;
|
|
14
|
+
intrinsic: {
|
|
15
|
+
inputModalities?: readonly InputModality[];
|
|
16
|
+
outputModalities?: readonly OutputModality[];
|
|
17
|
+
tools?: boolean;
|
|
18
|
+
reasoning?: boolean;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface ModelRegistration {
|
|
22
|
+
descriptor: ModelDescriptor;
|
|
23
|
+
defaultEndpointId: EndpointProfileId;
|
|
24
|
+
recommendedRuntimePolicy?: RuntimePolicy;
|
|
25
|
+
}
|
|
26
|
+
export interface DynamicModelDescriptorResolver {
|
|
27
|
+
readonly providerId: ProviderId;
|
|
28
|
+
resolve(modelId: string): ModelRegistration;
|
|
29
|
+
}
|
|
30
|
+
export interface EndpointRuntimeCapabilities {
|
|
31
|
+
nativeTokenCounting?: boolean;
|
|
32
|
+
promptCaching?: boolean;
|
|
33
|
+
protocolOverrides?: ProtocolRuntimeCapabilityOverrides;
|
|
34
|
+
}
|
|
35
|
+
export interface CacheCapabilityEvidence {
|
|
36
|
+
endpointId: EndpointProfileId;
|
|
37
|
+
source: string;
|
|
38
|
+
verifiedAt: "2026-08-26";
|
|
39
|
+
classification: "documentation" | "live_probe";
|
|
40
|
+
usageFields: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
export interface TokenMeasurementEvidence {
|
|
43
|
+
endpointId: EndpointProfileId;
|
|
44
|
+
source: string;
|
|
45
|
+
verifiedAt: "2026-08-26";
|
|
46
|
+
providerApiState: "supported" | "unsupported" | "unknown";
|
|
47
|
+
adapterState: "available" | "unavailable";
|
|
48
|
+
method: "provider_preflight" | "official_local_tokenizer" | "postflight" | "heuristic";
|
|
49
|
+
coverage: readonly string[];
|
|
50
|
+
sdk: string;
|
|
51
|
+
}
|
|
52
|
+
export type CapabilityEvidenceLayer = "model" | "protocol" | "endpoint";
|
|
53
|
+
export interface EffectiveCapability<T = boolean> {
|
|
54
|
+
state: CapabilityState;
|
|
55
|
+
value?: T;
|
|
56
|
+
evidence: readonly CapabilityEvidenceLayer[];
|
|
57
|
+
}
|
|
58
|
+
export interface EffectiveModelCapabilities {
|
|
59
|
+
inputModalities: Record<InputModality, EffectiveCapability>;
|
|
60
|
+
outputModalities: Record<OutputModality, EffectiveCapability>;
|
|
61
|
+
tools: EffectiveCapability;
|
|
62
|
+
reasoning: EffectiveCapability;
|
|
63
|
+
parallelToolCalls: EffectiveCapability;
|
|
64
|
+
structuredOutput: EffectiveCapability;
|
|
65
|
+
promptCaching: EffectiveCapability;
|
|
66
|
+
nativeTokenCounting: EffectiveCapability;
|
|
67
|
+
mediaForms: {
|
|
68
|
+
imageUrl: EffectiveCapability;
|
|
69
|
+
imageBase64: EffectiveCapability;
|
|
70
|
+
fileId: EffectiveCapability;
|
|
71
|
+
audioUrl: EffectiveCapability;
|
|
72
|
+
audioBase64: EffectiveCapability;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export interface ResolvedProviderRuntime<TAdapter = LLMProvider> {
|
|
76
|
+
identity: {
|
|
77
|
+
providerId: ProviderId;
|
|
78
|
+
modelId: string;
|
|
79
|
+
endpointId: EndpointProfileId;
|
|
80
|
+
protocol: GenerationProtocol;
|
|
81
|
+
};
|
|
82
|
+
model: ModelDescriptor;
|
|
83
|
+
endpoint: EndpointProfile;
|
|
84
|
+
adapter: TAdapter;
|
|
85
|
+
effectiveCapabilities: EffectiveModelCapabilities;
|
|
86
|
+
runtimePolicy?: RuntimePolicy;
|
|
87
|
+
}
|
|
88
|
+
export interface RegistryRuleEvidence {
|
|
89
|
+
ruleId: string;
|
|
90
|
+
classification: "routing" | "policy" | "protocol" | "endpoint";
|
|
91
|
+
source: string;
|
|
92
|
+
verifiedAt: "2026-08-12";
|
|
93
|
+
}
|
|
94
|
+
export declare const registryEvidence: readonly RegistryRuleEvidence[];
|
|
95
|
+
export declare const cacheCapabilityEvidence: readonly CacheCapabilityEvidence[];
|
|
96
|
+
export declare const tokenMeasurementEvidence: readonly TokenMeasurementEvidence[];
|
|
97
|
+
export declare function defaultModelForProvider(providerId: ProviderId): string;
|
|
98
|
+
export declare function defaultEndpointForProvider(providerId: ProviderId): EndpointProfileId;
|
|
99
|
+
export declare class ModelRegistry {
|
|
100
|
+
resolve(modelId: string, providerId?: ProviderId): ModelRegistration | undefined;
|
|
101
|
+
}
|
|
102
|
+
export declare const modelRegistry: ModelRegistry;
|
|
103
|
+
export declare function normalizeModelId(providerId: string, modelId: string): string;
|
|
104
|
+
export declare function getRuntimePolicy(providerId: string, modelId: string): RuntimePolicy;
|
|
105
|
+
export declare const protocolRuntimeCapabilities: Record<GenerationProtocol, ProtocolRuntimeCapabilities>;
|
|
106
|
+
export declare const endpointRuntimeCapabilities: Partial<Record<EndpointProfileId, EndpointRuntimeCapabilities>>;
|
|
107
|
+
export declare function resolveEffectiveCapability<T = boolean>(layers: readonly {
|
|
108
|
+
layer: CapabilityEvidenceLayer;
|
|
109
|
+
state: CapabilityState;
|
|
110
|
+
value?: T;
|
|
111
|
+
}[]): EffectiveCapability<T>;
|
|
112
|
+
export declare function resolveEffectiveModelCapabilities(input: {
|
|
113
|
+
model: ModelDescriptor;
|
|
114
|
+
protocol: GenerationProtocol;
|
|
115
|
+
endpointCapabilities?: EndpointRuntimeCapabilities;
|
|
116
|
+
}): EffectiveModelCapabilities;
|
|
117
|
+
export declare function generationProtocol(protocol: EndpointProtocol): GenerationProtocol | undefined;
|
|
118
|
+
export declare function endpointCapabilitiesFor(endpointId: EndpointProfileId, preserveEndpointIdentity: boolean, preserveCacheEvidence?: boolean): EndpointRuntimeCapabilities | undefined;
|
|
119
|
+
export declare function isKnownProviderId(value: string): value is ProviderId;
|