@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/base.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ export declare const INTERNAL_EXTENSION_KEYS: readonly string[];
|
|
|
18
18
|
export declare function omitExtensionKeys(extensions: Record<string, unknown> | undefined, keys: readonly string[]): Record<string, unknown>;
|
|
19
19
|
/**
|
|
20
20
|
* Cached-prompt-token count from an OpenAI-compatible usage object. Covers the
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Chat `prompt_tokens_details.cached_tokens`, Responses
|
|
22
|
+
* `input_tokens_details.cached_tokens`, and DeepSeek's `prompt_cache_hit_tokens`. These caches bill reads only,
|
|
23
23
|
* so there is no separate cache-creation count. The figure is a subset of
|
|
24
24
|
* `prompt_tokens` (the full prompt), surfaced for cost visibility — it must not
|
|
25
25
|
* be subtracted from the input count the kernel uses for context accounting.
|
package/dist/providers/base.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeToolResultPart, projectToolOutputToText } from "./content-normalization.js";
|
|
1
2
|
export class CircuitBreaker {
|
|
2
3
|
openAfter;
|
|
3
4
|
resetAfter;
|
|
@@ -43,8 +44,8 @@ export function omitExtensionKeys(extensions, keys) {
|
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
45
46
|
* Cached-prompt-token count from an OpenAI-compatible usage object. Covers the
|
|
46
|
-
*
|
|
47
|
-
*
|
|
47
|
+
* Chat `prompt_tokens_details.cached_tokens`, Responses
|
|
48
|
+
* `input_tokens_details.cached_tokens`, and DeepSeek's `prompt_cache_hit_tokens`. These caches bill reads only,
|
|
48
49
|
* so there is no separate cache-creation count. The figure is a subset of
|
|
49
50
|
* `prompt_tokens` (the full prompt), surfaced for cost visibility — it must not
|
|
50
51
|
* be subtracted from the input count the kernel uses for context accounting.
|
|
@@ -53,10 +54,12 @@ export function openAICachedPromptTokens(usage) {
|
|
|
53
54
|
if (!usage || typeof usage !== "object")
|
|
54
55
|
return 0;
|
|
55
56
|
const u = usage;
|
|
56
|
-
const
|
|
57
|
-
const
|
|
57
|
+
const promptDetails = u.prompt_tokens_details;
|
|
58
|
+
const inputDetails = u.input_tokens_details;
|
|
59
|
+
const standard = typeof promptDetails?.cached_tokens === "number" ? promptDetails.cached_tokens : 0;
|
|
60
|
+
const responses = typeof inputDetails?.cached_tokens === "number" ? inputDetails.cached_tokens : 0;
|
|
58
61
|
const deepseek = typeof u.prompt_cache_hit_tokens === "number" ? u.prompt_cache_hit_tokens : 0;
|
|
59
|
-
return Math.max(standard, deepseek);
|
|
62
|
+
return Math.max(standard, responses, deepseek);
|
|
60
63
|
}
|
|
61
64
|
/**
|
|
62
65
|
* Prompt-cache hit rate for one usage record: the fraction of the full prompt
|
|
@@ -140,11 +143,40 @@ export function toAnthropicContent(msg) {
|
|
|
140
143
|
throw new UnsupportedModalityError("audio", "anthropic");
|
|
141
144
|
}
|
|
142
145
|
if (p.type === "tool_result") {
|
|
143
|
-
return { type: "tool_result", tool_use_id: p.callId, content: p
|
|
146
|
+
return { type: "tool_result", tool_use_id: p.callId, content: toolResultAnthropicContent(p), is_error: p.isError };
|
|
144
147
|
}
|
|
145
148
|
return { type: "text", text: "" };
|
|
146
149
|
});
|
|
147
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* spc_012-N-03: a `ContentBlock` inside a structured tool result → Anthropic wire block.
|
|
153
|
+
* Anthropic's `tool_result.content` natively accepts text and image blocks. Anything else
|
|
154
|
+
* (audio/video/file, `fileId`/`object` sources with no Anthropic wire form) degrades to an
|
|
155
|
+
* explicit `[modality]` placeholder visible to the model, never silently dropped (INV-012-01).
|
|
156
|
+
*/
|
|
157
|
+
function contentBlockToAnthropic(block) {
|
|
158
|
+
if (block.type === "text")
|
|
159
|
+
return { type: "text", text: block.text };
|
|
160
|
+
if (block.type === "image") {
|
|
161
|
+
const src = block.source;
|
|
162
|
+
if (src.kind === "base64") {
|
|
163
|
+
return { type: "image", source: { type: "base64", media_type: block.mediaType ?? "image/png", data: src.data } };
|
|
164
|
+
}
|
|
165
|
+
if (src.kind === "url") {
|
|
166
|
+
return { type: "image", source: { type: "url", url: src.url } };
|
|
167
|
+
}
|
|
168
|
+
return { type: "text", text: "[image]" };
|
|
169
|
+
}
|
|
170
|
+
return { type: "text", text: `[${block.type}]` };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Structured `contentParts` win when present; otherwise `output` is the text form.
|
|
174
|
+
*/
|
|
175
|
+
function toolResultAnthropicContent(p) {
|
|
176
|
+
if (p.contentParts !== undefined)
|
|
177
|
+
return normalizeToolResultPart(p).blocks.map(contentBlockToAnthropic);
|
|
178
|
+
return p.output;
|
|
179
|
+
}
|
|
148
180
|
/**
|
|
149
181
|
* History turns with the volatile State turn appended as the latest turn, for
|
|
150
182
|
* providers that render it inline (OpenAI-family, Gemini, Ollama). Appending
|
|
@@ -166,7 +198,7 @@ export function toAnthropicMessages(turns, nativeReplay) {
|
|
|
166
198
|
if (msg.role === "tool") {
|
|
167
199
|
const parts = (msg.contentParts ?? [])
|
|
168
200
|
.filter((p) => p.type === "tool_result")
|
|
169
|
-
.map(p => ({ type: "tool_result", tool_use_id: p.callId, content: p
|
|
201
|
+
.map(p => ({ type: "tool_result", tool_use_id: p.callId, content: toolResultAnthropicContent(p), is_error: p.isError }));
|
|
170
202
|
if (parts.length)
|
|
171
203
|
result.push({ role: "user", content: parts });
|
|
172
204
|
continue;
|
|
@@ -246,10 +278,20 @@ export function toOpenAIMessageParams(context) {
|
|
|
246
278
|
// bindings, where the state is already inside `turns`.
|
|
247
279
|
for (const msg of turnsWithStateAppended(context)) {
|
|
248
280
|
if (msg.role === "tool") {
|
|
281
|
+
// spc_012-N-04: OpenAI **chat completions** tool-role messages accept text only — no
|
|
282
|
+
// structured tool_result content exists on this wire. Explicit text-only degradation:
|
|
283
|
+
// `output` is the constructor's text projection, which carries a visible `[modality]`
|
|
284
|
+
// placeholder for any structured block (INV-012-01 — degraded, not silently dropped).
|
|
285
|
+
// The Responses API (openai-responses.ts) does have native structured support and uses it.
|
|
249
286
|
const parts = (msg.contentParts ?? [])
|
|
250
287
|
.filter((p) => p.type === "tool_result");
|
|
251
288
|
for (const p of parts) {
|
|
252
|
-
|
|
289
|
+
const canonical = normalizeToolResultPart(p);
|
|
290
|
+
result.push({
|
|
291
|
+
role: "tool",
|
|
292
|
+
tool_call_id: p.callId,
|
|
293
|
+
content: projectToolOutputToText(canonical.blocks),
|
|
294
|
+
});
|
|
253
295
|
}
|
|
254
296
|
continue;
|
|
255
297
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CreateProviderOptions } from "./catalog.js";
|
|
2
|
+
import type { InputModality, ResolvedProviderRuntime } from "./model-registry.js";
|
|
3
|
+
export interface CapabilityRequirement {
|
|
4
|
+
requiredInputModalities?: readonly InputModality[];
|
|
5
|
+
tools?: boolean;
|
|
6
|
+
reasoning?: boolean;
|
|
7
|
+
minimumContextWindow?: number;
|
|
8
|
+
}
|
|
9
|
+
export type CapabilityRouteResult = {
|
|
10
|
+
ok: true;
|
|
11
|
+
runtime: ResolvedProviderRuntime;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
error: {
|
|
15
|
+
code: "no_capable_model";
|
|
16
|
+
requirement: CapabilityRequirement;
|
|
17
|
+
candidates: Array<{
|
|
18
|
+
model: string;
|
|
19
|
+
rejectedBy: string[];
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Deliberately policy-free first-match router. Unknown capability evidence stays eligible for
|
|
25
|
+
* forward compatibility; only evidence of unsupported capability rejects a candidate.
|
|
26
|
+
*/
|
|
27
|
+
export declare class CapabilityRouter {
|
|
28
|
+
route(requirement: CapabilityRequirement, candidates: readonly CreateProviderOptions[]): Promise<CapabilityRouteResult>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { resolveProviderRuntimeAsync } from "./catalog.js";
|
|
2
|
+
/**
|
|
3
|
+
* Deliberately policy-free first-match router. Unknown capability evidence stays eligible for
|
|
4
|
+
* forward compatibility; only evidence of unsupported capability rejects a candidate.
|
|
5
|
+
*/
|
|
6
|
+
export class CapabilityRouter {
|
|
7
|
+
async route(requirement, candidates) {
|
|
8
|
+
const rejected = [];
|
|
9
|
+
for (const candidate of candidates) {
|
|
10
|
+
let runtime;
|
|
11
|
+
try {
|
|
12
|
+
runtime = await resolveProviderRuntimeAsync(candidate);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
rejected.push({ model: candidate.model, rejectedBy: ["unavailable"] });
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const rejectedBy = rejects(requirement, runtime);
|
|
19
|
+
if (rejectedBy.length === 0)
|
|
20
|
+
return { ok: true, runtime };
|
|
21
|
+
rejected.push({ model: candidate.model, rejectedBy });
|
|
22
|
+
}
|
|
23
|
+
return { ok: false, error: { code: "no_capable_model", requirement, candidates: rejected } };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function rejects(requirement, runtime) {
|
|
27
|
+
const result = [];
|
|
28
|
+
for (const modality of requirement.requiredInputModalities ?? []) {
|
|
29
|
+
if (runtime.effectiveCapabilities.inputModalities[modality].state === "unsupported") {
|
|
30
|
+
result.push(`input:${modality}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (requirement.tools && runtime.effectiveCapabilities.tools.state === "unsupported")
|
|
34
|
+
result.push("tools");
|
|
35
|
+
if (requirement.reasoning && runtime.effectiveCapabilities.reasoning.state === "unsupported")
|
|
36
|
+
result.push("reasoning");
|
|
37
|
+
if (requirement.minimumContextWindow !== undefined
|
|
38
|
+
&& runtime.model.contextWindow !== undefined
|
|
39
|
+
&& runtime.model.contextWindow < requirement.minimumContextWindow) {
|
|
40
|
+
result.push("context");
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import type { LLMProvider } from "../types.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { type ResolvedProviderRuntime } from "./model-registry.js";
|
|
3
|
+
import { type EndpointProfileId, type ProviderId } from "./endpoints.js";
|
|
4
|
+
import { type CredentialOptions } from "./credentials.js";
|
|
5
|
+
import type { ModelCatalog } from "./model-catalog.js";
|
|
6
|
+
export type { EndpointProfileId } from "./endpoints.js";
|
|
4
7
|
export interface CreateProviderOptions {
|
|
5
|
-
model:
|
|
6
|
-
|
|
8
|
+
model: string;
|
|
9
|
+
/** Explicit credential; resolver-backed construction can omit it. */
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
bearerToken?: string;
|
|
12
|
+
credentialResolver?: CredentialOptions["credentialResolver"];
|
|
13
|
+
/** Host-provided catalog used only for lookup; it never carries routing policy. */
|
|
14
|
+
modelCatalog?: ModelCatalog;
|
|
7
15
|
provider?: ProviderId;
|
|
8
16
|
endpoint?: EndpointProfileId;
|
|
9
17
|
retry?: {
|
|
@@ -13,3 +21,7 @@ export interface CreateProviderOptions {
|
|
|
13
21
|
baseURL?: string;
|
|
14
22
|
}
|
|
15
23
|
export declare function createProvider(options: CreateProviderOptions): LLMProvider;
|
|
24
|
+
export declare function resolveProviderRuntime(options: CreateProviderOptions): ResolvedProviderRuntime;
|
|
25
|
+
/** I/O-capable equivalent for host credential resolvers and dynamic catalogs. */
|
|
26
|
+
export declare function resolveProviderRuntimeAsync(options: CreateProviderOptions): Promise<ResolvedProviderRuntime>;
|
|
27
|
+
export declare function createProviderAsync(options: CreateProviderOptions): Promise<LLMProvider>;
|
|
@@ -1,9 +1,46 @@
|
|
|
1
|
-
import { PROVIDER_REGISTRY, providerRegistryKey } from "./registry.js";
|
|
2
|
-
import {
|
|
1
|
+
import { PROVIDER_REGISTRY, providerRegistryKey, supportsBearerCredential } from "./registry.js";
|
|
2
|
+
import { defaultEndpointForProvider, endpointCapabilitiesFor, generationProtocol, modelRegistry, normalizeModelId, resolveEffectiveModelCapabilities, } from "./model-registry.js";
|
|
3
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
4
|
+
import { resolveCredential, resolveCredentialSync, CredentialResolutionError, } from "./credentials.js";
|
|
3
5
|
export function createProvider(options) {
|
|
4
|
-
|
|
6
|
+
return resolveProviderRuntime(options).adapter;
|
|
7
|
+
}
|
|
8
|
+
export function resolveProviderRuntime(options) {
|
|
9
|
+
const draft = resolveRuntimeDraft(options);
|
|
10
|
+
const credential = draft.providerId === "ollama"
|
|
11
|
+
? { type: "api_key", value: "" }
|
|
12
|
+
: resolveCredentialSync(draft.credentialRequest, options);
|
|
13
|
+
return constructResolvedRuntime(draft, credential, options);
|
|
14
|
+
}
|
|
15
|
+
/** I/O-capable equivalent for host credential resolvers and dynamic catalogs. */
|
|
16
|
+
export async function resolveProviderRuntimeAsync(options) {
|
|
17
|
+
const draft = await resolveRuntimeDraftAsync(options);
|
|
18
|
+
const credential = draft.providerId === "ollama"
|
|
19
|
+
? { type: "api_key", value: "" }
|
|
20
|
+
: await resolveCredential(draft.credentialRequest, options);
|
|
21
|
+
return constructResolvedRuntime(draft, credential, options);
|
|
22
|
+
}
|
|
23
|
+
export async function createProviderAsync(options) {
|
|
24
|
+
return (await resolveProviderRuntimeAsync(options)).adapter;
|
|
25
|
+
}
|
|
26
|
+
function resolveRuntimeDraft(options) {
|
|
5
27
|
const parsedProviderId = providerPrefix(options.model);
|
|
6
|
-
const
|
|
28
|
+
const providerHint = options.provider ?? parsedProviderId;
|
|
29
|
+
const initialRegistration = modelRegistry.resolve(options.model, providerHint);
|
|
30
|
+
return resolveRuntimeDraftWithRegistration(options, parsedProviderId, initialRegistration);
|
|
31
|
+
}
|
|
32
|
+
async function resolveRuntimeDraftAsync(options) {
|
|
33
|
+
const parsedProviderId = providerPrefix(options.model);
|
|
34
|
+
const providerHint = options.provider ?? parsedProviderId;
|
|
35
|
+
const fromCatalog = options.modelCatalog ? await options.modelCatalog.get(options.model) : undefined;
|
|
36
|
+
const initialRegistration = fromCatalog ?? modelRegistry.resolve(options.model, providerHint);
|
|
37
|
+
return resolveRuntimeDraftWithRegistration(options, parsedProviderId, initialRegistration);
|
|
38
|
+
}
|
|
39
|
+
function resolveRuntimeDraftWithRegistration(options, parsedProviderId, initialRegistration) {
|
|
40
|
+
const providerHint = options.provider ?? parsedProviderId;
|
|
41
|
+
const endpointId = (options.endpoint
|
|
42
|
+
?? initialRegistration?.defaultEndpointId
|
|
43
|
+
?? (providerHint ? defaultEndpointForProvider(providerHint) : undefined));
|
|
7
44
|
if (!endpointId) {
|
|
8
45
|
throw new Error(`Unknown model profile: ${options.model}. Pass provider or endpoint for custom model names.`);
|
|
9
46
|
}
|
|
@@ -11,26 +48,84 @@ export function createProvider(options) {
|
|
|
11
48
|
if (!endpoint) {
|
|
12
49
|
throw new Error(`Unknown endpoint profile: ${endpointId}`);
|
|
13
50
|
}
|
|
14
|
-
const providerId =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
51
|
+
const providerId = (initialRegistration?.descriptor.providerId ?? options.provider ?? parsedProviderId ?? endpoint.providerId);
|
|
52
|
+
const registration = initialRegistration ?? modelRegistry.resolve(options.model, providerId);
|
|
53
|
+
if (!registration)
|
|
54
|
+
throw new Error(`Unable to resolve model ${options.model} for provider ${providerId}`);
|
|
18
55
|
if (parsedProviderId && options.provider && parsedProviderId !== options.provider) {
|
|
19
56
|
throw new Error(`Model ${options.model} uses provider prefix ${parsedProviderId}, not ${options.provider}`);
|
|
20
57
|
}
|
|
21
58
|
if (endpoint.providerId !== providerId) {
|
|
22
59
|
throw new Error(`Endpoint ${endpoint.id} does not belong to provider ${providerId}`);
|
|
23
60
|
}
|
|
24
|
-
const model =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
61
|
+
const model = normalizeModelId(providerId, options.model);
|
|
62
|
+
return {
|
|
63
|
+
providerId,
|
|
64
|
+
model,
|
|
65
|
+
endpointId,
|
|
66
|
+
endpoint,
|
|
67
|
+
registration,
|
|
68
|
+
credentialRequest: { providerId, modelId: model, endpointId, protocol: endpoint.protocol },
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function constructResolvedRuntime(draft, credential, options) {
|
|
72
|
+
if (credential.type === "bearer" && !supportsBearerCredential(draft.providerId, draft.endpoint.protocol)) {
|
|
73
|
+
throw new CredentialResolutionError("credential_auth_mode_unsupported", draft.providerId);
|
|
74
|
+
}
|
|
75
|
+
const make = PROVIDER_REGISTRY[providerRegistryKey(draft.providerId, draft.endpoint.protocol)];
|
|
76
|
+
if (!make)
|
|
77
|
+
throw new Error(`No Node provider factory for ${draft.model} on ${draft.endpoint.id}`);
|
|
78
|
+
const protocol = generationProtocol(draft.endpoint.protocol);
|
|
79
|
+
if (!protocol)
|
|
80
|
+
throw new Error(`No Node provider factory for ${draft.model} on ${draft.endpoint.id}`);
|
|
81
|
+
const adapter = make(credential.value, draft.model, options.retry, options.baseURL ?? draft.endpoint.baseURL, draft.registration.recommendedRuntimePolicy, credential.type);
|
|
82
|
+
const resolved = {
|
|
83
|
+
identity: { providerId: draft.providerId, modelId: draft.model, endpointId: draft.endpointId, protocol },
|
|
84
|
+
model: draft.registration.descriptor,
|
|
85
|
+
endpoint: draft.endpoint,
|
|
86
|
+
adapter,
|
|
87
|
+
effectiveCapabilities: resolveEffectiveModelCapabilities({
|
|
88
|
+
model: draft.registration.descriptor,
|
|
89
|
+
protocol,
|
|
90
|
+
endpointCapabilities: endpointCapabilitiesFor(draft.endpointId, options.baseURL === undefined || options.endpoint !== undefined, options.baseURL === undefined),
|
|
91
|
+
}),
|
|
92
|
+
...(draft.registration.recommendedRuntimePolicy ? { runtimePolicy: draft.registration.recommendedRuntimePolicy } : {}),
|
|
93
|
+
};
|
|
94
|
+
const bind = adapter.bindResolvedRuntime;
|
|
95
|
+
bind?.call(adapter, resolved);
|
|
96
|
+
const requestPlanIdentity = {
|
|
97
|
+
providerId: resolved.identity.providerId,
|
|
98
|
+
modelId: resolved.identity.modelId,
|
|
99
|
+
endpoint: {
|
|
100
|
+
id: resolved.identity.endpointId,
|
|
101
|
+
protocol: resolved.identity.protocol,
|
|
102
|
+
baseURL: safeEndpointBaseURL(options.baseURL ?? draft.endpoint.baseURL),
|
|
103
|
+
},
|
|
104
|
+
...(resolved.effectiveCapabilities.nativeTokenCounting.state === "supported"
|
|
105
|
+
&& resolved.effectiveCapabilities.nativeTokenCounting.value === true
|
|
106
|
+
? { nativeTokenCounting: true }
|
|
107
|
+
: {}),
|
|
108
|
+
};
|
|
109
|
+
adapter
|
|
110
|
+
.requestPlanIdentity = () => ({
|
|
111
|
+
...requestPlanIdentity,
|
|
112
|
+
endpoint: { ...requestPlanIdentity.endpoint },
|
|
113
|
+
});
|
|
114
|
+
return resolved;
|
|
31
115
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
116
|
+
function safeEndpointBaseURL(baseURL) {
|
|
117
|
+
try {
|
|
118
|
+
const parsed = new URL(baseURL);
|
|
119
|
+
parsed.username = "";
|
|
120
|
+
parsed.password = "";
|
|
121
|
+
parsed.search = "";
|
|
122
|
+
parsed.hash = "";
|
|
123
|
+
return parsed.toString().replace(/\/$/, "");
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Provider construction has already accepted this opaque endpoint. Do not invent a replacement.
|
|
127
|
+
return baseURL;
|
|
128
|
+
}
|
|
34
129
|
}
|
|
35
130
|
function providerPrefix(model) {
|
|
36
131
|
const [prefix] = model.split("/", 1);
|
|
@@ -39,22 +134,3 @@ function providerPrefix(model) {
|
|
|
39
134
|
function providerIds() {
|
|
40
135
|
return Array.from(new Set(Object.values(endpointProfiles).map(endpoint => endpoint.providerId)));
|
|
41
136
|
}
|
|
42
|
-
function defaultEndpointForProvider(providerId) {
|
|
43
|
-
if (!providerId)
|
|
44
|
-
return undefined;
|
|
45
|
-
const defaults = {
|
|
46
|
-
anthropic: "anthropic.messages",
|
|
47
|
-
openai: "openai.chat",
|
|
48
|
-
minimax: "minimax.anthropic",
|
|
49
|
-
deepseek: "deepseek.anthropic",
|
|
50
|
-
kimi: "kimi.anthropic",
|
|
51
|
-
qwen: "qwen.anthropic",
|
|
52
|
-
gemini: "gemini.google",
|
|
53
|
-
glm: "glm.anthropic",
|
|
54
|
-
};
|
|
55
|
-
return defaults[providerId];
|
|
56
|
-
}
|
|
57
|
-
function modelNameForProvider(model, providerId) {
|
|
58
|
-
const prefix = `${providerId}/`;
|
|
59
|
-
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
|
|
60
|
-
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Message, RenderedContext, ToolOutputBlock, ToolResultPart, ToolSchema, ToolCall, ProviderReplay } from "../types.js";
|
|
2
|
+
import type { ResolvedProviderRuntime } from "./model-registry.js";
|
|
3
|
+
export declare class ContentValidationError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class ToolResultProjectionConflictError extends ContentValidationError {
|
|
7
|
+
constructor(callId: string);
|
|
8
|
+
}
|
|
9
|
+
export interface CanonicalToolResult {
|
|
10
|
+
readonly type: "tool_result";
|
|
11
|
+
readonly callId: string;
|
|
12
|
+
readonly blocks: readonly ToolOutputBlock[];
|
|
13
|
+
readonly isError: boolean;
|
|
14
|
+
/** Preserves the caller's explicit text-vs-block wire intent without duplicating content. */
|
|
15
|
+
readonly contentForm?: "text" | "blocks";
|
|
16
|
+
}
|
|
17
|
+
export type CanonicalMessageBlock = ToolOutputBlock | CanonicalToolResult;
|
|
18
|
+
export interface CanonicalMessage {
|
|
19
|
+
readonly role: Message["role"];
|
|
20
|
+
readonly blocks: readonly CanonicalMessageBlock[];
|
|
21
|
+
/** `blocks` remains authoritative; this only preserves an observable wire-shape distinction. */
|
|
22
|
+
readonly contentForm?: "text" | "blocks";
|
|
23
|
+
readonly toolCalls?: readonly ToolCall[];
|
|
24
|
+
readonly tokenCount?: number;
|
|
25
|
+
readonly providerReplay?: ProviderReplay;
|
|
26
|
+
}
|
|
27
|
+
export interface CanonicalRenderedContext {
|
|
28
|
+
readonly systemText: string;
|
|
29
|
+
readonly systemStable?: string;
|
|
30
|
+
readonly systemKnowledge?: string;
|
|
31
|
+
readonly turns: readonly CanonicalMessage[];
|
|
32
|
+
readonly stateTurn?: CanonicalMessage;
|
|
33
|
+
readonly frozenPrefixLen?: number;
|
|
34
|
+
readonly budgetOverflow?: RenderedContext["budgetOverflow"];
|
|
35
|
+
}
|
|
36
|
+
export interface CanonicalAdapterInput {
|
|
37
|
+
readonly context: CanonicalRenderedContext;
|
|
38
|
+
readonly tools: readonly ToolSchema[];
|
|
39
|
+
readonly resolved: ResolvedProviderRuntime<unknown>;
|
|
40
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
41
|
+
}
|
|
42
|
+
export declare function validateToolOutputBlocks(blocks: readonly ToolOutputBlock[]): void;
|
|
43
|
+
export declare function projectToolOutputToText(blocks: readonly ToolOutputBlock[]): string;
|
|
44
|
+
export declare function normalizeToolResultPart(part: ToolResultPart): CanonicalToolResult;
|
|
45
|
+
/** Attach process-local blocks only within the operation that produced them. */
|
|
46
|
+
export declare function attachToolOutputOverlay(context: RenderedContext, overlay: ReadonlyMap<string, readonly ToolOutputBlock[]>): RenderedContext;
|
|
47
|
+
export declare function normalizeCanonicalContext(context: RenderedContext, replayForMessage?: (message: Message) => ProviderReplay | undefined): CanonicalRenderedContext;
|
|
48
|
+
/** Full-tree validation uses the resolved operation capabilities. Unknown stays unknown/fail-open. */
|
|
49
|
+
export declare function validateCanonicalAdapterInput(input: CanonicalAdapterInput): void;
|
|
50
|
+
export declare function normalizeCanonicalAdapterInput(input: {
|
|
51
|
+
context: RenderedContext;
|
|
52
|
+
tools: readonly ToolSchema[];
|
|
53
|
+
resolved: ResolvedProviderRuntime<unknown>;
|
|
54
|
+
extensions?: Readonly<Record<string, unknown>>;
|
|
55
|
+
replayForMessage?: (message: Message) => ProviderReplay | undefined;
|
|
56
|
+
}): CanonicalAdapterInput;
|
|
57
|
+
export declare function normalizeToolResultContent(callId: string, output: string, isError: boolean, contentParts: readonly ToolOutputBlock[] | undefined): CanonicalToolResult;
|