@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
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const TRANSPORT_ONLY_KEYS = new Set([
|
|
3
|
+
"apiKey", "api_key", "bearerToken", "bearer_token", "authorization", "credential",
|
|
4
|
+
"credentials", "retry", "maxRetries", "baseDelay", "timeout", "signal", "access_token", "refresh_token", "token", "secret", "x-api-key",
|
|
5
|
+
]);
|
|
6
|
+
export function createProviderRequestPlan(input) {
|
|
7
|
+
const options = materialOptions(input.options ?? {});
|
|
8
|
+
const plan = {
|
|
9
|
+
providerId: input.providerId,
|
|
10
|
+
modelId: input.modelId,
|
|
11
|
+
endpoint: sanitizeEndpoint(input.endpoint),
|
|
12
|
+
context: clone(input.context),
|
|
13
|
+
tools: clone(input.tools),
|
|
14
|
+
options,
|
|
15
|
+
};
|
|
16
|
+
const stablePrefix = {
|
|
17
|
+
providerId: plan.providerId,
|
|
18
|
+
modelId: plan.modelId,
|
|
19
|
+
endpoint: plan.endpoint,
|
|
20
|
+
context: stablePrefixContext(plan.context),
|
|
21
|
+
tools: plan.tools,
|
|
22
|
+
options: plan.options,
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
...plan,
|
|
26
|
+
fingerprint: sha256(stableJson(plan)),
|
|
27
|
+
stablePrefixFingerprint: sha256(stableJson(stablePrefix)),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Build the plan from a resolved provider when the runner only has the public provider object. */
|
|
31
|
+
export function createProviderRequestPlanForProvider(provider, context, tools, options) {
|
|
32
|
+
const descriptor = provider.descriptor?.() ?? { provider: "unknown", protocol: "unknown", model: "unknown" };
|
|
33
|
+
const identity = provider.requestPlanIdentity?.();
|
|
34
|
+
return createProviderRequestPlan({
|
|
35
|
+
providerId: identity?.providerId ?? descriptor.provider,
|
|
36
|
+
modelId: identity?.modelId ?? descriptor.model,
|
|
37
|
+
endpoint: {
|
|
38
|
+
id: identity?.endpoint?.id ?? `${descriptor.provider}.${descriptor.protocol}`,
|
|
39
|
+
protocol: identity?.endpoint?.protocol ?? descriptor.protocol,
|
|
40
|
+
baseURL: identity?.endpoint?.baseURL ?? "",
|
|
41
|
+
},
|
|
42
|
+
context,
|
|
43
|
+
tools,
|
|
44
|
+
options,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function estimateProviderPromptTokens(context, tools) {
|
|
48
|
+
const bytes = new TextEncoder().encode(stableJson({ context, tools })).byteLength;
|
|
49
|
+
return Math.max(1, Math.ceil(bytes / 4));
|
|
50
|
+
}
|
|
51
|
+
/** Bind a preflight count to its exact provider-visible request. Replay only reuses matching facts. */
|
|
52
|
+
export function recordPromptMeasurement(plan, measurement) {
|
|
53
|
+
return {
|
|
54
|
+
requestFingerprint: plan.fingerprint,
|
|
55
|
+
inputTokens: requireNonNegativeInteger(measurement.inputTokens, "inputTokens"),
|
|
56
|
+
source: clone(measurement.source),
|
|
57
|
+
confidence: measurement.confidence,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function measurementForPlan(plan, recorded) {
|
|
61
|
+
if (!recorded || recorded.requestFingerprint !== plan.fingerprint)
|
|
62
|
+
return undefined;
|
|
63
|
+
if (!Number.isSafeInteger(recorded.inputTokens) || recorded.inputTokens < 0)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (recorded.confidence !== "exact" && recorded.confidence !== "high_confidence" && recorded.confidence !== "low_confidence")
|
|
66
|
+
return undefined;
|
|
67
|
+
const source = recorded.source;
|
|
68
|
+
if (!source || typeof source !== "object")
|
|
69
|
+
return undefined;
|
|
70
|
+
if (source.kind === "native" && typeof source["provider"] === "string" && source["provider"].length > 0)
|
|
71
|
+
return clone(recorded);
|
|
72
|
+
if (source.kind === "local_exact" && typeof source.tokenizer === "string" && source.tokenizer.length > 0)
|
|
73
|
+
return clone(recorded);
|
|
74
|
+
if (source.kind === "postflight")
|
|
75
|
+
return clone(recorded);
|
|
76
|
+
if (source.kind === "heuristic")
|
|
77
|
+
return clone(recorded);
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
/** Normalize postflight provider facts without turning estimates into actual usage. */
|
|
81
|
+
export function normalizeProviderUsage(usage) {
|
|
82
|
+
const inputTokens = requireNonNegativeInteger(usage.inputTokens, "inputTokens");
|
|
83
|
+
const outputTokens = requireNonNegativeInteger(usage.outputTokens, "outputTokens");
|
|
84
|
+
const cacheReadInputTokens = optionalNonNegativeInteger(usage.cacheReadInputTokens, "cacheReadInputTokens");
|
|
85
|
+
const cacheCreationInputTokens = optionalNonNegativeInteger(usage.cacheCreationInputTokens, "cacheCreationInputTokens");
|
|
86
|
+
const reasoningTokens = optionalNonNegativeInteger(usage.reasoningTokens, "reasoningTokens");
|
|
87
|
+
const cached = (cacheReadInputTokens ?? 0) + (cacheCreationInputTokens ?? 0);
|
|
88
|
+
if (cached > inputTokens)
|
|
89
|
+
throw new RangeError("cache token subsets cannot exceed inputTokens");
|
|
90
|
+
if (reasoningTokens !== undefined && reasoningTokens > outputTokens) {
|
|
91
|
+
throw new RangeError("reasoningTokens must be a subset of outputTokens");
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
inputTokens,
|
|
95
|
+
uncachedInputTokens: inputTokens - cached,
|
|
96
|
+
outputTokens,
|
|
97
|
+
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
98
|
+
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
99
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Cost is derived only from an explicit, time-valid host snapshot; otherwise it stays unknown. */
|
|
103
|
+
export function priceProviderUsage(usage, snapshot, observedAt = new Date()) {
|
|
104
|
+
const at = typeof observedAt === "string" ? new Date(observedAt) : observedAt;
|
|
105
|
+
const from = new Date(snapshot.effectiveFrom);
|
|
106
|
+
const expires = snapshot.expiresAt ? new Date(snapshot.expiresAt) : undefined;
|
|
107
|
+
const rates = snapshot.ratesPerMillion;
|
|
108
|
+
const requiredRates = [rates.input, rates.output];
|
|
109
|
+
if (!snapshot.version || !snapshot.currency || Number.isNaN(at.valueOf()) || Number.isNaN(from.valueOf())
|
|
110
|
+
|| requiredRates.some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)
|
|
111
|
+
|| Object.values(rates).some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)) {
|
|
112
|
+
return { source: "unpriced", reason: "invalid_pricing_snapshot" };
|
|
113
|
+
}
|
|
114
|
+
if (at < from)
|
|
115
|
+
return { source: "unpriced", reason: "pricing_snapshot_not_effective" };
|
|
116
|
+
if (expires && (Number.isNaN(expires.valueOf()) || at >= expires)) {
|
|
117
|
+
return { source: "unpriced", reason: "pricing_snapshot_expired" };
|
|
118
|
+
}
|
|
119
|
+
const amount = (usage.uncachedInputTokens * rates.input
|
|
120
|
+
+ usage.outputTokens * rates.output
|
|
121
|
+
+ (usage.cacheReadInputTokens ?? 0) * (rates.cacheRead ?? rates.input)
|
|
122
|
+
+ (usage.cacheCreationInputTokens ?? 0) * (rates.cacheCreation ?? rates.input)
|
|
123
|
+
+ (usage.reasoningTokens ?? 0) * (rates.reasoning ?? 0)) / 1_000_000;
|
|
124
|
+
return { source: "snapshot", currency: snapshot.currency, amount, pricingVersion: snapshot.version };
|
|
125
|
+
}
|
|
126
|
+
function materialOptions(options) {
|
|
127
|
+
return sanitizeMaterialValue(options);
|
|
128
|
+
}
|
|
129
|
+
function sanitizeEndpoint(endpoint) {
|
|
130
|
+
try {
|
|
131
|
+
const url = new URL(endpoint.baseURL);
|
|
132
|
+
url.username = "";
|
|
133
|
+
url.password = "";
|
|
134
|
+
url.search = "";
|
|
135
|
+
url.hash = "";
|
|
136
|
+
return { ...clone(endpoint), baseURL: url.toString().replace(/\/$/, "") };
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return { ...clone(endpoint), baseURL: "" };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function sanitizeMaterialValue(value) {
|
|
143
|
+
if (value === undefined || typeof value === "function")
|
|
144
|
+
return undefined;
|
|
145
|
+
if (Array.isArray(value))
|
|
146
|
+
return value.map(sanitizeMaterialValue).filter(item => item !== undefined);
|
|
147
|
+
if (value !== null && typeof value === "object") {
|
|
148
|
+
return Object.fromEntries(Object.keys(value).sort().flatMap(key => {
|
|
149
|
+
if (TRANSPORT_ONLY_KEYS.has(key) || isTransportOnlyKey(key))
|
|
150
|
+
return [];
|
|
151
|
+
const sanitized = sanitizeMaterialValue(value[key]);
|
|
152
|
+
return sanitized === undefined ? [] : [[key, sanitized]];
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
function isTransportOnlyKey(key) {
|
|
158
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
159
|
+
return normalized.includes("authorization") || normalized.includes("credential")
|
|
160
|
+
|| normalized.includes("accesstoken") || normalized.includes("refreshtoken")
|
|
161
|
+
|| normalized.includes("apikey") || normalized === "bearer" || normalized === "token"
|
|
162
|
+
|| normalized === "secret" || normalized === "xapikey";
|
|
163
|
+
}
|
|
164
|
+
function stableJson(value) {
|
|
165
|
+
if (value === null || typeof value !== "object")
|
|
166
|
+
return JSON.stringify(value);
|
|
167
|
+
if (Array.isArray(value))
|
|
168
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
169
|
+
const object = value;
|
|
170
|
+
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
|
|
171
|
+
}
|
|
172
|
+
function stablePrefixContext(context) {
|
|
173
|
+
const frozenPrefixLen = context.frozenPrefixLen ?? 0;
|
|
174
|
+
return {
|
|
175
|
+
systemText: context.systemText,
|
|
176
|
+
...(context.systemStable !== undefined ? { systemStable: context.systemStable } : {}),
|
|
177
|
+
...(context.systemKnowledge !== undefined ? { systemKnowledge: context.systemKnowledge } : {}),
|
|
178
|
+
frozenPrefixLen,
|
|
179
|
+
turns: clone(context.turns.slice(0, frozenPrefixLen)),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function sha256(value) {
|
|
183
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
184
|
+
}
|
|
185
|
+
function clone(value) {
|
|
186
|
+
if (value === undefined || value === null || typeof value !== "object")
|
|
187
|
+
return value;
|
|
188
|
+
if (Array.isArray(value))
|
|
189
|
+
return value.map(clone);
|
|
190
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clone(item)]));
|
|
191
|
+
}
|
|
192
|
+
function requireNonNegativeInteger(value, name) {
|
|
193
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
194
|
+
throw new RangeError(`${name} must be a non-negative safe integer`);
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
function optionalNonNegativeInteger(value, name) {
|
|
198
|
+
return value === undefined ? undefined : requireNonNegativeInteger(value, name);
|
|
199
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spc_011-C-07: normalizes each vendor's raw postflight usage object into the shared
|
|
3
|
+
* `ProviderUsage` shape (`../types.js`). One function per wire family, not one
|
|
4
|
+
* per provider — DeepSeek/Kimi/GLM/Qwen/MiniMax's OpenAI-wire variants all route through
|
|
5
|
+
* `normalizeOpenAIUsage` via `OpenAIChatProvider` inheritance, and their Anthropic-wire variants
|
|
6
|
+
* route through `normalizeAnthropicUsage` via `AnthropicCompatibleProvider` inheritance — the
|
|
7
|
+
* "8 providers" the spec counts are 8 *providers*, not 8 independent parsing implementations.
|
|
8
|
+
*
|
|
9
|
+
* Reuses `openAICachedPromptTokens` (`./base.js`) for the OpenAI-family cache figure rather than
|
|
10
|
+
* re-deriving it — that function already covers the OpenAI/Qwen/MiniMax/GLM/Kimi standard shape
|
|
11
|
+
* plus DeepSeek's `prompt_cache_hit_tokens` variant.
|
|
12
|
+
*
|
|
13
|
+
* `TokenUsage`/`UsageEvent` are otherwise untouched by this module. Missing or malformed usage
|
|
14
|
+
* returns `undefined`; absence is not a zero-token measurement.
|
|
15
|
+
*/
|
|
16
|
+
import type { ProviderUsage } from "../types.js";
|
|
17
|
+
/**
|
|
18
|
+
* Covers both OpenAI wire shapes actually in use: Chat Completions (`prompt_tokens`/
|
|
19
|
+
* `completion_tokens`/`completion_tokens_details.reasoning_tokens`, used by `openai.ts` and every
|
|
20
|
+
* `OpenAIChatProvider` subclass) and the Responses API (`input_tokens`/`output_tokens`/
|
|
21
|
+
* `output_tokens_details.reasoning_tokens`, used by `openai-responses.ts`) — the two field-name
|
|
22
|
+
* conventions are read via fallback, and only one will ever be present on a given raw object.
|
|
23
|
+
*/
|
|
24
|
+
export declare function normalizeOpenAIUsage(usage: unknown): ProviderUsage | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Anthropic's raw `input_tokens` is UNCACHED input only (unlike OpenAI's `prompt_tokens`, which
|
|
27
|
+
* is already cache-inclusive) — `anthropic.ts`'s own `stream()` sums `input_tokens +
|
|
28
|
+
* cache_read_input_tokens + cache_creation_input_tokens` into the full prompt size for the same
|
|
29
|
+
* reason context-pressure accounting needs it (see that file's comment on why excluding cached
|
|
30
|
+
* tokens would suppress compaction until a 413). This function replicates that same sum so
|
|
31
|
+
* `ProviderUsage.inputTokens` means the same "full prompt size" thing across vendors — reading
|
|
32
|
+
* raw `input_tokens` alone here would silently undercount every cache-heavy Anthropic turn.
|
|
33
|
+
* No `reasoning_tokens`-equivalent field exists in this SDK's `Usage` type, so that field stays
|
|
34
|
+
* unset rather than guessed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeAnthropicUsage(usage: unknown): ProviderUsage | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* `@google/generative-ai`'s `UsageMetadata` has no reasoning/thoughts token field and no separate
|
|
39
|
+
* cache-write count (only `cachedContentTokenCount`, a read figure) — `reasoningTokens` and
|
|
40
|
+
* `cacheCreationInputTokens` stay unset rather than invented.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeGeminiUsage(usage: unknown): ProviderUsage | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Ollama's final stream chunk (`done: true`) carries `prompt_eval_count`/`eval_count` — no cache
|
|
45
|
+
* or reasoning concept exists in its API at all, so both stay unset. Before this card `ollama.ts`
|
|
46
|
+
* read neither field; this is the first usage extraction it has ever had.
|
|
47
|
+
*/
|
|
48
|
+
export declare function normalizeOllamaUsage(chunk: unknown): ProviderUsage | undefined;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { openAICachedPromptTokens } from "./base.js";
|
|
2
|
+
import { ProtocolResponseError } from "./protocol-adapter.js";
|
|
3
|
+
function readNumber(obj, key, protocol) {
|
|
4
|
+
const value = obj?.[key];
|
|
5
|
+
if (value === undefined || value === null)
|
|
6
|
+
return undefined;
|
|
7
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
8
|
+
throw new ProtocolResponseError(protocol, `usage.${key} must be a non-negative safe integer`);
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function hasOwn(obj, key) {
|
|
13
|
+
return obj !== undefined && Object.prototype.hasOwnProperty.call(obj, key);
|
|
14
|
+
}
|
|
15
|
+
function openAICacheTelemetry(usage) {
|
|
16
|
+
const promptDetails = usage?.prompt_tokens_details;
|
|
17
|
+
const inputDetails = usage?.input_tokens_details;
|
|
18
|
+
if (hasOwn(usage, "prompt_cache_hit_tokens") || hasOwn(usage, "prompt_cache_miss_tokens")) {
|
|
19
|
+
return { cacheTelemetryStatus: "measured", cacheTelemetrySource: "deepseek_prompt_cache" };
|
|
20
|
+
}
|
|
21
|
+
if (hasOwn(promptDetails, "cached_tokens") || hasOwn(inputDetails, "cached_tokens")) {
|
|
22
|
+
return { cacheTelemetryStatus: "measured", cacheTelemetrySource: "openai_prompt_details" };
|
|
23
|
+
}
|
|
24
|
+
return { cacheTelemetryStatus: "unavailable" };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Covers both OpenAI wire shapes actually in use: Chat Completions (`prompt_tokens`/
|
|
28
|
+
* `completion_tokens`/`completion_tokens_details.reasoning_tokens`, used by `openai.ts` and every
|
|
29
|
+
* `OpenAIChatProvider` subclass) and the Responses API (`input_tokens`/`output_tokens`/
|
|
30
|
+
* `output_tokens_details.reasoning_tokens`, used by `openai-responses.ts`) — the two field-name
|
|
31
|
+
* conventions are read via fallback, and only one will ever be present on a given raw object.
|
|
32
|
+
*/
|
|
33
|
+
export function normalizeOpenAIUsage(usage) {
|
|
34
|
+
const u = usage && typeof usage === "object" ? usage : undefined;
|
|
35
|
+
const protocol = hasOwn(u, "input_tokens") ? "openai-responses" : "openai-chat";
|
|
36
|
+
const rawInput = readNumber(u, "prompt_tokens", protocol) ?? readNumber(u, "input_tokens", protocol);
|
|
37
|
+
const rawOutput = readNumber(u, "completion_tokens", protocol) ?? readNumber(u, "output_tokens", protocol);
|
|
38
|
+
if (rawInput === undefined && rawOutput === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
const inputTokens = rawInput ?? 0;
|
|
41
|
+
const outputTokens = rawOutput ?? 0;
|
|
42
|
+
const promptDetails = u?.prompt_tokens_details;
|
|
43
|
+
const inputDetails = u?.input_tokens_details;
|
|
44
|
+
readNumber(promptDetails, "cached_tokens", protocol);
|
|
45
|
+
readNumber(inputDetails, "cached_tokens", protocol);
|
|
46
|
+
const cacheHit = readNumber(u, "prompt_cache_hit_tokens", protocol);
|
|
47
|
+
const cacheMiss = readNumber(u, "prompt_cache_miss_tokens", protocol);
|
|
48
|
+
const cacheReadInputTokens = openAICachedPromptTokens(usage);
|
|
49
|
+
const details = (u?.completion_tokens_details ?? u?.output_tokens_details);
|
|
50
|
+
const reasoningTokens = readNumber(details, "reasoning_tokens", protocol);
|
|
51
|
+
if (cacheReadInputTokens > inputTokens) {
|
|
52
|
+
throw new ProtocolResponseError(protocol, "cache token subsets cannot exceed input tokens");
|
|
53
|
+
}
|
|
54
|
+
if (cacheHit !== undefined && cacheMiss !== undefined && cacheHit + cacheMiss !== inputTokens) {
|
|
55
|
+
throw new ProtocolResponseError(protocol, "DeepSeek cache hit and miss tokens must sum to prompt tokens");
|
|
56
|
+
}
|
|
57
|
+
const providerUsage = {
|
|
58
|
+
inputTokens,
|
|
59
|
+
outputTokens,
|
|
60
|
+
...(cacheReadInputTokens > 0 ? { cacheReadInputTokens } : {}),
|
|
61
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
62
|
+
...openAICacheTelemetry(u),
|
|
63
|
+
};
|
|
64
|
+
return providerUsage;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Anthropic's raw `input_tokens` is UNCACHED input only (unlike OpenAI's `prompt_tokens`, which
|
|
68
|
+
* is already cache-inclusive) — `anthropic.ts`'s own `stream()` sums `input_tokens +
|
|
69
|
+
* cache_read_input_tokens + cache_creation_input_tokens` into the full prompt size for the same
|
|
70
|
+
* reason context-pressure accounting needs it (see that file's comment on why excluding cached
|
|
71
|
+
* tokens would suppress compaction until a 413). This function replicates that same sum so
|
|
72
|
+
* `ProviderUsage.inputTokens` means the same "full prompt size" thing across vendors — reading
|
|
73
|
+
* raw `input_tokens` alone here would silently undercount every cache-heavy Anthropic turn.
|
|
74
|
+
* No `reasoning_tokens`-equivalent field exists in this SDK's `Usage` type, so that field stays
|
|
75
|
+
* unset rather than guessed.
|
|
76
|
+
*/
|
|
77
|
+
export function normalizeAnthropicUsage(usage) {
|
|
78
|
+
const u = usage && typeof usage === "object" ? usage : undefined;
|
|
79
|
+
const rawUncachedInput = readNumber(u, "input_tokens", "anthropic-messages");
|
|
80
|
+
const rawCacheRead = readNumber(u, "cache_read_input_tokens", "anthropic-messages");
|
|
81
|
+
const rawCacheCreation = readNumber(u, "cache_creation_input_tokens", "anthropic-messages");
|
|
82
|
+
const rawOutput = readNumber(u, "output_tokens", "anthropic-messages");
|
|
83
|
+
if (rawUncachedInput === undefined && rawCacheRead === undefined && rawCacheCreation === undefined && rawOutput === undefined)
|
|
84
|
+
return undefined;
|
|
85
|
+
const uncachedInput = rawUncachedInput ?? 0;
|
|
86
|
+
const cacheReadInputTokens = rawCacheRead ?? 0;
|
|
87
|
+
const cacheCreationInputTokens = rawCacheCreation ?? 0;
|
|
88
|
+
const outputTokens = rawOutput ?? 0;
|
|
89
|
+
const providerUsage = {
|
|
90
|
+
inputTokens: uncachedInput + cacheReadInputTokens + cacheCreationInputTokens,
|
|
91
|
+
outputTokens,
|
|
92
|
+
...(cacheReadInputTokens > 0 ? { cacheReadInputTokens } : {}),
|
|
93
|
+
...(cacheCreationInputTokens > 0 ? { cacheCreationInputTokens } : {}),
|
|
94
|
+
...(hasOwn(u, "cache_read_input_tokens") || hasOwn(u, "cache_creation_input_tokens")
|
|
95
|
+
? { cacheTelemetryStatus: "measured", cacheTelemetrySource: "anthropic_usage" }
|
|
96
|
+
: { cacheTelemetryStatus: "unavailable" }),
|
|
97
|
+
};
|
|
98
|
+
return providerUsage;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `@google/generative-ai`'s `UsageMetadata` has no reasoning/thoughts token field and no separate
|
|
102
|
+
* cache-write count (only `cachedContentTokenCount`, a read figure) — `reasoningTokens` and
|
|
103
|
+
* `cacheCreationInputTokens` stay unset rather than invented.
|
|
104
|
+
*/
|
|
105
|
+
export function normalizeGeminiUsage(usage) {
|
|
106
|
+
const u = usage && typeof usage === "object" ? usage : undefined;
|
|
107
|
+
const rawInput = readNumber(u, "promptTokenCount", "gemini");
|
|
108
|
+
const rawOutput = readNumber(u, "candidatesTokenCount", "gemini");
|
|
109
|
+
if (rawInput === undefined && rawOutput === undefined)
|
|
110
|
+
return undefined;
|
|
111
|
+
const inputTokens = rawInput ?? 0;
|
|
112
|
+
const outputTokens = rawOutput ?? 0;
|
|
113
|
+
const cacheReadInputTokens = readNumber(u, "cachedContentTokenCount", "gemini");
|
|
114
|
+
if ((cacheReadInputTokens ?? 0) > inputTokens) {
|
|
115
|
+
throw new ProtocolResponseError("gemini", "cache token subsets cannot exceed input tokens");
|
|
116
|
+
}
|
|
117
|
+
const providerUsage = {
|
|
118
|
+
inputTokens,
|
|
119
|
+
outputTokens,
|
|
120
|
+
...(cacheReadInputTokens ? { cacheReadInputTokens } : {}),
|
|
121
|
+
...(hasOwn(u, "cachedContentTokenCount")
|
|
122
|
+
? { cacheTelemetryStatus: "measured", cacheTelemetrySource: "gemini_usage" }
|
|
123
|
+
: { cacheTelemetryStatus: "unavailable" }),
|
|
124
|
+
};
|
|
125
|
+
return providerUsage;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Ollama's final stream chunk (`done: true`) carries `prompt_eval_count`/`eval_count` — no cache
|
|
129
|
+
* or reasoning concept exists in its API at all, so both stay unset. Before this card `ollama.ts`
|
|
130
|
+
* read neither field; this is the first usage extraction it has ever had.
|
|
131
|
+
*/
|
|
132
|
+
export function normalizeOllamaUsage(chunk) {
|
|
133
|
+
const u = chunk && typeof chunk === "object" ? chunk : undefined;
|
|
134
|
+
const rawInput = readNumber(u, "prompt_eval_count", "ollama-chat");
|
|
135
|
+
const rawOutput = readNumber(u, "eval_count", "ollama-chat");
|
|
136
|
+
if (rawInput === undefined && rawOutput === undefined)
|
|
137
|
+
return undefined;
|
|
138
|
+
return { inputTokens: rawInput ?? 0, outputTokens: rawOutput ?? 0, cacheTelemetryStatus: "unavailable" };
|
|
139
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { ProviderId } from "./profiles.js";
|
|
1
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
2
|
+
import type { ProviderId } from "./endpoints.js";
|
|
4
3
|
export type EndpointProfileKey = keyof typeof endpointProfiles;
|
|
5
4
|
export interface AnthropicVendorProfile {
|
|
6
5
|
/** Identity advertised in `descriptor().provider`. */
|
|
@@ -9,44 +8,32 @@ export interface AnthropicVendorProfile {
|
|
|
9
8
|
defaultModel: string;
|
|
10
9
|
/** Endpoint profile whose `baseURL` is the Anthropic-compatible wire for this vendor. */
|
|
11
10
|
baseURLProfileKey: EndpointProfileKey;
|
|
12
|
-
/** Recommended `maxTurns` per model id; missing model → empty policy. */
|
|
13
|
-
policies: Record<string, RuntimePolicy>;
|
|
14
11
|
}
|
|
15
|
-
export declare const DEEPSEEK_POLICIES: Record<string, RuntimePolicy>;
|
|
16
|
-
export declare const KIMI_POLICIES: Record<string, RuntimePolicy>;
|
|
17
|
-
export declare const QWEN_POLICIES: Record<string, RuntimePolicy>;
|
|
18
|
-
export declare const GLM_POLICIES: Record<string, RuntimePolicy>;
|
|
19
|
-
export declare const MINIMAX_POLICIES: Record<string, RuntimePolicy>;
|
|
20
12
|
export declare const anthropicVendorProfiles: {
|
|
21
13
|
deepseek: {
|
|
22
14
|
providerId: "deepseek";
|
|
23
15
|
defaultModel: string;
|
|
24
16
|
baseURLProfileKey: "deepseek.anthropic";
|
|
25
|
-
policies: Record<string, RuntimePolicy>;
|
|
26
17
|
};
|
|
27
18
|
kimi: {
|
|
28
19
|
providerId: "kimi";
|
|
29
20
|
defaultModel: string;
|
|
30
21
|
baseURLProfileKey: "kimi.anthropic";
|
|
31
|
-
policies: Record<string, RuntimePolicy>;
|
|
32
22
|
};
|
|
33
23
|
qwen: {
|
|
34
24
|
providerId: "qwen";
|
|
35
25
|
defaultModel: string;
|
|
36
26
|
baseURLProfileKey: "qwen.anthropic";
|
|
37
|
-
policies: Record<string, RuntimePolicy>;
|
|
38
27
|
};
|
|
39
28
|
glm: {
|
|
40
29
|
providerId: "glm";
|
|
41
30
|
defaultModel: string;
|
|
42
31
|
baseURLProfileKey: "glm.anthropic";
|
|
43
|
-
policies: Record<string, RuntimePolicy>;
|
|
44
32
|
};
|
|
45
33
|
minimax: {
|
|
46
34
|
providerId: "minimax";
|
|
47
35
|
defaultModel: string;
|
|
48
36
|
baseURLProfileKey: "minimax.anthropic";
|
|
49
|
-
policies: Record<string, RuntimePolicy>;
|
|
50
37
|
};
|
|
51
38
|
};
|
|
52
39
|
export type AnthropicVendorId = keyof typeof anthropicVendorProfiles;
|
|
@@ -1,64 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"moonshot-v1-32k": { maxTurns: 20 },
|
|
11
|
-
"moonshot-v1-128k": { maxTurns: 30 },
|
|
12
|
-
"kimi-k2.5": { maxTurns: 30 },
|
|
13
|
-
"kimi-k2.6": { maxTurns: 35 },
|
|
14
|
-
"kimi-k2-thinking": { maxTurns: 50 },
|
|
15
|
-
"kimi-k2-thinking-turbo": { maxTurns: 40 },
|
|
16
|
-
};
|
|
17
|
-
export const QWEN_POLICIES = {
|
|
18
|
-
"qwen3.7-max-preview": { maxTurns: 45 },
|
|
19
|
-
"qwen3.7-plus-preview": { maxTurns: 40 },
|
|
20
|
-
"qwen3.6-max-preview": { maxTurns: 40 },
|
|
21
|
-
"qwen3.6-plus": { maxTurns: 35 },
|
|
22
|
-
"qwen3.6-flash": { maxTurns: 20 },
|
|
23
|
-
"qwen3.6-35b-a3b": { maxTurns: 25 },
|
|
24
|
-
"qwen3.6-27b": { maxTurns: 25 },
|
|
25
|
-
"qwen3.5-plus": { maxTurns: 35 },
|
|
26
|
-
"qwen3.5-flash": { maxTurns: 20 },
|
|
27
|
-
"qwen3.5-397b-a17b": { maxTurns: 35 },
|
|
28
|
-
"qwen3.5-122b-a10b": { maxTurns: 25 },
|
|
29
|
-
"qwen3.5-35b-a3b": { maxTurns: 20 },
|
|
30
|
-
"qwen3.5-27b": { maxTurns: 20 },
|
|
31
|
-
};
|
|
32
|
-
export const GLM_POLICIES = {
|
|
33
|
-
"glm-5.2": { maxTurns: 50 },
|
|
34
|
-
"glm/glm-5.2": { maxTurns: 50 },
|
|
35
|
-
"glm-5.1": { maxTurns: 50 },
|
|
36
|
-
"glm/glm-5.1": { maxTurns: 50 },
|
|
37
|
-
"glm-4-plus": { maxTurns: 35 },
|
|
38
|
-
"glm/glm-4-plus": { maxTurns: 35 },
|
|
39
|
-
"glm-4-flash": { maxTurns: 15 },
|
|
40
|
-
"glm/glm-4-flash": { maxTurns: 15 },
|
|
41
|
-
"glm-4-air": { maxTurns: 20 },
|
|
42
|
-
"glm/glm-4-air": { maxTurns: 20 },
|
|
43
|
-
};
|
|
44
|
-
export const MINIMAX_POLICIES = {
|
|
45
|
-
"MiniMax-M3": { maxTurns: 35 },
|
|
46
|
-
"MiniMax-M3-highspeed": { maxTurns: 35 },
|
|
47
|
-
"MiniMax-M2.7": { maxTurns: 35 },
|
|
48
|
-
"MiniMax-M2.7-highspeed": { maxTurns: 35 },
|
|
49
|
-
"MiniMax-M2.5": { maxTurns: 25 },
|
|
50
|
-
"MiniMax-M2.5-highspeed": { maxTurns: 25 },
|
|
51
|
-
"MiniMax-M2.1": { maxTurns: 25 },
|
|
52
|
-
"MiniMax-M2.1-highspeed": { maxTurns: 25 },
|
|
53
|
-
"MiniMax-M2": { maxTurns: 20 },
|
|
54
|
-
"MiniMax-Text-01": { maxTurns: 20 },
|
|
55
|
-
};
|
|
1
|
+
// Single source of truth for the Anthropic-compatible vendor backends (DeepSeek,
|
|
2
|
+
// Kimi, Qwen, GLM, MiniMax). Each backend differs only by data — provider id,
|
|
3
|
+
// default model, endpoint, and per-model runtime policy — so the generic
|
|
4
|
+
// `AnthropicCompatibleProvider` reads a profile from here instead of every
|
|
5
|
+
// backend subclassing `AnthropicProvider` purely to carry configuration.
|
|
6
|
+
//
|
|
7
|
+
// Runtime policy and default model resolution live in ModelRegistry; this module
|
|
8
|
+
// only carries Anthropic-compatible transport configuration.
|
|
9
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
56
10
|
export const anthropicVendorProfiles = {
|
|
57
|
-
deepseek: { providerId: "deepseek", defaultModel: "deepseek-v4-flash", baseURLProfileKey: "deepseek.anthropic"
|
|
58
|
-
kimi: { providerId: "kimi", defaultModel: "kimi-k2.6", baseURLProfileKey: "kimi.anthropic"
|
|
59
|
-
qwen: { providerId: "qwen", defaultModel: "qwen3.6-plus", baseURLProfileKey: "qwen.anthropic"
|
|
60
|
-
glm: { providerId: "glm", defaultModel: "glm-5.2", baseURLProfileKey: "glm.anthropic"
|
|
61
|
-
minimax: { providerId: "minimax", defaultModel: "MiniMax-M3", baseURLProfileKey: "minimax.anthropic"
|
|
11
|
+
deepseek: { providerId: "deepseek", defaultModel: "deepseek-v4-flash", baseURLProfileKey: "deepseek.anthropic" },
|
|
12
|
+
kimi: { providerId: "kimi", defaultModel: "kimi-k2.6", baseURLProfileKey: "kimi.anthropic" },
|
|
13
|
+
qwen: { providerId: "qwen", defaultModel: "qwen3.6-plus", baseURLProfileKey: "qwen.anthropic" },
|
|
14
|
+
glm: { providerId: "glm", defaultModel: "glm-5.2", baseURLProfileKey: "glm.anthropic" },
|
|
15
|
+
minimax: { providerId: "minimax", defaultModel: "MiniMax-M3", baseURLProfileKey: "minimax.anthropic" },
|
|
62
16
|
};
|
|
63
17
|
/** Resolve the Anthropic-compatible base URL for a vendor profile. */
|
|
64
18
|
export function anthropicVendorBaseURL(profile) {
|
|
@@ -95,8 +95,7 @@ export interface CanonicalRunnerRuntimeOptions {
|
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Canonical operation runtime used by the Node host.
|
|
98
|
-
* Every durable transition below is one of the canonical
|
|
99
|
-
* envelope or synthesized host transaction reaches core or storage.
|
|
98
|
+
* Every durable transition below is one of the canonical contract's five input classes.
|
|
100
99
|
*/
|
|
101
100
|
export declare class CanonicalRunnerRuntime {
|
|
102
101
|
private readonly options;
|