@deepstrike/wasm 0.2.52 → 0.2.60
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 +15 -14
- package/dist/agent-ir.d.ts +81 -0
- package/dist/agent-ir.js +115 -0
- package/dist/agent.d.ts +140 -0
- package/dist/agent.js +34 -0
- package/dist/governance.d.ts +0 -25
- package/dist/governance.js +1 -53
- package/dist/index.d.ts +23 -8
- package/dist/index.js +11 -4
- package/dist/memory/durable.d.ts +13 -0
- package/dist/memory/durable.js +42 -0
- package/dist/memory/in-memory-store.d.ts +8 -6
- package/dist/memory/in-memory-store.js +8 -2
- package/dist/memory/index.d.ts +18 -2
- package/dist/providers/anthropic.d.ts +9 -0
- package/dist/providers/anthropic.js +12 -33
- package/dist/providers/content-policy.d.ts +16 -0
- package/dist/providers/content-policy.js +39 -0
- package/dist/providers/openai.d.ts +36 -17
- package/dist/providers/openai.js +86 -46
- package/dist/providers/provider-error.d.ts +22 -0
- package/dist/providers/provider-error.js +90 -0
- package/dist/providers/request-plan.d.ts +87 -0
- package/dist/providers/request-plan.js +153 -0
- package/dist/providers/stop-reason.d.ts +5 -0
- package/dist/providers/stop-reason.js +24 -0
- package/dist/runtime/canonical-kernel-step.d.ts +2 -5
- package/dist/runtime/canonical-kernel-step.js +40 -58
- package/dist/runtime/context-policy.d.ts +10 -12
- package/dist/runtime/context-policy.js +6 -8
- package/dist/runtime/durable-content.d.ts +44 -0
- package/dist/runtime/durable-content.js +119 -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 +1 -2
- package/dist/runtime/kernel-step.js +1 -1
- package/dist/runtime/provider-replay.d.ts +1 -1
- package/dist/runtime/provider-replay.js +12 -20
- package/dist/runtime/runner.d.ts +22 -18
- package/dist/runtime/runner.js +115 -55
- package/dist/runtime/session-log.d.ts +8 -1
- package/dist/runtime/session-repair.d.ts +1 -1
- package/dist/runtime/session-repair.js +1 -1
- package/dist/runtime/sha256.d.ts +2 -0
- package/dist/runtime/sha256.js +38 -0
- package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
- package/dist/runtime/sub-agent-orchestrator.js +3 -3
- package/dist/runtime/types/agent.d.ts +17 -7
- package/dist/runtime/types/agent.js +30 -4
- package/dist/runtime/workflow-control-flow.d.ts +0 -4
- package/dist/runtime/workflow-control-flow.js +0 -16
- package/dist/types.d.ts +58 -5
- package/package.json +2 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { RenderedContext, ToolSchema } from "../types.js";
|
|
2
|
+
export interface ProviderRequestEndpoint {
|
|
3
|
+
id: string;
|
|
4
|
+
protocol: string;
|
|
5
|
+
baseURL: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ProviderRequestPlan {
|
|
8
|
+
providerId: string;
|
|
9
|
+
modelId: string;
|
|
10
|
+
endpoint: ProviderRequestEndpoint;
|
|
11
|
+
context: RenderedContext;
|
|
12
|
+
tools: ToolSchema[];
|
|
13
|
+
options: Record<string, unknown>;
|
|
14
|
+
fingerprint: string;
|
|
15
|
+
}
|
|
16
|
+
/** Stable, provider-independent fallback used when no native token meter is available. */
|
|
17
|
+
export declare function estimateProviderPromptTokens(context: RenderedContext, tools: ToolSchema[]): number;
|
|
18
|
+
export interface RecordedPromptMeasurement {
|
|
19
|
+
requestFingerprint: string;
|
|
20
|
+
inputTokens: number;
|
|
21
|
+
source: {
|
|
22
|
+
kind: "native";
|
|
23
|
+
provider: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "local_exact";
|
|
26
|
+
tokenizer: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "heuristic";
|
|
29
|
+
};
|
|
30
|
+
confidence: "exact" | "high_confidence" | "low_confidence";
|
|
31
|
+
}
|
|
32
|
+
export interface ProviderUsage {
|
|
33
|
+
inputTokens: number;
|
|
34
|
+
outputTokens: number;
|
|
35
|
+
cacheReadInputTokens?: number;
|
|
36
|
+
cacheCreationInputTokens?: number;
|
|
37
|
+
reasoningTokens?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface NormalizedProviderUsage extends ProviderUsage {
|
|
40
|
+
uncachedInputTokens: number;
|
|
41
|
+
}
|
|
42
|
+
export interface PricingSnapshot {
|
|
43
|
+
version: string;
|
|
44
|
+
currency: string;
|
|
45
|
+
region: string;
|
|
46
|
+
effectiveFrom: string;
|
|
47
|
+
expiresAt?: string;
|
|
48
|
+
ratesPerMillion: {
|
|
49
|
+
input: number;
|
|
50
|
+
output: number;
|
|
51
|
+
cacheRead?: number;
|
|
52
|
+
cacheCreation?: number;
|
|
53
|
+
reasoning?: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export type CostObservation = {
|
|
57
|
+
source: "snapshot";
|
|
58
|
+
currency: string;
|
|
59
|
+
amount: number;
|
|
60
|
+
pricingVersion: string;
|
|
61
|
+
} | {
|
|
62
|
+
source: "unpriced";
|
|
63
|
+
reason: "pricing_snapshot_not_effective" | "pricing_snapshot_expired" | "invalid_pricing_snapshot";
|
|
64
|
+
};
|
|
65
|
+
export declare function createProviderRequestPlan(input: Omit<ProviderRequestPlan, "fingerprint" | "options"> & {
|
|
66
|
+
options?: Record<string, unknown>;
|
|
67
|
+
}): ProviderRequestPlan;
|
|
68
|
+
export declare function createProviderRequestPlanForProvider(provider: {
|
|
69
|
+
descriptor?(): {
|
|
70
|
+
provider: string;
|
|
71
|
+
protocol: string;
|
|
72
|
+
model: string;
|
|
73
|
+
};
|
|
74
|
+
requestPlanIdentity?(): {
|
|
75
|
+
providerId?: string;
|
|
76
|
+
modelId?: string;
|
|
77
|
+
endpoint?: {
|
|
78
|
+
id?: string;
|
|
79
|
+
protocol?: string;
|
|
80
|
+
baseURL?: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
}, context: RenderedContext, tools: ToolSchema[], options?: Record<string, unknown>): ProviderRequestPlan;
|
|
84
|
+
export declare function recordPromptMeasurement(plan: Pick<ProviderRequestPlan, "fingerprint">, measurement: Omit<RecordedPromptMeasurement, "requestFingerprint">): RecordedPromptMeasurement;
|
|
85
|
+
export declare function measurementForPlan(plan: Pick<ProviderRequestPlan, "fingerprint">, record: RecordedPromptMeasurement | undefined): RecordedPromptMeasurement | undefined;
|
|
86
|
+
export declare function normalizeProviderUsage(usage: ProviderUsage): NormalizedProviderUsage;
|
|
87
|
+
export declare function priceProviderUsage(usage: NormalizedProviderUsage, snapshot: PricingSnapshot, observedAt?: string | Date): CostObservation;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { sha256Hex } from "../runtime/sha256.js";
|
|
2
|
+
/** Stable, provider-independent fallback used when no native token meter is available. */
|
|
3
|
+
export function estimateProviderPromptTokens(context, tools) {
|
|
4
|
+
const bytes = new TextEncoder().encode(stableJson({ context, tools })).byteLength;
|
|
5
|
+
return Math.max(1, Math.ceil(bytes / 4));
|
|
6
|
+
}
|
|
7
|
+
const EXCLUDED = new Set(["apiKey", "api_key", "bearerToken", "bearer_token", "authorization", "credential", "credentials", "retry", "maxRetries", "baseDelay", "timeout", "signal"]);
|
|
8
|
+
export function createProviderRequestPlan(input) {
|
|
9
|
+
const value = {
|
|
10
|
+
providerId: input.providerId, modelId: input.modelId, endpoint: sanitizeEndpoint(input.endpoint),
|
|
11
|
+
context: clone(input.context), tools: clone(input.tools), options: materialOptions(input.options ?? {}),
|
|
12
|
+
};
|
|
13
|
+
return { ...value, fingerprint: sha256Hex(stableJson(value)) };
|
|
14
|
+
}
|
|
15
|
+
export function createProviderRequestPlanForProvider(provider, context, tools, options) {
|
|
16
|
+
const descriptor = provider.descriptor?.() ?? { provider: "unknown", protocol: "unknown", model: "unknown" };
|
|
17
|
+
const identity = provider.requestPlanIdentity?.();
|
|
18
|
+
return createProviderRequestPlan({
|
|
19
|
+
providerId: identity?.providerId ?? descriptor.provider,
|
|
20
|
+
modelId: identity?.modelId ?? descriptor.model,
|
|
21
|
+
endpoint: {
|
|
22
|
+
id: identity?.endpoint?.id ?? `${descriptor.provider}.${descriptor.protocol}`,
|
|
23
|
+
protocol: identity?.endpoint?.protocol ?? descriptor.protocol,
|
|
24
|
+
baseURL: identity?.endpoint?.baseURL ?? "",
|
|
25
|
+
},
|
|
26
|
+
context, tools, options,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function recordPromptMeasurement(plan, measurement) {
|
|
30
|
+
if (!Number.isSafeInteger(measurement.inputTokens) || measurement.inputTokens < 0)
|
|
31
|
+
throw new RangeError("inputTokens must be a non-negative safe integer");
|
|
32
|
+
return { requestFingerprint: plan.fingerprint, inputTokens: measurement.inputTokens, source: clone(measurement.source), confidence: measurement.confidence };
|
|
33
|
+
}
|
|
34
|
+
export function measurementForPlan(plan, record) {
|
|
35
|
+
if (!record || record.requestFingerprint !== plan.fingerprint)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (!Number.isSafeInteger(record.inputTokens) || record.inputTokens < 0)
|
|
38
|
+
return undefined;
|
|
39
|
+
if (record.confidence !== "exact" && record.confidence !== "high_confidence" && record.confidence !== "low_confidence")
|
|
40
|
+
return undefined;
|
|
41
|
+
if (!record.source || typeof record.source !== "object")
|
|
42
|
+
return undefined;
|
|
43
|
+
if (record.source.kind === "native" && typeof record.source.provider === "string" && record.source.provider.length > 0)
|
|
44
|
+
return clone(record);
|
|
45
|
+
if (record.source.kind === "local_exact" && typeof record.source.tokenizer === "string" && record.source.tokenizer.length > 0)
|
|
46
|
+
return clone(record);
|
|
47
|
+
if (record.source.kind === "heuristic")
|
|
48
|
+
return clone(record);
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
export function normalizeProviderUsage(usage) {
|
|
52
|
+
const inputTokens = nonNegativeInteger(usage.inputTokens, "inputTokens");
|
|
53
|
+
const outputTokens = nonNegativeInteger(usage.outputTokens, "outputTokens");
|
|
54
|
+
const cacheReadInputTokens = optionalNonNegativeInteger(usage.cacheReadInputTokens, "cacheReadInputTokens");
|
|
55
|
+
const cacheCreationInputTokens = optionalNonNegativeInteger(usage.cacheCreationInputTokens, "cacheCreationInputTokens");
|
|
56
|
+
const reasoningTokens = optionalNonNegativeInteger(usage.reasoningTokens, "reasoningTokens");
|
|
57
|
+
const cached = (cacheReadInputTokens ?? 0) + (cacheCreationInputTokens ?? 0);
|
|
58
|
+
if (cached > inputTokens)
|
|
59
|
+
throw new RangeError("cache token subsets cannot exceed inputTokens");
|
|
60
|
+
if (reasoningTokens !== undefined && reasoningTokens > outputTokens)
|
|
61
|
+
throw new RangeError("reasoningTokens must be a subset of outputTokens");
|
|
62
|
+
return {
|
|
63
|
+
inputTokens,
|
|
64
|
+
uncachedInputTokens: inputTokens - cached,
|
|
65
|
+
outputTokens,
|
|
66
|
+
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
67
|
+
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
68
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function priceProviderUsage(usage, snapshot, observedAt = new Date()) {
|
|
72
|
+
const at = typeof observedAt === "string" ? new Date(observedAt) : observedAt;
|
|
73
|
+
const from = new Date(snapshot.effectiveFrom);
|
|
74
|
+
const expires = snapshot.expiresAt ? new Date(snapshot.expiresAt) : undefined;
|
|
75
|
+
const rates = snapshot.ratesPerMillion;
|
|
76
|
+
const requiredRates = [rates.input, rates.output];
|
|
77
|
+
if (!snapshot.version || !snapshot.currency || Number.isNaN(at.valueOf()) || Number.isNaN(from.valueOf())
|
|
78
|
+
|| requiredRates.some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)
|
|
79
|
+
|| Object.values(rates).some(rate => typeof rate !== "number" || !Number.isFinite(rate) || rate < 0)) {
|
|
80
|
+
return { source: "unpriced", reason: "invalid_pricing_snapshot" };
|
|
81
|
+
}
|
|
82
|
+
if (at < from)
|
|
83
|
+
return { source: "unpriced", reason: "pricing_snapshot_not_effective" };
|
|
84
|
+
if (expires && (Number.isNaN(expires.valueOf()) || at >= expires))
|
|
85
|
+
return { source: "unpriced", reason: "pricing_snapshot_expired" };
|
|
86
|
+
const amount = (usage.uncachedInputTokens * rates.input
|
|
87
|
+
+ usage.outputTokens * rates.output
|
|
88
|
+
+ (usage.cacheReadInputTokens ?? 0) * (rates.cacheRead ?? rates.input)
|
|
89
|
+
+ (usage.cacheCreationInputTokens ?? 0) * (rates.cacheCreation ?? rates.input)
|
|
90
|
+
+ (usage.reasoningTokens ?? 0) * (rates.reasoning ?? 0)) / 1_000_000;
|
|
91
|
+
return { source: "snapshot", currency: snapshot.currency, amount, pricingVersion: snapshot.version };
|
|
92
|
+
}
|
|
93
|
+
function materialOptions(options) {
|
|
94
|
+
return sanitizeMaterialValue(options);
|
|
95
|
+
}
|
|
96
|
+
function sanitizeEndpoint(endpoint) {
|
|
97
|
+
try {
|
|
98
|
+
const url = new URL(endpoint.baseURL);
|
|
99
|
+
url.username = "";
|
|
100
|
+
url.password = "";
|
|
101
|
+
url.search = "";
|
|
102
|
+
url.hash = "";
|
|
103
|
+
return { ...clone(endpoint), baseURL: url.toString().replace(/\/$/, "") };
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return { ...clone(endpoint), baseURL: "" };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function sanitizeMaterialValue(value) {
|
|
110
|
+
if (value === undefined || typeof value === "function")
|
|
111
|
+
return undefined;
|
|
112
|
+
if (Array.isArray(value))
|
|
113
|
+
return value.map(sanitizeMaterialValue).filter(item => item !== undefined);
|
|
114
|
+
if (value !== null && typeof value === "object") {
|
|
115
|
+
return Object.fromEntries(Object.keys(value).sort().flatMap(key => {
|
|
116
|
+
if (EXCLUDED.has(key) || isTransportOnlyKey(key))
|
|
117
|
+
return [];
|
|
118
|
+
const sanitized = sanitizeMaterialValue(value[key]);
|
|
119
|
+
return sanitized === undefined ? [] : [[key, sanitized]];
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
function isTransportOnlyKey(key) {
|
|
125
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
126
|
+
return normalized.includes("authorization") || normalized.includes("credential")
|
|
127
|
+
|| normalized.includes("accesstoken") || normalized.includes("refreshtoken")
|
|
128
|
+
|| normalized.includes("apikey") || normalized === "bearer" || normalized === "token"
|
|
129
|
+
|| normalized === "secret" || normalized === "xapikey";
|
|
130
|
+
}
|
|
131
|
+
function stableJson(value) {
|
|
132
|
+
if (value === null || typeof value !== "object")
|
|
133
|
+
return JSON.stringify(value);
|
|
134
|
+
if (Array.isArray(value))
|
|
135
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
136
|
+
const object = value;
|
|
137
|
+
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
|
|
138
|
+
}
|
|
139
|
+
function clone(value) {
|
|
140
|
+
if (value === undefined || value === null || typeof value !== "object")
|
|
141
|
+
return value;
|
|
142
|
+
if (Array.isArray(value))
|
|
143
|
+
return value.map(clone);
|
|
144
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clone(item)]));
|
|
145
|
+
}
|
|
146
|
+
function nonNegativeInteger(value, name) {
|
|
147
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
148
|
+
throw new RangeError(`${name} must be a non-negative safe integer`);
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function optionalNonNegativeInteger(value, name) {
|
|
152
|
+
return value === undefined ? undefined : nonNegativeInteger(value, name);
|
|
153
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type CanonicalStopReason = "end_turn" | "tool_use" | "max_tokens" | "stop_sequence" | "content_filter" | "other";
|
|
2
|
+
/** Validates the closed, provider-normalized stop-reason contract. */
|
|
3
|
+
export declare function decodeCanonicalStopReason(value: unknown): CanonicalStopReason;
|
|
4
|
+
/** Normalize an open-ended provider value into the closed runtime contract. */
|
|
5
|
+
export declare function normalizeProviderStopReason(value: unknown): CanonicalStopReason;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const KNOWN = new Set([
|
|
2
|
+
"end_turn",
|
|
3
|
+
"tool_use",
|
|
4
|
+
"max_tokens",
|
|
5
|
+
"stop_sequence",
|
|
6
|
+
"content_filter",
|
|
7
|
+
"other",
|
|
8
|
+
]);
|
|
9
|
+
/** Validates the closed, provider-normalized stop-reason contract. */
|
|
10
|
+
export function decodeCanonicalStopReason(value) {
|
|
11
|
+
if (typeof value !== "string" || !KNOWN.has(value)) {
|
|
12
|
+
throw new RangeError(`unknown canonical stop reason: ${String(value)}`);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
/** Normalize an open-ended provider value into the closed runtime contract. */
|
|
17
|
+
export function normalizeProviderStopReason(value) {
|
|
18
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
19
|
+
throw new RangeError(`invalid provider stop reason: ${String(value)}`);
|
|
20
|
+
}
|
|
21
|
+
return KNOWN.has(value)
|
|
22
|
+
? value
|
|
23
|
+
: "other";
|
|
24
|
+
}
|
|
@@ -94,13 +94,9 @@ export interface CanonicalRunnerRuntimeOptions {
|
|
|
94
94
|
}>;
|
|
95
95
|
}
|
|
96
96
|
export declare function sha256(value: string): string;
|
|
97
|
-
/** Small synchronous SHA-256 for Worker/browser hosts (no node:crypto). */
|
|
98
|
-
declare function syncSha256(value: string): string;
|
|
99
|
-
export { syncSha256 as sha256Hex };
|
|
100
97
|
/**
|
|
101
98
|
* Canonical operation runtime used by the WASM host.
|
|
102
|
-
* Every durable transition below is one of the canonical
|
|
103
|
-
* envelope or synthesized host transaction reaches core or storage.
|
|
99
|
+
* Every durable transition below is one of the canonical contract's five input classes.
|
|
104
100
|
*/
|
|
105
101
|
export declare class CanonicalRunnerRuntime {
|
|
106
102
|
private readonly options;
|
|
@@ -153,3 +149,4 @@ export declare function canonicalKernelAction(runtime: CanonicalRunnerRuntime, p
|
|
|
153
149
|
export declare function canonicalStartAgent(runtime: CanonicalRunnerRuntime, pending: KernelObservationLike[], task: Record<string, unknown>, runSpec?: Record<string, unknown>): Promise<KernelRunnerAction>;
|
|
154
150
|
export declare function canonicalStartWorkflow(runtime: CanonicalRunnerRuntime, pending: KernelObservationLike[], spec: Record<string, unknown>): Promise<KernelRunnerAction | null>;
|
|
155
151
|
type KernelObservationLike = KernelObservation;
|
|
152
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeProviderStopReason } from "../providers/stop-reason.js";
|
|
2
|
+
import { sha256Hex } from "./sha256.js";
|
|
2
3
|
import { JournalCasConflictError, MAX_CHAIN_POSITION as JOURNAL_MAX_CHAIN_POSITION, } from "./kernel-journal.js";
|
|
3
4
|
import { encodeCanonicalContentParts, kernelMessageToSdk, renderedContextToSdk, } from "./kernel-step.js";
|
|
4
5
|
export const MAX_CHAIN_POSITION = JOURNAL_MAX_CHAIN_POSITION;
|
|
@@ -343,7 +344,6 @@ export class CanonicalKernelHost {
|
|
|
343
344
|
}
|
|
344
345
|
async transition(input, options = {}) {
|
|
345
346
|
const inputJson = JSON.stringify({
|
|
346
|
-
abi_version: kernelAbiVersion(),
|
|
347
347
|
operation_id: this.operationId,
|
|
348
348
|
input_id: options.inputId ?? `wasm-input-${crypto.randomUUID()}`,
|
|
349
349
|
observed_at_ms: options.observedAtMs ?? String(Date.now()),
|
|
@@ -591,7 +591,7 @@ function logicalRunSpec(raw, goal) {
|
|
|
591
591
|
...(raw.metadata && typeof raw.metadata === "object" ? { metadata: raw.metadata } : {}),
|
|
592
592
|
};
|
|
593
593
|
}
|
|
594
|
-
function canonicalWorkflowSpec(raw) {
|
|
594
|
+
function canonicalWorkflowSpec(raw, allowHostSchedulingFactors = false) {
|
|
595
595
|
const nodes = Array.isArray(raw.nodes) ? raw.nodes.map(asObject) : [];
|
|
596
596
|
const nodeIds = nodes.map((_node, index) => `wf-node${index}`);
|
|
597
597
|
return {
|
|
@@ -614,6 +614,9 @@ function canonicalWorkflowSpec(raw) {
|
|
|
614
614
|
unsupported.push("max_turns");
|
|
615
615
|
if (node.max_wall_ms !== undefined || node.maxWallMs !== undefined)
|
|
616
616
|
unsupported.push("max_wall_ms");
|
|
617
|
+
const schedulingFactors = node.scheduling_factors ?? node.schedulingFactors;
|
|
618
|
+
if (schedulingFactors !== undefined && !allowHostSchedulingFactors)
|
|
619
|
+
unsupported.push("scheduling_factors");
|
|
617
620
|
const inheritance = node.context_inheritance ?? node.contextInheritance;
|
|
618
621
|
if (unsupported.length > 0) {
|
|
619
622
|
throw new CanonicalKernelRejectedError(JSON.stringify({
|
|
@@ -634,16 +637,20 @@ function canonicalWorkflowSpec(raw) {
|
|
|
634
637
|
: [];
|
|
635
638
|
const modelHint = node.model_hint ?? node.modelHint;
|
|
636
639
|
const outputSchema = node.output_schema ?? node.outputSchema;
|
|
640
|
+
const canonicalSchedulingFactors = schedulingFactors === undefined
|
|
641
|
+
? undefined
|
|
642
|
+
: canonicalSchedulingFactorsForHost(schedulingFactors);
|
|
637
643
|
const runSpec = logicalRunSpec({
|
|
638
644
|
goal,
|
|
639
645
|
...(node.role ? { role: node.role } : {}),
|
|
640
646
|
...(node.isolation ? { isolation: node.isolation } : {}),
|
|
641
647
|
...(inheritance ? { context_inheritance: inheritance } : {}),
|
|
642
|
-
...((modelHint !== undefined || outputSchema !== undefined)
|
|
648
|
+
...((modelHint !== undefined || outputSchema !== undefined || canonicalSchedulingFactors !== undefined)
|
|
643
649
|
? {
|
|
644
650
|
metadata: {
|
|
645
651
|
...(modelHint !== undefined ? { model_hint: modelHint } : {}),
|
|
646
652
|
...(outputSchema !== undefined ? { output_schema: outputSchema } : {}),
|
|
653
|
+
...(canonicalSchedulingFactors !== undefined ? { scheduling_factors: canonicalSchedulingFactors } : {}),
|
|
647
654
|
},
|
|
648
655
|
}
|
|
649
656
|
: {}),
|
|
@@ -661,62 +668,35 @@ function canonicalWorkflowSpec(raw) {
|
|
|
661
668
|
}),
|
|
662
669
|
};
|
|
663
670
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
const
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
const h = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);
|
|
678
|
-
const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
|
|
679
|
-
const ror = (x, n) => (x >>> n) | (x << (32 - n));
|
|
680
|
-
for (let offset = 0; offset < data.length; offset += 64) {
|
|
681
|
-
const w = new Uint32Array(64);
|
|
682
|
-
const view = new DataView(data.buffer, offset, 64);
|
|
683
|
-
for (let i = 0; i < 16; i++)
|
|
684
|
-
w[i] = view.getUint32(i * 4, false);
|
|
685
|
-
for (let i = 16; i < 64; i++) {
|
|
686
|
-
w[i] = (w[i - 16] + (ror(w[i - 15], 7) ^ ror(w[i - 15], 18) ^ (w[i - 15] >>> 3)) + w[i - 7] + (ror(w[i - 2], 17) ^ ror(w[i - 2], 19) ^ (w[i - 2] >>> 10))) >>> 0;
|
|
671
|
+
function canonicalSchedulingFactorsForHost(value) {
|
|
672
|
+
const raw = asObject(value);
|
|
673
|
+
const allowed = new Set(["deadline_urgency", "process_priority", "resource_pressure", "budget_pressure"]);
|
|
674
|
+
const unknown = Object.keys(raw).filter(key => !allowed.has(key));
|
|
675
|
+
if (unknown.length > 0)
|
|
676
|
+
throw new TypeError(`unknown scheduling factor(s): ${unknown.join(", ")}`);
|
|
677
|
+
const factors = {};
|
|
678
|
+
for (const key of allowed) {
|
|
679
|
+
const factor = raw[key];
|
|
680
|
+
if (factor === undefined)
|
|
681
|
+
continue;
|
|
682
|
+
if (!Number.isSafeInteger(factor) || factor < 0) {
|
|
683
|
+
throw new RangeError(`scheduling_factors.${key} must be a non-negative safe integer`);
|
|
687
684
|
}
|
|
688
|
-
|
|
689
|
-
for (let i = 0; i < 64; i++) {
|
|
690
|
-
const t1 = (hh + (ror(e, 6) ^ ror(e, 11) ^ ror(e, 25)) + ((e & f) ^ ((~e) & g)) + k[i] + w[i]) >>> 0;
|
|
691
|
-
const t2 = ((ror(a, 2) ^ ror(a, 13) ^ ror(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
|
|
692
|
-
hh = g;
|
|
693
|
-
g = f;
|
|
694
|
-
f = e;
|
|
695
|
-
e = (d + t1) >>> 0;
|
|
696
|
-
d = c;
|
|
697
|
-
c = b;
|
|
698
|
-
b = a;
|
|
699
|
-
a = (t1 + t2) >>> 0;
|
|
700
|
-
}
|
|
701
|
-
for (let i = 0; i < 8; i++)
|
|
702
|
-
h[i] = (h[i] + [a, b, c, d, e, f, g, hh][i]) >>> 0;
|
|
685
|
+
factors[key] = factor;
|
|
703
686
|
}
|
|
704
|
-
return
|
|
687
|
+
return factors;
|
|
688
|
+
}
|
|
689
|
+
export function sha256(value) {
|
|
690
|
+
return sha256Hex(value);
|
|
705
691
|
}
|
|
706
|
-
export { syncSha256 as sha256Hex };
|
|
707
692
|
function providerStopReason(value) {
|
|
708
|
-
if (
|
|
693
|
+
if (value === undefined || value === null || value === "")
|
|
709
694
|
return undefined;
|
|
710
|
-
|
|
711
|
-
if (["end_turn", "tool_use", "max_tokens", "stop_sequence", "content_filter"].includes(normalized)) {
|
|
712
|
-
return normalized;
|
|
713
|
-
}
|
|
714
|
-
return "other";
|
|
695
|
+
return normalizeProviderStopReason(value);
|
|
715
696
|
}
|
|
716
697
|
/**
|
|
717
698
|
* Canonical operation runtime used by the WASM host.
|
|
718
|
-
* Every durable transition below is one of the canonical
|
|
719
|
-
* envelope or synthesized host transaction reaches core or storage.
|
|
699
|
+
* Every durable transition below is one of the canonical contract's five input classes.
|
|
720
700
|
*/
|
|
721
701
|
export class CanonicalRunnerRuntime {
|
|
722
702
|
options;
|
|
@@ -842,7 +822,7 @@ export class CanonicalRunnerRuntime {
|
|
|
842
822
|
kind: "start_operation",
|
|
843
823
|
entry: {
|
|
844
824
|
kind: "workflow",
|
|
845
|
-
spec: canonicalWorkflowSpec(specValue),
|
|
825
|
+
spec: canonicalWorkflowSpec(specValue, true),
|
|
846
826
|
},
|
|
847
827
|
initial_context: this.initialContext,
|
|
848
828
|
});
|
|
@@ -896,7 +876,8 @@ export class CanonicalRunnerRuntime {
|
|
|
896
876
|
}
|
|
897
877
|
case "provider_error": {
|
|
898
878
|
const message = String(event.message ?? "");
|
|
899
|
-
const
|
|
879
|
+
const errorKind = typeof event.error_kind === "string" ? event.error_kind : "unknown";
|
|
880
|
+
const contextOverflow = errorKind === "context_overflow";
|
|
900
881
|
input = contextOverflow
|
|
901
882
|
? {
|
|
902
883
|
kind: "resolve_effect",
|
|
@@ -906,7 +887,11 @@ export class CanonicalRunnerRuntime {
|
|
|
906
887
|
result: { kind: "provider", outcome: { kind: "context_overflow" } },
|
|
907
888
|
},
|
|
908
889
|
}
|
|
909
|
-
: this.failedEffect(event, "
|
|
890
|
+
: this.failedEffect(event, ["transport", "rate_limit", "model_unavailable"].includes(errorKind)
|
|
891
|
+
? "transport_exhausted"
|
|
892
|
+
: ["auth", "invalid_request", "modality", "protocol"].includes(errorKind)
|
|
893
|
+
? "protocol_error"
|
|
894
|
+
: "unknown", message, typeof event.retryable === "boolean" ? event.retryable : false);
|
|
910
895
|
break;
|
|
911
896
|
}
|
|
912
897
|
case "tool_results": {
|
|
@@ -1465,9 +1450,6 @@ export class CanonicalRunnerRuntime {
|
|
|
1465
1450
|
delete asObject(execution.entropy_watch).threshold;
|
|
1466
1451
|
delete asObject(execution.entropy_watch).hysteresis;
|
|
1467
1452
|
}
|
|
1468
|
-
if (config.tool_dispatch_gate !== undefined) {
|
|
1469
|
-
this.featurePolicy().tool_dispatch_gate = config.tool_dispatch_gate;
|
|
1470
|
-
}
|
|
1471
1453
|
if (config.knowledge_budget_ratio !== undefined) {
|
|
1472
1454
|
const context = asObject(this.config.context_policy);
|
|
1473
1455
|
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,44 @@
|
|
|
1
|
+
export declare class DurableContentError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export type DurableSource = {
|
|
5
|
+
kind: "url";
|
|
6
|
+
url: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "base64";
|
|
9
|
+
data: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "file_id";
|
|
12
|
+
id: string;
|
|
13
|
+
affinity: {
|
|
14
|
+
provider_id: string;
|
|
15
|
+
endpoint_id: string;
|
|
16
|
+
};
|
|
17
|
+
} | {
|
|
18
|
+
kind: "object";
|
|
19
|
+
handle: string;
|
|
20
|
+
owner: string;
|
|
21
|
+
payload_ref: string;
|
|
22
|
+
};
|
|
23
|
+
export type DurableContentBlock = {
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: "image" | "audio" | "video" | "file";
|
|
28
|
+
source: DurableSource;
|
|
29
|
+
media_type?: string;
|
|
30
|
+
provider_options?: Record<string, unknown>;
|
|
31
|
+
};
|
|
32
|
+
export interface DurableContent {
|
|
33
|
+
blocks: DurableContentBlock[];
|
|
34
|
+
}
|
|
35
|
+
export interface DurableToolResult extends DurableContent {
|
|
36
|
+
call_id: string;
|
|
37
|
+
is_error: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function decodeDurableContent(value: unknown): DurableContent;
|
|
40
|
+
export declare function decodeDurableToolResult(value: unknown): DurableToolResult;
|
|
41
|
+
export declare function encodeDurableContent(content: DurableContent): Record<string, unknown>;
|
|
42
|
+
export declare function encodeDurableToolResult(result: DurableToolResult): Record<string, unknown>;
|
|
43
|
+
export declare function toolOutputBlocksToDurable(blocks: readonly import("../types.js").ToolOutputBlock[]): DurableContentBlock[];
|
|
44
|
+
export declare function durableBlocksToToolOutput(blocks: readonly DurableContentBlock[]): import("../types.js").ToolOutputBlock[];
|