@deepstrike/wasm 0.2.63 → 0.2.64
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/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/providers/request-plan.d.ts +25 -2
- package/dist/providers/request-plan.js +49 -0
- package/dist/runtime/execution-evidence.d.ts +3 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/runner.d.ts +22 -0
- package/dist/runtime/runner.js +141 -7
- package/dist/runtime/session-log.d.ts +8 -0
- package/dist/runtime/session-log.js +72 -0
- package/dist/runtime/session-repair.d.ts +4 -1
- package/dist/runtime/session-repair.js +8 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, SESSION_EVENT_KINDS, LocalExecutionPlane, DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, DEFAULT_SANDBOX_POLICY, assertNativeProfile, osProfile, validateDeclarativePolicy, ReplayProvider, extractRecordedMessages, judge, buildEvalMessages, parseVerdict, verdictOutputSchema, } from "./runtime/index.js";
|
|
1
|
+
export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, assertCanonicalProviderAttemptRecord, SESSION_EVENT_KINDS, LocalExecutionPlane, DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, DEFAULT_SANDBOX_POLICY, assertNativeProfile, osProfile, validateDeclarativePolicy, ReplayProvider, extractRecordedMessages, judge, buildEvalMessages, parseVerdict, verdictOutputSchema, } from "./runtime/index.js";
|
|
2
2
|
export { DriverKernelJournal, InMemoryJournalDriver, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, } from "./runtime/kernel-journal.js";
|
|
3
3
|
export type { CheckpointCandidate, InstalledCheckpoint, JournalAppendReceipt, JournalEntry, JournalHead, JournalPruneReceipt, JournalRecordInput, JournalStorageDriver, KernelJournal, } from "./runtime/kernel-journal.js";
|
|
4
4
|
export { CANONICAL_CONTENT_PARTS_PREFIX, encodeCanonicalContentParts, decodeCanonicalContentParts, } from "./runtime/kernel-step.js";
|
|
@@ -42,7 +42,7 @@ export type { RuntimeSignal, SignalSource } from "./signals/index.js";
|
|
|
42
42
|
export { PermissionManager, PermissionMode } from "./safety/index.js";
|
|
43
43
|
export { createProviderRequestPlan, createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, normalizeProviderUsage, priceProviderUsage, recordPromptMeasurement } from "./providers/request-plan.js";
|
|
44
44
|
export type { CostObservation, NormalizedProviderUsage, PricingSnapshot, ProviderRequestEndpoint, ProviderRequestPlan, ProviderUsage, RecordedPromptMeasurement, ResolvedProviderRoute } from "./providers/request-plan.js";
|
|
45
|
-
export type { ProviderAttempt, ProviderAttemptRecord, ProviderAttemptStatus, ModelInvocation, InvocationOutcome,
|
|
45
|
+
export type { ProviderAttempt, ProviderAttemptRecord, ProviderAttemptStatus, ModelInvocation, InvocationOutcome, ModelUsageSettlement, UsageAccountingPolicy, } from "./runtime/execution-evidence.js";
|
|
46
46
|
export { FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY, providerAttemptToRecord, tryNormalizeProviderUsage } from "./runtime/execution-evidence.js";
|
|
47
47
|
export { decodeCanonicalStopReason, normalizeProviderStopReason } from "./providers/stop-reason.js";
|
|
48
48
|
export type { CanonicalStopReason } from "./providers/stop-reason.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, SESSION_EVENT_KINDS, LocalExecutionPlane, DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, DEFAULT_SANDBOX_POLICY, assertNativeProfile, osProfile, validateDeclarativePolicy, ReplayProvider, extractRecordedMessages, judge, buildEvalMessages, parseVerdict, verdictOutputSchema, } from "./runtime/index.js";
|
|
1
|
+
export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, assertCanonicalProviderAttemptRecord, SESSION_EVENT_KINDS, LocalExecutionPlane, DEFAULT_NATIVE_SIGNAL_POLICY, DEFAULT_NATIVE_GOVERNANCE_POLICY, DEFAULT_SANDBOX_POLICY, assertNativeProfile, osProfile, validateDeclarativePolicy, ReplayProvider, extractRecordedMessages, judge, buildEvalMessages, parseVerdict, verdictOutputSchema, } from "./runtime/index.js";
|
|
2
2
|
// ── Durable transaction capability (Canonical Kernel ABI §9.1) ──────────────
|
|
3
3
|
export { DriverKernelJournal, InMemoryJournalDriver, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, } from "./runtime/kernel-journal.js";
|
|
4
4
|
// ── content-parts-v1 registered encoding (F14/B5; byte-pinned by sdk-conformance) ──
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RenderedContext, ToolSchema } from "../types.js";
|
|
1
|
+
import type { ProviderProtocol, RenderedContext, ToolSchema } from "../types.js";
|
|
2
2
|
export interface ProviderRequestEndpoint {
|
|
3
3
|
id: string;
|
|
4
4
|
protocol: string;
|
|
@@ -40,7 +40,7 @@ export interface ProviderUsage {
|
|
|
40
40
|
export interface ResolvedProviderRoute {
|
|
41
41
|
routeId: string;
|
|
42
42
|
provider: string;
|
|
43
|
-
protocol:
|
|
43
|
+
protocol: ProviderProtocol;
|
|
44
44
|
model: string;
|
|
45
45
|
endpoint: ProviderRequestEndpoint;
|
|
46
46
|
adapterVersion: string;
|
|
@@ -95,3 +95,26 @@ export declare function recordPromptMeasurement(plan: Pick<ProviderRequestPlan,
|
|
|
95
95
|
export declare function measurementForPlan(plan: Pick<ProviderRequestPlan, "fingerprint">, record: RecordedPromptMeasurement | undefined): RecordedPromptMeasurement | undefined;
|
|
96
96
|
export declare function normalizeProviderUsage(usage: ProviderUsage): NormalizedProviderUsage;
|
|
97
97
|
export declare function priceProviderUsage(usage: NormalizedProviderUsage, snapshot: PricingSnapshot, observedAt?: string | Date): CostObservation;
|
|
98
|
+
/**
|
|
99
|
+
* P4-S1: assemble the run's route once at runner construction (P4 §0.2 — the provider is
|
|
100
|
+
* fixed for the run today; a future failover resolver re-evaluates per attempt with the same
|
|
101
|
+
* shape). Never throws: evidence assembly degrades to "unknown" fields rather than breaking a
|
|
102
|
+
* run. The wasm bundle cannot read its own package manifest at runtime (browser targets), so
|
|
103
|
+
* adapterVersion is honestly "unknown" — the field is a report, not a gate.
|
|
104
|
+
*/
|
|
105
|
+
export declare function resolveProviderRoute(provider: {
|
|
106
|
+
descriptor?(): {
|
|
107
|
+
provider: string;
|
|
108
|
+
protocol: string;
|
|
109
|
+
model: string;
|
|
110
|
+
};
|
|
111
|
+
requestPlanIdentity?(): {
|
|
112
|
+
providerId?: string;
|
|
113
|
+
modelId?: string;
|
|
114
|
+
endpoint?: {
|
|
115
|
+
id?: string;
|
|
116
|
+
protocol?: string;
|
|
117
|
+
baseURL?: string;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
}): ResolvedProviderRoute;
|
|
@@ -106,6 +106,55 @@ function sanitizeEndpoint(endpoint) {
|
|
|
106
106
|
return { ...clone(endpoint), baseURL: "" };
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
const KNOWN_GENERATION_PROTOCOLS = new Set([
|
|
110
|
+
"anthropic-messages",
|
|
111
|
+
"openai-chat",
|
|
112
|
+
"openai-responses",
|
|
113
|
+
"gemini",
|
|
114
|
+
"ollama-chat",
|
|
115
|
+
]);
|
|
116
|
+
/**
|
|
117
|
+
* P4-S1: assemble the run's route once at runner construction (P4 §0.2 — the provider is
|
|
118
|
+
* fixed for the run today; a future failover resolver re-evaluates per attempt with the same
|
|
119
|
+
* shape). Never throws: evidence assembly degrades to "unknown" fields rather than breaking a
|
|
120
|
+
* run. The wasm bundle cannot read its own package manifest at runtime (browser targets), so
|
|
121
|
+
* adapterVersion is honestly "unknown" — the field is a report, not a gate.
|
|
122
|
+
*/
|
|
123
|
+
export function resolveProviderRoute(provider) {
|
|
124
|
+
try {
|
|
125
|
+
const descriptor = provider.descriptor?.() ?? { provider: "unknown", protocol: "unknown", model: "unknown" };
|
|
126
|
+
const identity = provider.requestPlanIdentity?.();
|
|
127
|
+
const protocolRaw = identity?.endpoint?.protocol ?? descriptor.protocol;
|
|
128
|
+
// Evidence records what the descriptor said, even when a foreign provider speaks a protocol
|
|
129
|
+
// outside the in-tree vocabulary — the field is a report, not a gate.
|
|
130
|
+
const protocol = protocolRaw;
|
|
131
|
+
const route = {
|
|
132
|
+
provider: identity?.providerId ?? descriptor.provider,
|
|
133
|
+
protocol,
|
|
134
|
+
model: identity?.modelId ?? descriptor.model,
|
|
135
|
+
endpoint: sanitizeEndpoint({
|
|
136
|
+
id: identity?.endpoint?.id ?? `${descriptor.provider}.${descriptor.protocol}`,
|
|
137
|
+
protocol: protocolRaw,
|
|
138
|
+
baseURL: identity?.endpoint?.baseURL ?? "",
|
|
139
|
+
}),
|
|
140
|
+
adapterVersion: "unknown",
|
|
141
|
+
capabilitiesRef: KNOWN_GENERATION_PROTOCOLS.has(protocolRaw) ? protocolRaw : "unknown",
|
|
142
|
+
};
|
|
143
|
+
// §1.3: content addressing covers every field EXCEPT capabilitiesRef (a reference, not content).
|
|
144
|
+
const { capabilitiesRef: _ref, ...addressed } = route;
|
|
145
|
+
return { ...route, routeId: sha256Hex(stableJson(addressed)) };
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
const fallback = {
|
|
149
|
+
provider: "unknown",
|
|
150
|
+
protocol: "unknown",
|
|
151
|
+
model: "unknown",
|
|
152
|
+
endpoint: { id: "unknown", protocol: "unknown", baseURL: "" },
|
|
153
|
+
adapterVersion: "unknown",
|
|
154
|
+
};
|
|
155
|
+
return { ...fallback, capabilitiesRef: "unknown", routeId: sha256Hex(stableJson(fallback)) };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
109
158
|
function sanitizeMaterialValue(value) {
|
|
110
159
|
if (value === undefined || typeof value === "function")
|
|
111
160
|
return undefined;
|
|
@@ -29,7 +29,7 @@ export interface InvocationOutcome {
|
|
|
29
29
|
selectedEffectId: string;
|
|
30
30
|
stopReason?: CanonicalStopReason;
|
|
31
31
|
/** Absent on a failed chain (nothing settled). */
|
|
32
|
-
settlement?:
|
|
32
|
+
settlement?: ModelUsageSettlement;
|
|
33
33
|
}
|
|
34
34
|
export type ProviderAttemptStatus = "success" | "transport_exhausted" | "aborted" | "rejected";
|
|
35
35
|
/**
|
|
@@ -84,7 +84,7 @@ export declare function providerAttemptToRecord(attempt: ProviderAttempt, accoun
|
|
|
84
84
|
* existing ResolveEffect wire shape — this is what the runner already feeds the kernel as
|
|
85
85
|
* `observed_input_tokens` / `observed_output_tokens`.
|
|
86
86
|
*/
|
|
87
|
-
export interface
|
|
87
|
+
export interface ModelUsageSettlement {
|
|
88
88
|
observed_input_tokens: number;
|
|
89
89
|
observed_output_tokens: number;
|
|
90
90
|
}
|
|
@@ -95,7 +95,7 @@ export interface UsageSettlement {
|
|
|
95
95
|
*/
|
|
96
96
|
export interface UsageAccountingPolicy {
|
|
97
97
|
policyId: string;
|
|
98
|
-
settle(usage: NormalizedProviderUsage):
|
|
98
|
+
settle(usage: NormalizedProviderUsage): ModelUsageSettlement;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* The default policy = today's implicit runner behavior exactly (full input footprint + full
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { SessionEvent, SessionEventKind, SessionLog } from "./session-log.js";
|
|
2
|
-
export { InMemorySessionLog } from "./session-log.js";
|
|
2
|
+
export { InMemorySessionLog, assertCanonicalProviderAttemptRecord } from "./session-log.js";
|
|
3
3
|
export { SESSION_EVENT_KINDS } from "./session-log.js";
|
|
4
4
|
export { DriverKernelJournal, InMemoryJournalDriver, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, } from "./kernel-journal.js";
|
|
5
5
|
export type { CheckpointCandidate, InstalledCheckpoint, JournalAppendReceipt, JournalEntry, JournalHead, JournalPruneReceipt, JournalRecordInput, JournalStorageDriver, KernelJournal, } from "./kernel-journal.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { InMemorySessionLog } from "./session-log.js";
|
|
1
|
+
export { InMemorySessionLog, assertCanonicalProviderAttemptRecord } from "./session-log.js";
|
|
2
2
|
// Registered session-event vocabulary (F9/S3; manifest-pinned by sdk-conformance, P7-S4)
|
|
3
3
|
export { SESSION_EVENT_KINDS } from "./session-log.js";
|
|
4
4
|
// Durable transaction capability (Canonical Kernel ABI §9.1)
|
package/dist/runtime/runner.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { type ReducerRegistry } from "./reducers.js";
|
|
|
13
13
|
import { type NativeOsProfile, type OsProfileId, type SignalPolicy } from "./os-profile.js";
|
|
14
14
|
import { PayloadStore } from "./payload-store.js";
|
|
15
15
|
import { type ContextPolicyOverrides } from "./context-policy.js";
|
|
16
|
+
import { type UsageAccountingPolicy } from "./execution-evidence.js";
|
|
16
17
|
export interface MemoryWriteRateLimit {
|
|
17
18
|
maxWrites: number;
|
|
18
19
|
windowMs: number;
|
|
@@ -140,6 +141,10 @@ export interface RuntimeOptions {
|
|
|
140
141
|
governancePolicy?: GovernancePolicy;
|
|
141
142
|
signalPolicy?: SignalPolicy;
|
|
142
143
|
promptBudget?: PromptBudget;
|
|
144
|
+
/** P4 §2.1: the named policy turning a provider measurement into the two observed_* numbers
|
|
145
|
+
* that cross the kernel boundary. Undefined ⇒ FULL_FOOTPRINT (the numbers the runner has
|
|
146
|
+
* always fed); only makes the conversion named, pinnable on `provider_attempt`, replayable. */
|
|
147
|
+
usageAccountingPolicy?: UsageAccountingPolicy;
|
|
143
148
|
/** Stable replayable context behavior; ratios are normalized to integer ppm. */
|
|
144
149
|
contextPolicy?: ContextPolicyOverrides;
|
|
145
150
|
schedulerPolicy?: SchedulerPolicy;
|
|
@@ -281,7 +286,24 @@ export declare class RuntimeRunner {
|
|
|
281
286
|
private activePageOutArchive;
|
|
282
287
|
/** Provider continuation emitted after a canonical nested workflow completes. */
|
|
283
288
|
private workflowContinuation;
|
|
289
|
+
/** P4 (0.2.64 Evidence Plane): the resolved route every provider attempt is pinned to —
|
|
290
|
+
* resolved once so evidence identity is byte-stable across the run (C6.3 pins in-run
|
|
291
|
+
* route stability). */
|
|
292
|
+
private readonly providerRoute;
|
|
293
|
+
private readonly usageAccountingPolicy;
|
|
294
|
+
/** P4 §1.1: the active invocation's derived identity = its chain's FIRST effect_id. Tracked
|
|
295
|
+
* across the kernel-recovered retry loop; a fresh call_provider with no pending retry opens
|
|
296
|
+
* a new invocation. */
|
|
297
|
+
private providerRetryPending;
|
|
298
|
+
private activeProviderInvocationId;
|
|
284
299
|
constructor(opts: RuntimeOptions);
|
|
300
|
+
/**
|
|
301
|
+
* P4-S1 (G1): land one provider_attempt evidence record per effect execution. Pure host
|
|
302
|
+
* evidence (B7) — appended AFTER the transport fact exists (success/failure/abort), never
|
|
303
|
+
* consulted for kernel input. The accounting policy id pins only when a measurement exists,
|
|
304
|
+
* so (usage, policy_id) deterministically recomputes the settlement that crossed the wire.
|
|
305
|
+
*/
|
|
306
|
+
private appendProviderAttempt;
|
|
285
307
|
private resolveKernelJournal;
|
|
286
308
|
private createCanonicalRuntime;
|
|
287
309
|
private commitKernelApply;
|
package/dist/runtime/runner.js
CHANGED
|
@@ -19,7 +19,8 @@ import { assertNativeProfile } from "./os-profile.js";
|
|
|
19
19
|
import { classifyProviderError, providerErrorEventFields } from "../providers/provider-error.js";
|
|
20
20
|
import { PayloadStore } from "./payload-store.js";
|
|
21
21
|
import { contextPolicy, normalizeContextPolicy, } from "./context-policy.js";
|
|
22
|
-
import { createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, recordPromptMeasurement, } from "../providers/request-plan.js";
|
|
22
|
+
import { createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, recordPromptMeasurement, resolveProviderRoute, } from "../providers/request-plan.js";
|
|
23
|
+
import { FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY, providerAttemptToRecord, tryNormalizeProviderUsage, } from "./execution-evidence.js";
|
|
23
24
|
export function schedulerPolicyToKernel(policy) {
|
|
24
25
|
const allowed = new Set([
|
|
25
26
|
"criticalPathWeight", "fanoutWeight", "ageWeight", "tokenCostWeight",
|
|
@@ -121,12 +122,36 @@ export class RuntimeRunner {
|
|
|
121
122
|
activePageOutArchive;
|
|
122
123
|
/** Provider continuation emitted after a canonical nested workflow completes. */
|
|
123
124
|
workflowContinuation = null;
|
|
125
|
+
/** P4 (0.2.64 Evidence Plane): the resolved route every provider attempt is pinned to —
|
|
126
|
+
* resolved once so evidence identity is byte-stable across the run (C6.3 pins in-run
|
|
127
|
+
* route stability). */
|
|
128
|
+
providerRoute;
|
|
129
|
+
usageAccountingPolicy;
|
|
130
|
+
/** P4 §1.1: the active invocation's derived identity = its chain's FIRST effect_id. Tracked
|
|
131
|
+
* across the kernel-recovered retry loop; a fresh call_provider with no pending retry opens
|
|
132
|
+
* a new invocation. */
|
|
133
|
+
providerRetryPending = false;
|
|
134
|
+
activeProviderInvocationId;
|
|
124
135
|
constructor(opts) {
|
|
125
136
|
this.opts = opts;
|
|
126
137
|
const schemaAttempts = opts.workflowSchemaValidationAttempts ?? 2;
|
|
127
138
|
if (!Number.isInteger(schemaAttempts) || schemaAttempts < 1 || schemaAttempts > 16) {
|
|
128
139
|
throw new RangeError("workflowSchemaValidationAttempts must be an integer between 1 and 16");
|
|
129
140
|
}
|
|
141
|
+
this.providerRoute = resolveProviderRoute(opts.provider);
|
|
142
|
+
this.usageAccountingPolicy = opts.usageAccountingPolicy ?? FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* P4-S1 (G1): land one provider_attempt evidence record per effect execution. Pure host
|
|
146
|
+
* evidence (B7) — appended AFTER the transport fact exists (success/failure/abort), never
|
|
147
|
+
* consulted for kernel input. The accounting policy id pins only when a measurement exists,
|
|
148
|
+
* so (usage, policy_id) deterministically recomputes the settlement that crossed the wire.
|
|
149
|
+
*/
|
|
150
|
+
async appendProviderAttempt(sessionId, attempt) {
|
|
151
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
152
|
+
kind: "provider_attempt",
|
|
153
|
+
...providerAttemptToRecord(attempt, attempt.usage ? this.usageAccountingPolicy.policyId : undefined),
|
|
154
|
+
});
|
|
130
155
|
}
|
|
131
156
|
resolveKernelJournal() {
|
|
132
157
|
const embedded = this.opts.sessionLog;
|
|
@@ -269,6 +294,7 @@ export class RuntimeRunner {
|
|
|
269
294
|
agent_id: this.opts.agentId,
|
|
270
295
|
system_prompt: this.opts.systemPrompt,
|
|
271
296
|
...(attachments ? { attachments } : {}),
|
|
297
|
+
route: this.providerRoute,
|
|
272
298
|
});
|
|
273
299
|
}
|
|
274
300
|
yield* this.execute(req.sessionId, runId, req.goal, req.criteria ?? [], req.extensions, prior.length > 0 ? prior : undefined, midRun, attachments);
|
|
@@ -355,7 +381,7 @@ export class RuntimeRunner {
|
|
|
355
381
|
await this.commitKernelApply(this.activeKernel, this.pendingObservations, { kind: "skill_deactivated", name });
|
|
356
382
|
this.knowledgePushedSkills.delete(name);
|
|
357
383
|
}
|
|
358
|
-
async resolveKernelSuspend(requests, runtime, sessionId) {
|
|
384
|
+
async resolveKernelSuspend(requests, runtime, sessionId, effectId) {
|
|
359
385
|
const approved = [];
|
|
360
386
|
const denied = [];
|
|
361
387
|
const events = [];
|
|
@@ -421,6 +447,8 @@ export class RuntimeRunner {
|
|
|
421
447
|
await this.opts.sessionLog.append(sessionId, {
|
|
422
448
|
kind: "tool_completed",
|
|
423
449
|
turn: runtime.turn(),
|
|
450
|
+
// P4 §1.1: governance-denied completions carry the requesting effect's identity.
|
|
451
|
+
...(effectId !== undefined ? { effect_id: effectId } : {}),
|
|
424
452
|
results: [{
|
|
425
453
|
call_id: requestAction.callId,
|
|
426
454
|
output: `permission denied: ${denyReason}`,
|
|
@@ -638,6 +666,18 @@ export class RuntimeRunner {
|
|
|
638
666
|
break;
|
|
639
667
|
if (action.kind === "call_provider") {
|
|
640
668
|
const providerEffectId = action.effectId;
|
|
669
|
+
// P4 §1.1: invocation identity is derived, never minted — the chain's FIRST effect_id.
|
|
670
|
+
// A provider_error commit armed `providerRetryPending`, so this effect CONTINUES the
|
|
671
|
+
// pending invocation; otherwise it opens a new one. The chain itself lives in the
|
|
672
|
+
// journal (each hop a resolution input → new effect); this is the SessionLog evidence
|
|
673
|
+
// projection of it.
|
|
674
|
+
if (!this.providerRetryPending || this.activeProviderInvocationId === undefined) {
|
|
675
|
+
this.activeProviderInvocationId = providerEffectId;
|
|
676
|
+
}
|
|
677
|
+
this.providerRetryPending = false;
|
|
678
|
+
const invocationId = this.activeProviderInvocationId;
|
|
679
|
+
// Host wall-clock, pure evidence (B7/DEC-2): never crosses into kernel input.
|
|
680
|
+
const attemptStartedAtMs = Date.now();
|
|
641
681
|
const finalToolCalls = [];
|
|
642
682
|
let finalText = "";
|
|
643
683
|
// I5: governance schema-level pre-filter — see Node runner for full rationale.
|
|
@@ -684,7 +724,7 @@ export class RuntimeRunner {
|
|
|
684
724
|
});
|
|
685
725
|
}
|
|
686
726
|
recordedMeasurements.set(providerPlan.fingerprint, promptMeasurement);
|
|
687
|
-
await this.opts.sessionLog.append(sessionId, { kind: "prompt_measured", turn: runtime.turn(), measurement: promptMeasurement });
|
|
727
|
+
await this.opts.sessionLog.append(sessionId, { kind: "prompt_measured", turn: runtime.turn(), measurement: promptMeasurement, effect_id: providerEffectId });
|
|
688
728
|
}
|
|
689
729
|
const reservedPromptTokens = (this.opts.promptBudget?.promptOverheadTokens ?? 0)
|
|
690
730
|
+ (this.opts.promptBudget?.outputReserveTokens ?? 0)
|
|
@@ -693,11 +733,29 @@ export class RuntimeRunner {
|
|
|
693
733
|
&& promptMeasurement.source.kind !== "heuristic"
|
|
694
734
|
&& promptMeasurement.inputTokens + reservedPromptTokens > this.opts.maxTokens;
|
|
695
735
|
if (context.budgetOverflow || measuredOverflow) {
|
|
736
|
+
// P4 §1.2: blocked BEFORE any transport — zero rungs, status rejected. The
|
|
737
|
+
// fingerprint still binds the would-be request to its prompt_measured record (G2).
|
|
738
|
+
await this.appendProviderAttempt(sessionId, {
|
|
739
|
+
effectId: providerEffectId,
|
|
740
|
+
attemptSeq: 1,
|
|
741
|
+
route: this.providerRoute,
|
|
742
|
+
requestFingerprint: providerPlan.fingerprint,
|
|
743
|
+
status: "rejected",
|
|
744
|
+
transportRungs: 0,
|
|
745
|
+
lastErrorClass: "context_overflow",
|
|
746
|
+
startedAtMs: attemptStartedAtMs,
|
|
747
|
+
finishedAtMs: Date.now(),
|
|
748
|
+
wireEvidence: {
|
|
749
|
+
protocol: this.providerRoute.protocol,
|
|
750
|
+
request_fingerprint: providerPlan.fingerprint,
|
|
751
|
+
},
|
|
752
|
+
});
|
|
696
753
|
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
697
754
|
kind: "provider_error", effect_id: providerEffectId,
|
|
698
755
|
message: "provider-visible prompt exceeds the configured context budget",
|
|
699
756
|
error_kind: "context_overflow", retryable: false,
|
|
700
757
|
});
|
|
758
|
+
this.providerRetryPending = action.kind === "call_provider";
|
|
701
759
|
continue;
|
|
702
760
|
}
|
|
703
761
|
const abortSignal = this.abortController?.signal;
|
|
@@ -741,6 +799,23 @@ export class RuntimeRunner {
|
|
|
741
799
|
else {
|
|
742
800
|
const descriptor = this.opts.provider.descriptor?.();
|
|
743
801
|
const providerError = classifyProviderError(descriptor?.provider ?? "unknown", err);
|
|
802
|
+
// P4 §1.2: the transport ladder is exhausted — one attempt record, error CLASS only
|
|
803
|
+
// (B1: never the raw vendor text). The single-shot stream path reports 1 rung.
|
|
804
|
+
await this.appendProviderAttempt(sessionId, {
|
|
805
|
+
effectId: providerEffectId,
|
|
806
|
+
attemptSeq: 1,
|
|
807
|
+
route: this.providerRoute,
|
|
808
|
+
requestFingerprint: providerPlan.fingerprint,
|
|
809
|
+
status: "transport_exhausted",
|
|
810
|
+
transportRungs: 1,
|
|
811
|
+
lastErrorClass: providerError.kind,
|
|
812
|
+
startedAtMs: attemptStartedAtMs,
|
|
813
|
+
finishedAtMs: Date.now(),
|
|
814
|
+
wireEvidence: {
|
|
815
|
+
protocol: this.providerRoute.protocol,
|
|
816
|
+
request_fingerprint: providerPlan.fingerprint,
|
|
817
|
+
},
|
|
818
|
+
});
|
|
744
819
|
// Reactive recovery is now a kernel decision. Forward the raw provider error and
|
|
745
820
|
// dispatch whatever the kernel returns: `call_provider` to retry with a freshly
|
|
746
821
|
// compacted context, or `done` to terminate with an honest `ContextOverflow`. The
|
|
@@ -752,6 +827,9 @@ export class RuntimeRunner {
|
|
|
752
827
|
message: providerError.message,
|
|
753
828
|
...providerErrorEventFields(providerError),
|
|
754
829
|
});
|
|
830
|
+
// P4 §1.1: a kernel-recovered retry CONTINUES this invocation (the journal holds the
|
|
831
|
+
// causation hop); a terminal closes it.
|
|
832
|
+
this.providerRetryPending = action.kind === "call_provider";
|
|
755
833
|
// Withholding (query.ts parity): surface the raw provider error only when the kernel
|
|
756
834
|
// could NOT recover (it returned a terminal). On a recovered retry (`call_provider`)
|
|
757
835
|
// the error stays hidden. `continue` re-enters the loop: a recovered turn persists its
|
|
@@ -765,6 +843,21 @@ export class RuntimeRunner {
|
|
|
765
843
|
}
|
|
766
844
|
// #2-B-ii: stream aborted (preempt/interrupt) via the break path — end the turn now.
|
|
767
845
|
if (abortSignal?.aborted) {
|
|
846
|
+
// P4 §1.2: host cancellation mid-stream — the attempt is evidence too.
|
|
847
|
+
await this.appendProviderAttempt(sessionId, {
|
|
848
|
+
effectId: providerEffectId,
|
|
849
|
+
attemptSeq: 1,
|
|
850
|
+
route: this.providerRoute,
|
|
851
|
+
requestFingerprint: providerPlan.fingerprint,
|
|
852
|
+
status: "aborted",
|
|
853
|
+
transportRungs: 1,
|
|
854
|
+
startedAtMs: attemptStartedAtMs,
|
|
855
|
+
finishedAtMs: Date.now(),
|
|
856
|
+
wireEvidence: {
|
|
857
|
+
protocol: this.providerRoute.protocol,
|
|
858
|
+
request_fingerprint: providerPlan.fingerprint,
|
|
859
|
+
},
|
|
860
|
+
});
|
|
768
861
|
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
769
862
|
kind: "cancel_operation",
|
|
770
863
|
reason: this.cancellationReason ?? "user",
|
|
@@ -778,22 +871,60 @@ export class RuntimeRunner {
|
|
|
778
871
|
toolCalls: finalToolCalls,
|
|
779
872
|
tokenCount: turnOutputTokens || turnTokens || undefined,
|
|
780
873
|
};
|
|
874
|
+
// P4 §2: assemble the measurement from the exact numbers that cross the boundary today
|
|
875
|
+
// (input/output turn counters + the cache split). An invalid frame degrades to no
|
|
876
|
+
// measurement (evidence never breaks a run); the settlement then falls back to the raw
|
|
877
|
+
// counts below.
|
|
878
|
+
const attemptUsage = (turnInputTokens > 0 || turnOutputTokens > 0)
|
|
879
|
+
? tryNormalizeProviderUsage({
|
|
880
|
+
inputTokens: turnInputTokens,
|
|
881
|
+
outputTokens: turnOutputTokens,
|
|
882
|
+
...(turnCacheReadTokens > 0 ? { cacheReadInputTokens: turnCacheReadTokens } : {}),
|
|
883
|
+
...(turnCacheCreationTokens > 0 ? { cacheCreationInputTokens: turnCacheCreationTokens } : {}),
|
|
884
|
+
})
|
|
885
|
+
: undefined;
|
|
886
|
+
const settlement = attemptUsage ? this.usageAccountingPolicy.settle(attemptUsage) : undefined;
|
|
781
887
|
const providerEvent = {
|
|
782
888
|
kind: "provider_result",
|
|
783
889
|
effect_id: providerEffectId,
|
|
784
890
|
message: messageToKernelMessage(assistantMessage),
|
|
785
|
-
|
|
786
|
-
|
|
891
|
+
// P4-S2: observed_* now comes from the pinned policy's settlement of the measurement.
|
|
892
|
+
// Under the default full-footprint policy these are provably the numbers the runner
|
|
893
|
+
// has always fed (inputTokens/outputTokens verbatim under the same >0 gates).
|
|
894
|
+
...(turnInputTokens > 0 ? { observed_input_tokens: settlement?.observed_input_tokens ?? turnInputTokens } : {}),
|
|
895
|
+
...(turnOutputTokens > 0 ? { observed_output_tokens: settlement?.observed_output_tokens ?? turnOutputTokens } : {}),
|
|
787
896
|
...(turnStopReason ? { stop_reason: turnStopReason } : {}),
|
|
788
897
|
};
|
|
789
|
-
|
|
898
|
+
// P4-S1: land the attempt evidence BEFORE the kernel resolution commits — the record
|
|
899
|
+
// describes the transport fact, which exists regardless of what the kernel decides next.
|
|
790
900
|
const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
|
|
901
|
+
const wireEvidence = {
|
|
902
|
+
protocol: this.providerRoute.protocol,
|
|
903
|
+
request_fingerprint: providerPlan.fingerprint,
|
|
904
|
+
...(providerReplay !== undefined ? { replay_state: providerReplay } : {}),
|
|
905
|
+
};
|
|
906
|
+
await this.appendProviderAttempt(sessionId, {
|
|
907
|
+
effectId: providerEffectId,
|
|
908
|
+
attemptSeq: 1,
|
|
909
|
+
route: this.providerRoute,
|
|
910
|
+
requestFingerprint: providerPlan.fingerprint,
|
|
911
|
+
status: "success",
|
|
912
|
+
transportRungs: 1,
|
|
913
|
+
startedAtMs: attemptStartedAtMs,
|
|
914
|
+
finishedAtMs: Date.now(),
|
|
915
|
+
...(attemptUsage !== undefined ? { usage: attemptUsage } : {}),
|
|
916
|
+
wireEvidence,
|
|
917
|
+
});
|
|
918
|
+
action = await this.commitKernelAction(runtime, this.pendingObservations, providerEvent);
|
|
791
919
|
await this.opts.sessionLog.append(sessionId, buildLlmCompletedEvent({
|
|
792
920
|
turn: runtime.turn(),
|
|
793
921
|
content: finalText,
|
|
794
922
|
tokenCount: turnOutputTokens || turnTokens || undefined,
|
|
795
923
|
toolCalls: finalToolCalls,
|
|
796
924
|
providerReplay,
|
|
925
|
+
effectId: providerEffectId,
|
|
926
|
+
invocationId,
|
|
927
|
+
wireEvidence,
|
|
797
928
|
}));
|
|
798
929
|
// P0-C: per-turn tool-gating telemetry. `activeSkill` reflects the skill in effect GOING INTO
|
|
799
930
|
// this turn; a `skill` call here only takes effect next turn — emit first, then advance.
|
|
@@ -823,7 +954,7 @@ export class RuntimeRunner {
|
|
|
823
954
|
}
|
|
824
955
|
}
|
|
825
956
|
else if (action.kind === "request_approval") {
|
|
826
|
-
const resolved = await this.resolveKernelSuspend(action.requests, runtime, sessionId);
|
|
957
|
+
const resolved = await this.resolveKernelSuspend(action.requests, runtime, sessionId, action.effectId);
|
|
827
958
|
for (const evt of resolved.events)
|
|
828
959
|
yield evt;
|
|
829
960
|
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
@@ -1076,6 +1207,8 @@ export class RuntimeRunner {
|
|
|
1076
1207
|
await this.opts.sessionLog.append(sessionId, {
|
|
1077
1208
|
kind: "tool_completed",
|
|
1078
1209
|
turn: runtime.turn(),
|
|
1210
|
+
// P4 §1.1: the completion carries the execute_tools effect's identity.
|
|
1211
|
+
effect_id: toolEffectId,
|
|
1079
1212
|
results: toolResults.map(r => ({
|
|
1080
1213
|
call_id: r.callId,
|
|
1081
1214
|
output: r.output,
|
|
@@ -1530,6 +1663,7 @@ export class RuntimeRunner {
|
|
|
1530
1663
|
goal: `workflow:${spec.nodes.length} nodes`,
|
|
1531
1664
|
criteria: [],
|
|
1532
1665
|
...(this.opts.agentId ? { agent_id: this.opts.agentId } : {}),
|
|
1666
|
+
route: this.providerRoute,
|
|
1533
1667
|
});
|
|
1534
1668
|
await this.initializeWorkflowKernel(sessionId, runId);
|
|
1535
1669
|
}
|
|
@@ -395,3 +395,11 @@ export declare class InMemorySessionLog implements SessionLog {
|
|
|
395
395
|
}>>;
|
|
396
396
|
latestSeq(sessionId: string): Promise<number>;
|
|
397
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* P4 §3 teeth, wasm mirror of the node/python persisted-record validator. The wasm SessionLog is
|
|
400
|
+
* in-memory only (no durable read path where validation would otherwise live), so the teeth are
|
|
401
|
+
* exported for hosts that bridge these events to durable storage — and for the conformance
|
|
402
|
+
* runner, which pins the rejection contract (`invalid_provider_attempt`) across all three
|
|
403
|
+
* JSON-projection SDKs. Same checks and message wording as node `assertCanonicalProviderAttempt`.
|
|
404
|
+
*/
|
|
405
|
+
export declare function assertCanonicalProviderAttemptRecord(event: Record<string, unknown>): void;
|
|
@@ -99,3 +99,75 @@ export class InMemorySessionLog {
|
|
|
99
99
|
return (this.seqCounters.get(sessionId) ?? 0) - 1;
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
+
const PROVIDER_ATTEMPT_KEYS = new Set([
|
|
103
|
+
"kind", "effect_id", "attempt_seq", "route", "request_fingerprint", "status", "transport_rungs",
|
|
104
|
+
"last_error_class", "started_at_ms", "finished_at_ms", "usage", "wire_evidence", "accounting_policy_id",
|
|
105
|
+
]);
|
|
106
|
+
const PROVIDER_ATTEMPT_STATUSES = new Set(["success", "transport_exhausted", "aborted", "rejected"]);
|
|
107
|
+
const WIRE_EVIDENCE_KEYS = new Set(["protocol", "request_fingerprint", "response_id", "raw_usage", "replay_state"]);
|
|
108
|
+
function assertCanonicalRoute(value) {
|
|
109
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
110
|
+
throw new Error("route must be an object");
|
|
111
|
+
const route = value;
|
|
112
|
+
for (const field of ["routeId", "provider", "protocol", "model", "adapterVersion", "capabilitiesRef"]) {
|
|
113
|
+
if (typeof route[field] !== "string" || route[field].length === 0) {
|
|
114
|
+
throw new Error(`route ${field} must be a non-empty string`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!route.endpoint || typeof route.endpoint !== "object" || Array.isArray(route.endpoint)) {
|
|
118
|
+
throw new Error("route endpoint must be an object");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function assertCanonicalWireEvidence(value) {
|
|
122
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
123
|
+
throw new Error("wire evidence must be an object");
|
|
124
|
+
const evidence = value;
|
|
125
|
+
for (const key of Object.keys(evidence))
|
|
126
|
+
if (!WIRE_EVIDENCE_KEYS.has(key))
|
|
127
|
+
throw new Error(`wire evidence has unknown field ${key}`);
|
|
128
|
+
if (typeof evidence.protocol !== "string" || evidence.protocol.length === 0)
|
|
129
|
+
throw new Error("wire evidence protocol is required");
|
|
130
|
+
// G2: the fingerprint is mandatory non-empty — it is what binds this evidence to a request plan.
|
|
131
|
+
if (typeof evidence.request_fingerprint !== "string" || evidence.request_fingerprint.length === 0) {
|
|
132
|
+
throw new Error("wire evidence request_fingerprint is required");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* P4 §3 teeth, wasm mirror of the node/python persisted-record validator. The wasm SessionLog is
|
|
137
|
+
* in-memory only (no durable read path where validation would otherwise live), so the teeth are
|
|
138
|
+
* exported for hosts that bridge these events to durable storage — and for the conformance
|
|
139
|
+
* runner, which pins the rejection contract (`invalid_provider_attempt`) across all three
|
|
140
|
+
* JSON-projection SDKs. Same checks and message wording as node `assertCanonicalProviderAttempt`.
|
|
141
|
+
*/
|
|
142
|
+
export function assertCanonicalProviderAttemptRecord(event) {
|
|
143
|
+
for (const key of Object.keys(event))
|
|
144
|
+
if (!PROVIDER_ATTEMPT_KEYS.has(key))
|
|
145
|
+
throw new Error(`provider_attempt has unknown field ${key}`);
|
|
146
|
+
if (typeof event.effect_id !== "string" || event.effect_id.length === 0)
|
|
147
|
+
throw new Error("provider_attempt effect_id is required");
|
|
148
|
+
if (!Number.isInteger(event.attempt_seq) || event.attempt_seq < 1)
|
|
149
|
+
throw new Error("provider_attempt attempt_seq must be a positive integer");
|
|
150
|
+
assertCanonicalRoute(event.route);
|
|
151
|
+
if (typeof event.request_fingerprint !== "string" || event.request_fingerprint.length === 0) {
|
|
152
|
+
throw new Error("provider_attempt request_fingerprint is required");
|
|
153
|
+
}
|
|
154
|
+
if (typeof event.status !== "string" || !PROVIDER_ATTEMPT_STATUSES.has(event.status)) {
|
|
155
|
+
throw new Error("provider_attempt status must be success|transport_exhausted|aborted|rejected");
|
|
156
|
+
}
|
|
157
|
+
if (!Number.isInteger(event.transport_rungs) || event.transport_rungs < 0) {
|
|
158
|
+
throw new Error("provider_attempt transport_rungs must be a non-negative integer");
|
|
159
|
+
}
|
|
160
|
+
if (event.last_error_class !== undefined && typeof event.last_error_class !== "string") {
|
|
161
|
+
throw new Error("provider_attempt last_error_class must be a string");
|
|
162
|
+
}
|
|
163
|
+
for (const field of ["started_at_ms", "finished_at_ms"]) {
|
|
164
|
+
if (typeof event[field] !== "number" || !Number.isFinite(event[field])) {
|
|
165
|
+
throw new Error(`provider_attempt ${field} must be a finite number`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (event.wire_evidence !== undefined)
|
|
169
|
+
assertCanonicalWireEvidence(event.wire_evidence);
|
|
170
|
+
if (event.accounting_policy_id !== undefined && typeof event.accounting_policy_id !== "string") {
|
|
171
|
+
throw new Error("provider_attempt accounting_policy_id must be a string");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Message, ProviderReplay, ToolCall } from "../types.js";
|
|
1
|
+
import type { Message, ProviderReplay, ProviderWireEvidence, ToolCall } from "../types.js";
|
|
2
2
|
import type { SessionEvent } from "./session-log.js";
|
|
3
3
|
import type { WorkflowNodeStatus } from "./types/agent.js";
|
|
4
4
|
export { REPLAY_CONTENT_MAX_BYTES as RECOVERY_CONTENT_MAX_BYTES } from "./replay-sanitize.js";
|
|
@@ -27,6 +27,9 @@ export declare function buildLlmCompletedEvent(input: {
|
|
|
27
27
|
tokenCount?: number;
|
|
28
28
|
toolCalls: ToolCall[];
|
|
29
29
|
providerReplay?: ProviderReplay;
|
|
30
|
+
effectId?: string;
|
|
31
|
+
invocationId?: string;
|
|
32
|
+
wireEvidence?: ProviderWireEvidence;
|
|
30
33
|
}): Extract<SessionEvent, {
|
|
31
34
|
kind: "llm_completed";
|
|
32
35
|
}>;
|
|
@@ -21,6 +21,11 @@ export function normalizeLlmCompleted(event, maxBytes) {
|
|
|
21
21
|
tool_calls: toolCalls,
|
|
22
22
|
token_count: event.token_count ?? estimateTokenCount(content),
|
|
23
23
|
...(providerReplay ? { provider_replay: providerReplay } : {}),
|
|
24
|
+
// P4 §3: the evidence-plane fields ride along verbatim — recovery never reads them
|
|
25
|
+
// (SessionLog is evidence, not authority), so normalize must neither synthesize nor drop them.
|
|
26
|
+
...(event.effect_id !== undefined ? { effect_id: event.effect_id } : {}),
|
|
27
|
+
...(event.invocation_id !== undefined ? { invocation_id: event.invocation_id } : {}),
|
|
28
|
+
...(event.wire_evidence !== undefined ? { wire_evidence: event.wire_evidence } : {}),
|
|
24
29
|
};
|
|
25
30
|
}
|
|
26
31
|
export function repairEventsForRecovery(events, maxBytes) {
|
|
@@ -38,6 +43,9 @@ export function buildLlmCompletedEvent(input) {
|
|
|
38
43
|
tool_calls: input.toolCalls ?? [],
|
|
39
44
|
token_count: input.tokenCount,
|
|
40
45
|
provider_replay: input.providerReplay,
|
|
46
|
+
...(input.effectId !== undefined ? { effect_id: input.effectId } : {}),
|
|
47
|
+
...(input.invocationId !== undefined ? { invocation_id: input.invocationId } : {}),
|
|
48
|
+
...(input.wireEvidence !== undefined ? { wire_evidence: input.wireEvidence } : {}),
|
|
41
49
|
});
|
|
42
50
|
}
|
|
43
51
|
export function buildRunTerminalEvent(input) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepstrike/wasm",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.64",
|
|
4
4
|
"description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"test:canonical-binding": "wasm-pack build ../crates/deepstrike-wasm --target nodejs --dev --out-dir ../../wasm/pkg-node && node tests/canonical-binding.node.cjs && node tests/golden-fixtures-sweep.node.cjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@deepstrike/wasm-kernel": "0.2.
|
|
20
|
+
"@deepstrike/wasm-kernel": "0.2.64"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/jest": "^30.0.0",
|