@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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { getKernel } from "../kernel.js";
|
|
3
2
|
import { JournalCasConflictError, MAX_CHAIN_POSITION as JOURNAL_MAX_CHAIN_POSITION, } from "./kernel-journal.js";
|
|
4
3
|
import { encodeCanonicalContentParts, kernelMessageToSdk, renderedContextToSdk, } from "./kernel-step.js";
|
|
5
4
|
export const MAX_CHAIN_POSITION = JOURNAL_MAX_CHAIN_POSITION;
|
|
@@ -12,6 +11,21 @@ function totalUsageTokens(terminal) {
|
|
|
12
11
|
const output = Number(usage.output_tokens ?? 0);
|
|
13
12
|
return Number.isSafeInteger(input + output) ? input + output : 0;
|
|
14
13
|
}
|
|
14
|
+
function canonicalProviderFailureKind(kind) {
|
|
15
|
+
switch (kind) {
|
|
16
|
+
case "transport":
|
|
17
|
+
case "rate_limit":
|
|
18
|
+
case "model_unavailable":
|
|
19
|
+
return "transport_exhausted";
|
|
20
|
+
case "auth":
|
|
21
|
+
case "invalid_request":
|
|
22
|
+
case "modality":
|
|
23
|
+
case "protocol":
|
|
24
|
+
return "protocol_error";
|
|
25
|
+
default:
|
|
26
|
+
return "unknown";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
15
29
|
export function canonicalUnsupportedEffectResolution(effectId, effectKind) {
|
|
16
30
|
return {
|
|
17
31
|
kind: "resolve_effect",
|
|
@@ -343,7 +357,6 @@ export class CanonicalKernelHost {
|
|
|
343
357
|
}
|
|
344
358
|
async transition(input, options = {}) {
|
|
345
359
|
const inputJson = JSON.stringify({
|
|
346
|
-
abi_version: getKernel().kernelAbiVersion(),
|
|
347
360
|
operation_id: this.operationId,
|
|
348
361
|
input_id: options.inputId ?? `node-input-${randomUUID()}`,
|
|
349
362
|
observed_at_ms: options.observedAtMs ?? String(Date.now()),
|
|
@@ -591,7 +604,7 @@ function logicalRunSpec(raw, goal) {
|
|
|
591
604
|
...(raw.metadata && typeof raw.metadata === "object" ? { metadata: raw.metadata } : {}),
|
|
592
605
|
};
|
|
593
606
|
}
|
|
594
|
-
function canonicalWorkflowSpec(raw) {
|
|
607
|
+
function canonicalWorkflowSpec(raw, allowHostSchedulingFactors = false) {
|
|
595
608
|
const nodes = Array.isArray(raw.nodes) ? raw.nodes.map(asObject) : [];
|
|
596
609
|
const nodeIds = nodes.map((_node, index) => `wf-node${index}`);
|
|
597
610
|
return {
|
|
@@ -614,6 +627,9 @@ function canonicalWorkflowSpec(raw) {
|
|
|
614
627
|
unsupported.push("max_turns");
|
|
615
628
|
if (node.max_wall_ms !== undefined || node.maxWallMs !== undefined)
|
|
616
629
|
unsupported.push("max_wall_ms");
|
|
630
|
+
const schedulingFactors = node.scheduling_factors ?? node.schedulingFactors;
|
|
631
|
+
if (schedulingFactors !== undefined && !allowHostSchedulingFactors)
|
|
632
|
+
unsupported.push("scheduling_factors");
|
|
617
633
|
const inheritance = node.context_inheritance ?? node.contextInheritance;
|
|
618
634
|
if (unsupported.length > 0) {
|
|
619
635
|
throw new CanonicalKernelRejectedError(JSON.stringify({
|
|
@@ -634,16 +650,20 @@ function canonicalWorkflowSpec(raw) {
|
|
|
634
650
|
: [];
|
|
635
651
|
const modelHint = node.model_hint ?? node.modelHint;
|
|
636
652
|
const outputSchema = node.output_schema ?? node.outputSchema;
|
|
653
|
+
const canonicalSchedulingFactors = schedulingFactors === undefined
|
|
654
|
+
? undefined
|
|
655
|
+
: canonicalSchedulingFactorsForHost(schedulingFactors);
|
|
637
656
|
const runSpec = logicalRunSpec({
|
|
638
657
|
goal,
|
|
639
658
|
...(node.role ? { role: node.role } : {}),
|
|
640
659
|
...(node.isolation ? { isolation: node.isolation } : {}),
|
|
641
660
|
...(inheritance ? { context_inheritance: inheritance } : {}),
|
|
642
|
-
...((modelHint !== undefined || outputSchema !== undefined)
|
|
661
|
+
...((modelHint !== undefined || outputSchema !== undefined || canonicalSchedulingFactors !== undefined)
|
|
643
662
|
? {
|
|
644
663
|
metadata: {
|
|
645
664
|
...(modelHint !== undefined ? { model_hint: modelHint } : {}),
|
|
646
665
|
...(outputSchema !== undefined ? { output_schema: outputSchema } : {}),
|
|
666
|
+
...(canonicalSchedulingFactors !== undefined ? { scheduling_factors: canonicalSchedulingFactors } : {}),
|
|
647
667
|
},
|
|
648
668
|
}
|
|
649
669
|
: {}),
|
|
@@ -661,6 +681,24 @@ function canonicalWorkflowSpec(raw) {
|
|
|
661
681
|
}),
|
|
662
682
|
};
|
|
663
683
|
}
|
|
684
|
+
function canonicalSchedulingFactorsForHost(value) {
|
|
685
|
+
const raw = asObject(value);
|
|
686
|
+
const allowed = new Set(["deadline_urgency", "process_priority", "resource_pressure", "budget_pressure"]);
|
|
687
|
+
const unknown = Object.keys(raw).filter(key => !allowed.has(key));
|
|
688
|
+
if (unknown.length > 0)
|
|
689
|
+
throw new TypeError(`unknown scheduling factor(s): ${unknown.join(", ")}`);
|
|
690
|
+
const factors = {};
|
|
691
|
+
for (const key of allowed) {
|
|
692
|
+
const factor = raw[key];
|
|
693
|
+
if (factor === undefined)
|
|
694
|
+
continue;
|
|
695
|
+
if (!Number.isSafeInteger(factor) || factor < 0) {
|
|
696
|
+
throw new RangeError(`scheduling_factors.${key} must be a non-negative safe integer`);
|
|
697
|
+
}
|
|
698
|
+
factors[key] = factor;
|
|
699
|
+
}
|
|
700
|
+
return factors;
|
|
701
|
+
}
|
|
664
702
|
function sha256(value) {
|
|
665
703
|
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
666
704
|
}
|
|
@@ -675,8 +713,7 @@ function providerStopReason(value) {
|
|
|
675
713
|
}
|
|
676
714
|
/**
|
|
677
715
|
* Canonical operation runtime used by the Node host.
|
|
678
|
-
* Every durable transition below is one of the canonical
|
|
679
|
-
* envelope or synthesized host transaction reaches core or storage.
|
|
716
|
+
* Every durable transition below is one of the canonical contract's five input classes.
|
|
680
717
|
*/
|
|
681
718
|
export class CanonicalRunnerRuntime {
|
|
682
719
|
options;
|
|
@@ -802,7 +839,7 @@ export class CanonicalRunnerRuntime {
|
|
|
802
839
|
kind: "start_operation",
|
|
803
840
|
entry: {
|
|
804
841
|
kind: "workflow",
|
|
805
|
-
spec: canonicalWorkflowSpec(specValue),
|
|
842
|
+
spec: canonicalWorkflowSpec(specValue, true),
|
|
806
843
|
},
|
|
807
844
|
initial_context: this.initialContext,
|
|
808
845
|
});
|
|
@@ -856,7 +893,8 @@ export class CanonicalRunnerRuntime {
|
|
|
856
893
|
}
|
|
857
894
|
case "provider_error": {
|
|
858
895
|
const message = String(event.message ?? "");
|
|
859
|
-
const
|
|
896
|
+
const hasStructuredKind = typeof event.error_kind === "string";
|
|
897
|
+
const contextOverflow = event.error_kind === "context_overflow";
|
|
860
898
|
input = contextOverflow
|
|
861
899
|
? {
|
|
862
900
|
kind: "resolve_effect",
|
|
@@ -866,7 +904,7 @@ export class CanonicalRunnerRuntime {
|
|
|
866
904
|
result: { kind: "provider", outcome: { kind: "context_overflow" } },
|
|
867
905
|
},
|
|
868
906
|
}
|
|
869
|
-
: this.failedEffect(event, "transport_exhausted", message, true);
|
|
907
|
+
: this.failedEffect(event, hasStructuredKind ? canonicalProviderFailureKind(event.error_kind) : "transport_exhausted", message, typeof event.retryable === "boolean" ? event.retryable : true);
|
|
870
908
|
break;
|
|
871
909
|
}
|
|
872
910
|
case "tool_results": {
|
|
@@ -1425,9 +1463,6 @@ export class CanonicalRunnerRuntime {
|
|
|
1425
1463
|
delete asObject(execution.entropy_watch).threshold;
|
|
1426
1464
|
delete asObject(execution.entropy_watch).hysteresis;
|
|
1427
1465
|
}
|
|
1428
|
-
if (config.tool_dispatch_gate !== undefined) {
|
|
1429
|
-
this.featurePolicy().tool_dispatch_gate = config.tool_dispatch_gate;
|
|
1430
|
-
}
|
|
1431
1466
|
if (config.knowledge_budget_ratio !== undefined) {
|
|
1432
1467
|
const context = asObject(this.config.context_policy);
|
|
1433
1468
|
context.knowledge_budget_ppm = Math.round(Number(config.knowledge_budget_ratio) * 1_000_000);
|
|
@@ -1,35 +1,33 @@
|
|
|
1
|
-
export declare const CONTEXT_POLICY_VERSION: 1;
|
|
2
1
|
export declare const PPM_SCALE: 1000000;
|
|
3
|
-
export interface
|
|
2
|
+
export interface ContextPressureThresholds {
|
|
4
3
|
snip: number;
|
|
5
4
|
micro: number;
|
|
6
5
|
collapse: number;
|
|
7
6
|
auto: number;
|
|
8
7
|
renewal: number;
|
|
9
8
|
}
|
|
10
|
-
export interface
|
|
11
|
-
pressureThresholds:
|
|
9
|
+
export interface ContextPolicy {
|
|
10
|
+
pressureThresholds: ContextPressureThresholds;
|
|
12
11
|
targetAfterCompress: number;
|
|
13
12
|
preserveRecentTurns: number;
|
|
14
13
|
renewalCarryover: number;
|
|
15
14
|
collapseOldAssistantNarration: boolean;
|
|
16
15
|
idleMicroCompactMinutes: number;
|
|
17
16
|
}
|
|
18
|
-
export interface
|
|
19
|
-
|
|
20
|
-
pressure_thresholds_ppm: ContextPressureThresholdsV1;
|
|
17
|
+
export interface ContextPolicyWire {
|
|
18
|
+
pressure_thresholds_ppm: ContextPressureThresholds;
|
|
21
19
|
target_after_compress_ppm: number;
|
|
22
20
|
preserve_recent_turns: number;
|
|
23
21
|
renewal_carryover_ppm: number;
|
|
24
22
|
collapse_old_assistant_narration: boolean;
|
|
25
23
|
idle_micro_compact_minutes: number;
|
|
26
24
|
}
|
|
27
|
-
export interface
|
|
28
|
-
pressureThresholds?: Partial<
|
|
25
|
+
export interface ContextPolicyOverrides extends Partial<Omit<ContextPolicy, "pressureThresholds">> {
|
|
26
|
+
pressureThresholds?: Partial<ContextPressureThresholds>;
|
|
29
27
|
}
|
|
30
|
-
export declare const
|
|
28
|
+
export declare const DEFAULT_CONTEXT_POLICY: Readonly<ContextPolicy>;
|
|
31
29
|
/** Resolve ergonomic partial SDK options into one complete, atomically validated policy. */
|
|
32
|
-
export declare function
|
|
30
|
+
export declare function contextPolicy(overrides?: ContextPolicyOverrides): ContextPolicy;
|
|
33
31
|
/** Convert the public ratio-based policy to the canonical integer-only ABI wire shape. */
|
|
34
|
-
export declare function
|
|
32
|
+
export declare function normalizeContextPolicy(policy: ContextPolicy): ContextPolicyWire;
|
|
35
33
|
export declare function ratioToPpm(value: number, field?: string): number;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export const CONTEXT_POLICY_VERSION = 1;
|
|
2
1
|
export const PPM_SCALE = 1_000_000;
|
|
3
|
-
export const
|
|
2
|
+
export const DEFAULT_CONTEXT_POLICY = Object.freeze({
|
|
4
3
|
pressureThresholds: Object.freeze({ snip: 0.70, micro: 0.80, collapse: 0.90, auto: 0.95, renewal: 0.98 }),
|
|
5
4
|
targetAfterCompress: 0.65,
|
|
6
5
|
preserveRecentTurns: 2,
|
|
@@ -9,20 +8,20 @@ export const DEFAULT_CONTEXT_POLICY_V1 = Object.freeze({
|
|
|
9
8
|
idleMicroCompactMinutes: 60,
|
|
10
9
|
});
|
|
11
10
|
/** Resolve ergonomic partial SDK options into one complete, atomically validated policy. */
|
|
12
|
-
export function
|
|
11
|
+
export function contextPolicy(overrides = {}) {
|
|
13
12
|
const policy = {
|
|
14
|
-
...
|
|
13
|
+
...DEFAULT_CONTEXT_POLICY,
|
|
15
14
|
...overrides,
|
|
16
15
|
pressureThresholds: {
|
|
17
|
-
...
|
|
16
|
+
...DEFAULT_CONTEXT_POLICY.pressureThresholds,
|
|
18
17
|
...overrides.pressureThresholds,
|
|
19
18
|
},
|
|
20
19
|
};
|
|
21
|
-
|
|
20
|
+
normalizeContextPolicy(policy);
|
|
22
21
|
return policy;
|
|
23
22
|
}
|
|
24
23
|
/** Convert the public ratio-based policy to the canonical integer-only ABI wire shape. */
|
|
25
|
-
export function
|
|
24
|
+
export function normalizeContextPolicy(policy) {
|
|
26
25
|
const pressure_thresholds_ppm = {
|
|
27
26
|
snip: ratioToPpm(policy.pressureThresholds.snip, "pressureThresholds.snip"),
|
|
28
27
|
micro: ratioToPpm(policy.pressureThresholds.micro, "pressureThresholds.micro"),
|
|
@@ -44,7 +43,6 @@ export function normalizeContextPolicyV1(policy) {
|
|
|
44
43
|
throw new TypeError("collapseOldAssistantNarration must be boolean");
|
|
45
44
|
}
|
|
46
45
|
return {
|
|
47
|
-
version: CONTEXT_POLICY_VERSION,
|
|
48
46
|
pressure_thresholds_ppm,
|
|
49
47
|
target_after_compress_ppm,
|
|
50
48
|
preserve_recent_turns: policy.preserveRecentTurns,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Provider-neutral durable content ABI.
|
|
2
|
+
*
|
|
3
|
+
* This is deliberately separate from provider-facing ContentPart. Durable records carry only
|
|
4
|
+
* portable content and explicit payload locators; protocol adapters decide how to serialize it.
|
|
5
|
+
*/
|
|
6
|
+
export declare class DurableContentError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export type DurableSource = {
|
|
10
|
+
kind: "url";
|
|
11
|
+
url: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "base64";
|
|
14
|
+
data: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "file_id";
|
|
17
|
+
id: string;
|
|
18
|
+
affinity: {
|
|
19
|
+
provider_id: string;
|
|
20
|
+
endpoint_id: string;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
kind: "object";
|
|
24
|
+
handle: string;
|
|
25
|
+
owner: string;
|
|
26
|
+
payload_ref: string;
|
|
27
|
+
};
|
|
28
|
+
export type DurableContentBlock = {
|
|
29
|
+
type: "text";
|
|
30
|
+
text: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "image" | "audio" | "video" | "file";
|
|
33
|
+
source: DurableSource;
|
|
34
|
+
media_type?: string;
|
|
35
|
+
provider_options?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
export interface DurableContent {
|
|
38
|
+
blocks: DurableContentBlock[];
|
|
39
|
+
}
|
|
40
|
+
export interface DurableToolResult extends DurableContent {
|
|
41
|
+
call_id: string;
|
|
42
|
+
is_error: boolean;
|
|
43
|
+
}
|
|
44
|
+
import type { ToolOutputBlock } from "../types.js";
|
|
45
|
+
export declare function decodeDurableContent(value: unknown): DurableContent;
|
|
46
|
+
export declare function decodeDurableToolResult(value: unknown): DurableToolResult;
|
|
47
|
+
export declare function encodeDurableContent(content: DurableContent): Record<string, unknown>;
|
|
48
|
+
export declare function encodeDurableToolResult(result: DurableToolResult): Record<string, unknown>;
|
|
49
|
+
export declare function toolOutputBlocksToDurable(blocks: readonly ToolOutputBlock[]): DurableContentBlock[];
|
|
50
|
+
export declare function durableBlocksToToolOutput(blocks: readonly DurableContentBlock[]): ToolOutputBlock[];
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/** Provider-neutral durable content ABI.
|
|
2
|
+
*
|
|
3
|
+
* This is deliberately separate from provider-facing ContentPart. Durable records carry only
|
|
4
|
+
* portable content and explicit payload locators; protocol adapters decide how to serialize it.
|
|
5
|
+
*/
|
|
6
|
+
export class DurableContentError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "DurableContentError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const CONTENT_KEYS = new Set(["blocks"]);
|
|
13
|
+
const TOOL_RESULT_KEYS = new Set(["call_id", "is_error", "blocks"]);
|
|
14
|
+
const SOURCE_KEYS = {
|
|
15
|
+
url: new Set(["kind", "url"]),
|
|
16
|
+
base64: new Set(["kind", "data"]),
|
|
17
|
+
file_id: new Set(["kind", "id", "affinity"]),
|
|
18
|
+
object: new Set(["kind", "handle", "owner", "payload_ref"]),
|
|
19
|
+
};
|
|
20
|
+
function object(value, label) {
|
|
21
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
22
|
+
throw new DurableContentError(`${label} must be an object`);
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
function exactKeys(value, allowed, label) {
|
|
26
|
+
for (const key of Object.keys(value))
|
|
27
|
+
if (!allowed.has(key))
|
|
28
|
+
throw new DurableContentError(`${label} has unknown field ${key}`);
|
|
29
|
+
}
|
|
30
|
+
function requiredString(value, label) {
|
|
31
|
+
if (typeof value !== "string" || value.length === 0)
|
|
32
|
+
throw new DurableContentError(`${label} must be a non-empty string`);
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function requiredBoolean(value, label) {
|
|
36
|
+
if (typeof value !== "boolean")
|
|
37
|
+
throw new DurableContentError(`${label} must be a boolean`);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function base64(value, label) {
|
|
41
|
+
const data = requiredString(value, label);
|
|
42
|
+
if (data.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)) {
|
|
43
|
+
throw new DurableContentError(`${label} is not valid base64`);
|
|
44
|
+
}
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
function source(value, label) {
|
|
48
|
+
const raw = object(value, `${label} source`);
|
|
49
|
+
const kind = raw.kind;
|
|
50
|
+
if (kind !== "url" && kind !== "base64" && kind !== "file_id" && kind !== "object")
|
|
51
|
+
throw new DurableContentError(`${label} source kind is invalid`);
|
|
52
|
+
exactKeys(raw, SOURCE_KEYS[kind], `${label} source`);
|
|
53
|
+
if (kind === "url")
|
|
54
|
+
return { kind, url: requiredString(raw.url, `${label} URL`) };
|
|
55
|
+
if (kind === "base64")
|
|
56
|
+
return { kind, data: base64(raw.data, `${label} base64 data`) };
|
|
57
|
+
if (kind === "file_id") {
|
|
58
|
+
const id = requiredString(raw.id, `${label} file id`);
|
|
59
|
+
const a = object(raw.affinity, `${label} affinity`);
|
|
60
|
+
exactKeys(a, new Set(["provider_id", "endpoint_id"]), `${label} affinity`);
|
|
61
|
+
return {
|
|
62
|
+
kind,
|
|
63
|
+
id,
|
|
64
|
+
affinity: {
|
|
65
|
+
provider_id: requiredString(a.provider_id, `${label} affinity provider_id`),
|
|
66
|
+
endpoint_id: requiredString(a.endpoint_id, `${label} affinity endpoint_id`),
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
kind,
|
|
72
|
+
handle: requiredString(raw.handle, `${label} object handle`),
|
|
73
|
+
owner: requiredString(raw.owner, `${label} object owner`),
|
|
74
|
+
payload_ref: requiredString(raw.payload_ref, `${label} payload_ref`),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function block(value, index) {
|
|
78
|
+
const raw = object(value, `content block ${index}`);
|
|
79
|
+
const type = raw.type;
|
|
80
|
+
if (type === "text") {
|
|
81
|
+
exactKeys(raw, new Set(["type", "text"]), `content block ${index}`);
|
|
82
|
+
return { type, text: typeof raw.text === "string" ? raw.text : (() => { throw new DurableContentError(`content block ${index} text must be a string`); })() };
|
|
83
|
+
}
|
|
84
|
+
if (type === "tool_result")
|
|
85
|
+
throw new DurableContentError("nested tool_result blocks are forbidden");
|
|
86
|
+
if (type !== "image" && type !== "audio" && type !== "video" && type !== "file")
|
|
87
|
+
throw new DurableContentError(`unknown content block type: ${String(type)}`);
|
|
88
|
+
exactKeys(raw, new Set(["type", "source", "media_type", "provider_options"]), `content block ${index}`);
|
|
89
|
+
const mediaType = raw.media_type === undefined ? undefined : requiredString(raw.media_type, `content block ${index} media_type`);
|
|
90
|
+
let providerOptions;
|
|
91
|
+
if (raw.provider_options !== undefined)
|
|
92
|
+
providerOptions = object(raw.provider_options, `content block ${index} provider_options`);
|
|
93
|
+
return {
|
|
94
|
+
type,
|
|
95
|
+
source: source(raw.source, `content block ${index}`),
|
|
96
|
+
...(mediaType === undefined ? {} : { media_type: mediaType }),
|
|
97
|
+
...(providerOptions === undefined ? {} : { provider_options: providerOptions }),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function blocks(value) {
|
|
101
|
+
if (!Array.isArray(value))
|
|
102
|
+
throw new DurableContentError("content blocks must be an array");
|
|
103
|
+
return value.map(block);
|
|
104
|
+
}
|
|
105
|
+
export function decodeDurableContent(value) {
|
|
106
|
+
const raw = object(value, "durable content");
|
|
107
|
+
exactKeys(raw, CONTENT_KEYS, "durable content");
|
|
108
|
+
return { blocks: blocks(raw.blocks) };
|
|
109
|
+
}
|
|
110
|
+
export function decodeDurableToolResult(value) {
|
|
111
|
+
const raw = object(value, "durable tool result");
|
|
112
|
+
exactKeys(raw, TOOL_RESULT_KEYS, "durable tool result");
|
|
113
|
+
return { call_id: requiredString(raw.call_id, "tool result call_id"), is_error: requiredBoolean(raw.is_error, "tool result is_error"), blocks: blocks(raw.blocks) };
|
|
114
|
+
}
|
|
115
|
+
export function encodeDurableContent(content) {
|
|
116
|
+
const decoded = decodeDurableContent(content);
|
|
117
|
+
return { blocks: decoded.blocks };
|
|
118
|
+
}
|
|
119
|
+
export function encodeDurableToolResult(result) {
|
|
120
|
+
const decoded = decodeDurableToolResult(result);
|
|
121
|
+
return { call_id: decoded.call_id, is_error: decoded.is_error, blocks: decoded.blocks };
|
|
122
|
+
}
|
|
123
|
+
export function toolOutputBlocksToDurable(blocks) {
|
|
124
|
+
return blocks.map((part, index) => {
|
|
125
|
+
if (part.type === "text")
|
|
126
|
+
return { type: "text", text: part.text };
|
|
127
|
+
const source = part.source;
|
|
128
|
+
const durableSource = source.kind === "fileId"
|
|
129
|
+
? {
|
|
130
|
+
kind: "file_id",
|
|
131
|
+
id: source.id,
|
|
132
|
+
affinity: source.affinity
|
|
133
|
+
? { provider_id: source.affinity.providerId, endpoint_id: source.affinity.endpointId }
|
|
134
|
+
: (() => { throw new DurableContentError(`tool output block ${index} fileId source requires endpoint affinity`); })(),
|
|
135
|
+
}
|
|
136
|
+
: source.kind === "base64" ? { kind: "base64", data: source.data }
|
|
137
|
+
: source.kind === "url" ? { kind: "url", url: source.url }
|
|
138
|
+
: {
|
|
139
|
+
kind: "object",
|
|
140
|
+
handle: source.handle,
|
|
141
|
+
owner: source.owner ?? (() => { throw new DurableContentError(`tool output block ${index} object source requires owner`); })(),
|
|
142
|
+
payload_ref: source.payloadRef ?? (() => { throw new DurableContentError(`tool output block ${index} object source requires payloadRef`); })(),
|
|
143
|
+
};
|
|
144
|
+
return { type: part.type, source: durableSource, ...(part.mediaType ? { media_type: part.mediaType } : {}), ...(part.providerOptions ? { provider_options: part.providerOptions } : {}) };
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function durableBlocksToToolOutput(blocks) {
|
|
148
|
+
return blocks.map((part) => {
|
|
149
|
+
if (part.type === "text")
|
|
150
|
+
return part;
|
|
151
|
+
const source = part.source;
|
|
152
|
+
const sdkSource = source.kind === "file_id"
|
|
153
|
+
? { kind: "fileId", id: source.id, affinity: { providerId: source.affinity.provider_id, endpointId: source.affinity.endpoint_id } }
|
|
154
|
+
: source.kind === "base64" ? source
|
|
155
|
+
: source.kind === "url" ? source
|
|
156
|
+
: { kind: "object", handle: source.handle, owner: source.owner, payloadRef: source.payload_ref };
|
|
157
|
+
return { type: part.type, source: sdkSource, ...(part.media_type ? { mediaType: part.media_type } : {}), ...(part.provider_options ? { providerOptions: part.provider_options } : {}) };
|
|
158
|
+
});
|
|
159
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ToolCall, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse } from "../types.js";
|
|
2
2
|
import type { RegisteredTool } from "../tools/index.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { MemoryStore, MemoryScope } from "../memory/protocols.js";
|
|
4
4
|
import type { KnowledgeSource } from "../knowledge/source.js";
|
|
5
5
|
import type { OperationContext } from "./reliability.js";
|
|
6
6
|
export interface RunContext {
|
|
@@ -9,7 +9,7 @@ export interface RunContext {
|
|
|
9
9
|
agentId?: string;
|
|
10
10
|
memoryScope?: MemoryScope;
|
|
11
11
|
skillDir?: string;
|
|
12
|
-
|
|
12
|
+
memoryStore?: MemoryStore;
|
|
13
13
|
knowledgeSource?: KnowledgeSource;
|
|
14
14
|
onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
|
|
15
15
|
onPermissionRequest?: (event: PermissionRequestEvent) => Promise<PermissionResponse | boolean> | PermissionResponse | boolean;
|
|
@@ -29,8 +29,8 @@ export class LocalExecutionPlane {
|
|
|
29
29
|
for (const c of memoryCalls) {
|
|
30
30
|
const args = tryParseJson(c.arguments);
|
|
31
31
|
const topK = typeof args?.top_k === "number" ? args.top_k : 5;
|
|
32
|
-
const entries = (ctx.
|
|
33
|
-
? await ctx.
|
|
32
|
+
const entries = (ctx.memoryStore && ctx.agentId && ctx.memoryScope)
|
|
33
|
+
? await ctx.memoryStore.search(ctx.agentId, {
|
|
34
34
|
scope: ctx.memoryScope,
|
|
35
35
|
query: String(args?.query ?? ""),
|
|
36
36
|
top_k: topK,
|
|
@@ -91,7 +91,6 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
91
91
|
kind: "entropy_sample",
|
|
92
92
|
turn: t,
|
|
93
93
|
score: obs.score ?? 0,
|
|
94
|
-
score_version: obs.score_version ?? 0,
|
|
95
94
|
rho: obs.rho ?? 0,
|
|
96
95
|
repeat_pressure: obs.repeat_pressure ?? 0,
|
|
97
96
|
failure_rate: obs.failure_rate ?? 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const CANONICAL_CONTENT_PARTS_PREFIX = "[[deepstrike-content-parts
|
|
1
|
+
const CANONICAL_CONTENT_PARTS_PREFIX = "[[deepstrike-content-parts]]";
|
|
2
2
|
export function encodeCanonicalContentParts(parts) {
|
|
3
3
|
return `${CANONICAL_CONTENT_PARTS_PREFIX}${Buffer.from(JSON.stringify(parts)).toString("base64url")}`;
|
|
4
4
|
}
|
|
@@ -43,6 +43,9 @@ export function skillMetadataToKernel(skill) {
|
|
|
43
43
|
// P1-B: forward declared tool ids (additive; omitted when empty so existing skills' wire is unchanged).
|
|
44
44
|
if (skill.allowedTools?.length)
|
|
45
45
|
out.allowed_tools = skill.allowedTools;
|
|
46
|
+
// SPC-015-01: structured grants are caller-supplied rather than inferred from scalar frontmatter.
|
|
47
|
+
if (skill.capabilityGrants?.length)
|
|
48
|
+
out.capability_grants = skill.capabilityGrants;
|
|
46
49
|
return out;
|
|
47
50
|
}
|
|
48
51
|
export function messageToKernelMessage(message) {
|
|
@@ -153,7 +156,6 @@ export function entropySampleFromObservation(obs) {
|
|
|
153
156
|
return {
|
|
154
157
|
turn: obs.turn ?? 0,
|
|
155
158
|
score: obs.score ?? 0,
|
|
156
|
-
scoreVersion: obs.score_version ?? 0,
|
|
157
159
|
rho: obs.rho ?? 0,
|
|
158
160
|
repeatPressure: obs.repeat_pressure ?? 0,
|
|
159
161
|
failureRate: obs.failure_rate ?? 0,
|
|
@@ -1,7 +1,31 @@
|
|
|
1
|
-
import type { ToolCall, ToolSchema, StreamEvent } from "../types.js";
|
|
1
|
+
import type { ToolCall, ToolSchema, StreamEvent, ToolOutputBlock } from "../types.js";
|
|
2
2
|
import type { RegisteredTool } from "../tools/index.js";
|
|
3
3
|
import type { ExecutionPlane, RunContext } from "./execution-plane.js";
|
|
4
4
|
import type { CredentialVault } from "./credential-vault.js";
|
|
5
|
+
/** Raw MCP `tools/call` response `content` block shapes we accept (text/image/audio). */
|
|
6
|
+
export interface McpContentBlock {
|
|
7
|
+
type: string;
|
|
8
|
+
text?: string;
|
|
9
|
+
data?: string;
|
|
10
|
+
mimeType?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* spc_012-N-02: pure conversion, unit-testable without spawning a subprocess. Prior behavior
|
|
14
|
+
* silently dropped every non-`"text"` block (INV-012-01 violation — an MCP tool returning a
|
|
15
|
+
* screenshot lost the image with no trace). `output` stays the text projection for backward
|
|
16
|
+
* available as the text projection — when non-text blocks exist the projection
|
|
17
|
+
* carries an explicit `[modality]` placeholder, so text-only providers (spc_012-N-04) degrade visibly instead
|
|
18
|
+
* of swallowing the block. `contentParts` is populated (and only populated) when the response
|
|
19
|
+
* actually contains a non-text block, so pure-text tool calls see zero behavior change.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mcpResultToToolOutput(result: {
|
|
22
|
+
content?: McpContentBlock[];
|
|
23
|
+
isError?: boolean;
|
|
24
|
+
}): {
|
|
25
|
+
output: string;
|
|
26
|
+
isError: boolean;
|
|
27
|
+
contentParts?: ToolOutputBlock[];
|
|
28
|
+
};
|
|
5
29
|
export interface McpServerConfig {
|
|
6
30
|
/** Executable to run (e.g. "npx", "python3", "/usr/local/bin/my-mcp-server"). */
|
|
7
31
|
command: string;
|
|
@@ -3,6 +3,41 @@ import { createInterface } from "node:readline";
|
|
|
3
3
|
import { LocalExecutionPlane } from "./execution-plane.js";
|
|
4
4
|
import { formatToolError } from "../tools/errors.js";
|
|
5
5
|
import { operationAbortSignal } from "./reliability.js";
|
|
6
|
+
/**
|
|
7
|
+
* spc_012-N-02: pure conversion, unit-testable without spawning a subprocess. Prior behavior
|
|
8
|
+
* silently dropped every non-`"text"` block (INV-012-01 violation — an MCP tool returning a
|
|
9
|
+
* screenshot lost the image with no trace). `output` stays the text projection for backward
|
|
10
|
+
* available as the text projection — when non-text blocks exist the projection
|
|
11
|
+
* carries an explicit `[modality]` placeholder, so text-only providers (spc_012-N-04) degrade visibly instead
|
|
12
|
+
* of swallowing the block. `contentParts` is populated (and only populated) when the response
|
|
13
|
+
* actually contains a non-text block, so pure-text tool calls see zero behavior change.
|
|
14
|
+
*/
|
|
15
|
+
export function mcpResultToToolOutput(result) {
|
|
16
|
+
const blocks = result.content ?? [];
|
|
17
|
+
const hasNonText = blocks.some(c => c.type !== "text");
|
|
18
|
+
if (!hasNonText) {
|
|
19
|
+
const text = blocks
|
|
20
|
+
.filter(c => c.type === "text")
|
|
21
|
+
.map(c => c.text ?? "")
|
|
22
|
+
.join("\n");
|
|
23
|
+
return { output: text || JSON.stringify(result), isError: result.isError ?? false };
|
|
24
|
+
}
|
|
25
|
+
const output = blocks
|
|
26
|
+
.map(c => (c.type === "text" ? c.text ?? "" : `[${c.type}]`))
|
|
27
|
+
.join("\n");
|
|
28
|
+
const contentParts = blocks.map(c => {
|
|
29
|
+
if (c.type === "text")
|
|
30
|
+
return { type: "text", text: c.text ?? "" };
|
|
31
|
+
if (c.type === "image") {
|
|
32
|
+
return { type: "image", source: { kind: "base64", data: c.data ?? "" }, mediaType: c.mimeType };
|
|
33
|
+
}
|
|
34
|
+
if (c.type === "audio") {
|
|
35
|
+
return { type: "audio", source: { kind: "base64", data: c.data ?? "" }, mediaType: c.mimeType ?? "audio/wav" };
|
|
36
|
+
}
|
|
37
|
+
return { type: "text", text: JSON.stringify(c) };
|
|
38
|
+
});
|
|
39
|
+
return { output, isError: result.isError ?? false, contentParts };
|
|
40
|
+
}
|
|
6
41
|
class McpConnection {
|
|
7
42
|
serverName;
|
|
8
43
|
config;
|
|
@@ -106,11 +141,7 @@ class McpConnection {
|
|
|
106
141
|
try {
|
|
107
142
|
const args = JSON.parse(call.arguments || "{}");
|
|
108
143
|
const result = await this.request("tools/call", { name: call.name, arguments: args }, signal);
|
|
109
|
-
|
|
110
|
-
.filter(c => c.type === "text")
|
|
111
|
-
.map(c => c.text ?? "")
|
|
112
|
-
.join("\n");
|
|
113
|
-
return { output: text || JSON.stringify(result), isError: result.isError ?? false };
|
|
144
|
+
return mcpResultToToolOutput(result);
|
|
114
145
|
}
|
|
115
146
|
catch (err) {
|
|
116
147
|
return { output: formatToolError(err), isError: true };
|
|
@@ -215,7 +246,14 @@ export class McpProxyPlane {
|
|
|
215
246
|
});
|
|
216
247
|
for (const settled of await Promise.all(tasks)) {
|
|
217
248
|
for (const { call, result } of settled) {
|
|
218
|
-
yield {
|
|
249
|
+
yield {
|
|
250
|
+
type: "tool_result",
|
|
251
|
+
callId: call.id,
|
|
252
|
+
name: call.name,
|
|
253
|
+
content: result.output,
|
|
254
|
+
isError: result.isError,
|
|
255
|
+
contentParts: result.contentParts,
|
|
256
|
+
};
|
|
219
257
|
}
|
|
220
258
|
}
|
|
221
259
|
}
|
|
@@ -2,7 +2,7 @@ export interface SchemaValidation {
|
|
|
2
2
|
ok: boolean;
|
|
3
3
|
errors: string[];
|
|
4
4
|
}
|
|
5
|
-
type JsonSchema = Record<string, unknown>;
|
|
5
|
+
export type JsonSchema = Record<string, unknown>;
|
|
6
6
|
/** Validate `value` against `schema` (the supported subset). `path` is for error messages. */
|
|
7
7
|
export declare function validateAgainstSchema(value: unknown, schema: JsonSchema, path?: string): SchemaValidation;
|
|
8
8
|
/** The instruction appended to a node's goal so its agent produces schema-conforming JSON. */
|
|
@@ -11,4 +11,3 @@ export declare function schemaInstruction(schema: JsonSchema): string;
|
|
|
11
11
|
export declare function schemaRetryInstruction(schema: JsonSchema, errors: string[]): string;
|
|
12
12
|
/** Best-effort extraction of a JSON value from agent output (raw, fenced, or embedded). */
|
|
13
13
|
export declare function extractJsonValue(text: string): unknown;
|
|
14
|
-
export {};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { LLMProvider, Message, ProviderDescriptor, ProviderReplay, RenderedContext, ReplayabilityAssessment, ToolCall } from "../types.js";
|
|
2
2
|
import type { SessionEvent } from "./session-log.js";
|
|
3
|
+
export declare class ProviderReplayProtocolMismatchError extends Error {
|
|
4
|
+
readonly code: "provider_replay_protocol_mismatch";
|
|
5
|
+
constructor(provider: string, storedProtocol: string, resolvedProtocol: string);
|
|
6
|
+
}
|
|
3
7
|
export declare function assistantReplayKey(message: Pick<Message, "content" | "toolCalls">): string;
|
|
4
8
|
/**
|
|
5
9
|
* A stored replay may only be seeded into a provider speaking the same wire
|
|
@@ -7,7 +11,7 @@ export declare function assistantReplayKey(message: Pick<Message, "content" | "t
|
|
|
7
11
|
* incompatible envelope is skipped so B re-serializes neutral context instead
|
|
8
12
|
* of replaying A's protocol-specific shape.
|
|
9
13
|
*/
|
|
10
|
-
export declare function isReplayCompatibleWithProvider(replay: ProviderReplay
|
|
14
|
+
export declare function isReplayCompatibleWithProvider(replay: Partial<ProviderReplay>, descriptor: ProviderDescriptor | undefined): boolean;
|
|
11
15
|
export declare function seedProviderReplayFromEvents(provider: LLMProvider, events: Array<{
|
|
12
16
|
event: SessionEvent;
|
|
13
17
|
}>): void;
|