@deepstrike/wasm 0.2.61 → 0.2.63

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/LICENSE ADDED
@@ -0,0 +1,106 @@
1
+ DeepStrike License (Dual License)
2
+ Version 1.0 — 2026-09-01
3
+
4
+ Copyright (c) 2025-2026 DeepStrike Contributors
5
+ Project: https://github.com/kongusen/deepstrike
6
+
7
+ ======================================================================
8
+ 中文摘要(便于理解,不具有法律效力;以下英文条款为准)
9
+ ======================================================================
10
+
11
+ 本软件采用双授权模式:
12
+
13
+ 1. 个人,以及上一财年总营收低于 1,000,000 美元的组织(含其关联方),
14
+ 可按 MIT 条款免费使用本软件(见第 2 节),包括使用、复制、修改、
15
+ 合并、发布、分发、再授权及销售的权利。
16
+ 2. 上一财年总营收达到或超过 1,000,000 美元的组织(含其关联方),
17
+ 在使用本软件之前(包括内部使用、基于本软件开发的项目、以及对外
18
+ 分发此类产品或服务)须向作者获取商业授权(见第 3 节)。
19
+ 获取方式:发送邮件至 wanghaishan0210@gmail.com,或通过
20
+ https://github.com/kongusen/deepstrike 提交 Issue / Discussion
21
+ 联系作者。出于评估目的的试用不超过 30 天除外。
22
+ 3. 当组织的年营收增长至达到或超过该阈值时,自该时点起第 2 节的免费
23
+ 授权终止,须获取商业授权后方可继续使用。
24
+ 4. v0.2.62 及之前已经以 MIT 协议发布的版本继续适用 MIT 协议,不受
25
+ 本协议影响。本协议仅适用于随其一同分发的版本。
26
+
27
+ ======================================================================
28
+ TERMS AND CONDITIONS
29
+ ======================================================================
30
+
31
+ 1. DEFINITIONS
32
+
33
+ "Software" means the DeepStrike software and associated documentation
34
+ files distributed by the Licensor, including all copies and substantial
35
+ portions thereof.
36
+
37
+ "Licensor" means the copyright holders of the Software (the DeepStrike
38
+ Contributors), represented by the project maintainer at
39
+ https://github.com/kongusen/deepstrike.
40
+
41
+ "You" (or "Licensee") means the individual or legal entity exercising
42
+ permissions granted by this License, including, where that entity is an
43
+ organization, all entities that control, are controlled by, or are under
44
+ common control with that entity ("Affiliates"). "Control" means ownership
45
+ of more than fifty percent (50%) of the equity or voting interests, or
46
+ the power to direct management and policies.
47
+
48
+ "Annual Revenue" means the total gross revenue of You and Your Affiliates
49
+ for the most recently completed fiscal year, expressed in US dollars or
50
+ converted into US dollars at prevailing exchange rates.
51
+
52
+ 2. FREE LICENSE FOR INDIVIDUALS AND SMALL ORGANIZATIONS
53
+
54
+ If You are an individual, or a legal entity whose Annual Revenue is less
55
+ than one million US dollars (USD 1,000,000), the Licensor hereby grants
56
+ You, free of charge, permission to deal in the Software without
57
+ restriction, including without limitation the rights to use, copy, modify,
58
+ merge, publish, distribute, sublicense, and/or sell copies of the
59
+ Software, and to permit persons to whom the Software is furnished to do
60
+ so, subject to the following conditions:
61
+
62
+ (a) The above copyright notice and this License shall be included in all
63
+ copies or substantial portions of the Software.
64
+
65
+ (b) If Your Annual Revenue reaches or exceeds USD 1,000,000, the grant in
66
+ this Section 2 terminates for You, and Section 3 applies from that
67
+ point on.
68
+
69
+ 3. COMMERCIAL LICENSE REQUIRED (ANNUAL REVENUE >= USD 1,000,000)
70
+
71
+ If Your Annual Revenue equals or exceeds one million US dollars
72
+ (USD 1,000,000), You must obtain a commercial license from the Licensor
73
+ before using the Software. This applies to every form of use, including
74
+ internal use, use within products or services developed based on the
75
+ Software, and distribution or provision of such products or services to
76
+ third parties.
77
+
78
+ Exception: You may use the Software without a commercial license solely
79
+ for evaluation purposes, for a period of up to thirty (30) days.
80
+
81
+ To obtain a commercial license, contact the Licensor at
82
+ wanghaishan0210@gmail.com, or via the project repository at
83
+ https://github.com/kongusen/deepstrike (open an issue or discussion).
84
+ Commercial terms, including fees, are set by individual agreement with
85
+ the Licensor.
86
+
87
+ Any use of the Software requiring a commercial license under this
88
+ Section 3 without one is unlicensed use and constitutes copyright
89
+ infringement.
90
+
91
+ 4. PRIOR VERSIONS
92
+
93
+ Versions of the Software released before this License took effect (up to
94
+ and including version 0.2.62) were released under the MIT License and
95
+ remain available under the terms of the MIT License. This License applies
96
+ only to versions of the Software distributed together with it.
97
+
98
+ 5. NO WARRANTY
99
+
100
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
101
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
102
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
103
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
104
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
105
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
106
+ DEALINGS IN THE SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, 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, 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
+ export { CANONICAL_CONTENT_PARTS_PREFIX, encodeCanonicalContentParts, decodeCanonicalContentParts, } from "./runtime/kernel-step.js";
4
5
  export type { ReplayProviderOpts, Criterion, Verdict, VerdictDetail, JudgeArgs, } from "./runtime/index.js";
5
- export type { NativeOsProfile, OsProfileId, MemoryPolicy, MemoryWriteRateLimit, ResourceQuota, RuntimeOptions, PromptBudget, SchedulerPolicy, SignalPolicy, SessionEvent, SessionLog, RunContext, ExecutionPlane, KernelEventCategory, KernelPrimitive, } from "./runtime/index.js";
6
+ export type { NativeOsProfile, OsProfileId, MemoryPolicy, MemoryWriteRateLimit, ResourceQuota, RuntimeOptions, PromptBudget, SchedulerPolicy, SignalPolicy, SessionEvent, SessionEventKind, SessionLog, RunContext, ExecutionPlane, KernelEventCategory, KernelPrimitive, } from "./runtime/index.js";
6
7
  export { primitiveForCategory, primitiveForKind } from "./runtime/index.js";
7
8
  export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
8
9
  export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
@@ -40,12 +41,14 @@ export { ScheduledPrompt } from "./signals/index.js";
40
41
  export type { RuntimeSignal, SignalSource } from "./signals/index.js";
41
42
  export { PermissionManager, PermissionMode } from "./safety/index.js";
42
43
  export { createProviderRequestPlan, createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, normalizeProviderUsage, priceProviderUsage, recordPromptMeasurement } from "./providers/request-plan.js";
43
- export type { CostObservation, NormalizedProviderUsage, PricingSnapshot, ProviderRequestEndpoint, ProviderRequestPlan, ProviderUsage, RecordedPromptMeasurement } from "./providers/request-plan.js";
44
+ export type { CostObservation, NormalizedProviderUsage, PricingSnapshot, ProviderRequestEndpoint, ProviderRequestPlan, ProviderUsage, RecordedPromptMeasurement, ResolvedProviderRoute } from "./providers/request-plan.js";
45
+ export type { ProviderAttempt, ProviderAttemptRecord, ProviderAttemptStatus, ModelInvocation, InvocationOutcome, UsageSettlement, UsageAccountingPolicy, } from "./runtime/execution-evidence.js";
46
+ export { FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY, providerAttemptToRecord, tryNormalizeProviderUsage } from "./runtime/execution-evidence.js";
44
47
  export { decodeCanonicalStopReason, normalizeProviderStopReason } from "./providers/stop-reason.js";
45
48
  export type { CanonicalStopReason } from "./providers/stop-reason.js";
46
49
  export { ContentPolicyError, contentDispositionFor, requireContentDisposition } from "./providers/content-policy.js";
47
50
  export type { ContentDisposition, ContentPlacement, InputModality } from "./providers/content-policy.js";
48
51
  export type { PermissionDecision } from "./safety/index.js";
49
- export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, ToolAuditFailedEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, EntropySample, EntropySampleEvent, EntropyAlertEvent, EntropyWatchOptions, LLMProvider, CacheBreakpointStrategy, } from "./types.js";
52
+ export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, ToolAuditFailedEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, EntropySample, EntropySampleEvent, EntropyAlertEvent, EntropyWatchOptions, LLMProvider, CacheBreakpointStrategy, ProviderWireEvidence, ProviderTransportTelemetry, } from "./types.js";
50
53
  export { DurableContentError, decodeDurableContent, decodeDurableToolResult, encodeDurableContent, encodeDurableToolResult, toolOutputBlocksToDurable, durableBlocksToToolOutput } from "./runtime/durable-content.js";
51
54
  export type { DurableContent, DurableContentBlock, DurableSource, DurableToolResult } from "./runtime/durable-content.js";
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
- export { RuntimeRunner, collectText, runAgent, runFanout, InMemorySessionLog, 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, 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
+ // ── content-parts-v1 registered encoding (F14/B5; byte-pinned by sdk-conformance) ──
5
+ export { CANONICAL_CONTENT_PARTS_PREFIX, encodeCanonicalContentParts, decodeCanonicalContentParts, } from "./runtime/kernel-step.js";
4
6
  export { primitiveForCategory, primitiveForKind } from "./runtime/index.js";
5
7
  export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
6
8
  export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
@@ -23,6 +25,7 @@ export { AttemptLoop, RuntimeAttemptBody, VerdictFnJudge, LlmEvalJudge, HybridJu
23
25
  export { ScheduledPrompt } from "./signals/index.js";
24
26
  export { PermissionManager, PermissionMode } from "./safety/index.js";
25
27
  export { createProviderRequestPlan, createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, normalizeProviderUsage, priceProviderUsage, recordPromptMeasurement } from "./providers/request-plan.js";
28
+ export { FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY, providerAttemptToRecord, tryNormalizeProviderUsage } from "./runtime/execution-evidence.js";
26
29
  export { decodeCanonicalStopReason, normalizeProviderStopReason } from "./providers/stop-reason.js";
27
30
  export { ContentPolicyError, contentDispositionFor, requireContentDisposition } from "./providers/content-policy.js";
28
31
  export { DurableContentError, decodeDurableContent, decodeDurableToolResult, encodeDurableContent, encodeDurableToolResult, toolOutputBlocksToDurable, durableBlocksToToolOutput } from "./runtime/durable-content.js";
@@ -36,6 +36,16 @@ export interface ProviderUsage {
36
36
  cacheCreationInputTokens?: number;
37
37
  reasoningTokens?: number;
38
38
  }
39
+ /** P4 §1.3 mirror of the node ResolvedProviderRoute (content-addressed route evidence). */
40
+ export interface ResolvedProviderRoute {
41
+ routeId: string;
42
+ provider: string;
43
+ protocol: string;
44
+ model: string;
45
+ endpoint: ProviderRequestEndpoint;
46
+ adapterVersion: string;
47
+ capabilitiesRef: string;
48
+ }
39
49
  export interface NormalizedProviderUsage extends ProviderUsage {
40
50
  uncachedInputTokens: number;
41
51
  }
@@ -37,8 +37,8 @@ export interface CanonicalTransition {
37
37
  replayed: boolean;
38
38
  }
39
39
  export declare function canonicalUnsupportedEffectResolution(effectId: string, effectKind: string): CanonicalKernelInput;
40
- /** The only ABI-v3 planned-step → Node host-action projection. */
41
- export declare function canonicalActionFromPlannedStep(plannedStep: CanonicalPlannedStep): KernelRunnerAction | null;
40
+ /** Adapt the additive core CurrentProjection JSON into the existing WASM action surface. */
41
+ export declare function canonicalActionFromProjectionJson(raw: string): KernelRunnerAction | null;
42
42
  export declare class CanonicalKernelRejectedError extends Error {
43
43
  readonly fault: Record<string, unknown>;
44
44
  constructor(faultJson: string);
@@ -27,240 +27,186 @@ export function canonicalUnsupportedEffectResolution(effectId, effectKind) {
27
27
  },
28
28
  };
29
29
  }
30
- /** The only ABI-v3 planned-step → Node host-action projection. */
31
- export function canonicalActionFromPlannedStep(plannedStep) {
32
- if (plannedStep.disposition.kind === "terminal") {
33
- const terminal = plannedStep.disposition.terminal;
34
- const usage = asObject(terminal.usage);
35
- let termination = String(terminal.kind ?? "failed");
36
- let turnsUsed = Number(usage.turns ?? 0);
37
- if (terminal.kind === "agent") {
38
- const result = asObject(terminal.result);
39
- termination = String(result.termination ?? "completed");
40
- turnsUsed = Number(result.turns_used ?? turnsUsed);
41
- const finalMessage = asObject(result.final_message);
42
- const pace = asObject(result.pace_decision);
43
- if (Object.keys(finalMessage).length > 0) {
44
- return {
45
- kind: "done",
46
- effectId: "",
47
- result: {
48
- termination,
49
- turnsUsed,
50
- totalTokensUsed: totalUsageTokens(terminal),
51
- finalMessage: {
52
- role: String(finalMessage.role ?? "assistant"),
53
- content: String(finalMessage.content ?? ""),
54
- toolCalls: (Array.isArray(finalMessage.tool_calls) ? finalMessage.tool_calls : [])
55
- .map(value => {
56
- const call = asObject(value);
57
- return {
58
- id: String(call.call_id ?? ""),
59
- name: String(call.name ?? ""),
60
- arguments: JSON.stringify(call.arguments ?? {}),
61
- };
62
- }),
63
- },
64
- ...(Object.keys(pace).length > 0
65
- ? {
66
- paceDecision: {
67
- action: String(pace.action ?? "stop"),
68
- ...(pace.delay_ms !== undefined ? { delayMs: Number(pace.delay_ms) } : {}),
69
- reason: String(pace.reason ?? ""),
70
- ...(pace.coerced_from ? { coercedFrom: String(pace.coerced_from) } : {}),
71
- },
72
- }
73
- : {}),
74
- },
75
- };
76
- }
77
- }
78
- else if (terminal.kind === "workflow") {
79
- const outcome = asObject(terminal.outcome);
80
- termination = String(outcome.status ?? "completed");
81
- }
82
- else if (terminal.kind === "cancelled") {
83
- termination = String(terminal.reason ?? "cancelled");
84
- }
85
- else if (terminal.kind === "failed") {
86
- const failure = asObject(terminal.failure);
87
- termination = failure.code === "provider_recovery_exhausted"
88
- ? "context_overflow"
89
- : "error";
90
- }
30
+ function canonicalDoneFromTerminal(terminal) {
31
+ const usage = asObject(terminal.usage);
32
+ let termination = String(terminal.kind ?? "failed");
33
+ let turnsUsed = Number(usage.turns ?? 0);
34
+ if (terminal.kind === "agent") {
35
+ const result = asObject(terminal.result);
36
+ termination = String(result.termination ?? "completed");
37
+ turnsUsed = Number(result.turns_used ?? turnsUsed);
38
+ const finalMessage = asObject(result.final_message);
39
+ const pace = asObject(result.pace_decision);
91
40
  return {
92
- kind: "done",
93
- effectId: "",
41
+ kind: "done", effectId: "",
94
42
  result: {
95
- termination,
96
- turnsUsed,
97
- totalTokensUsed: totalUsageTokens(terminal),
43
+ termination, turnsUsed, totalTokensUsed: totalUsageTokens(terminal),
44
+ ...(Object.keys(finalMessage).length > 0 ? { finalMessage: {
45
+ role: String(finalMessage.role ?? "assistant"),
46
+ content: String(finalMessage.content ?? ""),
47
+ toolCalls: (Array.isArray(finalMessage.tool_calls) ? finalMessage.tool_calls : []).map(value => {
48
+ const call = asObject(value);
49
+ return { id: String(call.call_id ?? ""), name: String(call.name ?? ""), arguments: JSON.stringify(call.arguments ?? {}) };
50
+ }),
51
+ } } : {}),
52
+ ...(Object.keys(pace).length > 0 ? { paceDecision: {
53
+ action: String(pace.action ?? "stop"),
54
+ ...(pace.delay_ms !== undefined ? { delayMs: Number(pace.delay_ms) } : {}),
55
+ reason: String(pace.reason ?? ""),
56
+ ...(pace.coerced_from ? { coercedFrom: String(pace.coerced_from) } : {}),
57
+ } } : {}),
98
58
  },
99
59
  };
100
60
  }
101
- const published = plannedStep.disposition.effects ?? [];
102
- if (published.length === 0)
61
+ if (terminal.kind === "workflow")
62
+ termination = String(asObject(terminal.outcome).status ?? "completed");
63
+ if (terminal.kind === "cancelled")
64
+ termination = String(terminal.reason ?? "cancelled");
65
+ if (terminal.kind === "failed")
66
+ termination = asObject(terminal.failure).code === "provider_recovery_exhausted" ? "context_overflow" : "error";
67
+ return { kind: "done", effectId: "", result: { termination, turnsUsed, totalTokensUsed: totalUsageTokens(terminal) } };
68
+ }
69
+ /** Adapt the additive core CurrentProjection JSON into the existing WASM action surface. */
70
+ export function canonicalActionFromProjectionJson(raw) {
71
+ const projection = asObject(JSON.parse(raw));
72
+ const state = String(projection.state ?? "idle");
73
+ if (state === "idle")
103
74
  return null;
104
- if (published.length !== 1) {
105
- throw new Error(`WASM runner expects one canonical effect at a time, received ${published.length}`);
75
+ if (state === "terminal") {
76
+ return canonicalDoneFromTerminal(asObject(projection.action));
106
77
  }
107
- const envelope = asObject(published[0]);
108
- const effectId = String(envelope.effect_id ?? "");
109
- const effect = asObject(envelope.effect);
110
- if (!effectId)
111
- throw new Error("canonical effect is missing effect_id");
112
- switch (effect.kind) {
113
- case "call_provider":
114
- return {
115
- kind: "call_provider",
116
- effectId,
117
- context: renderedContextToSdk(asObject(effect.context)),
118
- tools: (Array.isArray(effect.tools) ? effect.tools : []).map(raw => {
119
- const tool = asObject(raw);
120
- return {
121
- name: String(tool.name ?? ""),
122
- description: String(tool.description ?? ""),
123
- parameters: JSON.stringify(tool.parameters ?? {}),
124
- };
125
- }),
126
- };
127
- case "execute_tools":
128
- return {
129
- kind: "execute_tool",
130
- effectId,
131
- calls: (Array.isArray(effect.calls) ? effect.calls : []).map(raw => {
132
- const call = asObject(raw);
133
- return {
134
- id: String(call.call_id ?? ""),
135
- name: String(call.name ?? ""),
136
- arguments: JSON.stringify(call.arguments ?? {}),
137
- };
138
- }),
139
- };
140
- case "request_approval":
141
- return {
142
- kind: "request_approval",
143
- effectId,
144
- requests: (Array.isArray(effect.requests) ? effect.requests : []).map(raw => {
145
- const request = asObject(raw);
146
- return {
147
- callId: String(request.call_id ?? ""),
148
- tool: String(request.tool_name ?? ""),
149
- arguments: JSON.stringify(request.arguments ?? {}),
150
- reason: String(request.reason ?? ""),
151
- };
152
- }),
153
- };
154
- case "spawn_tasks":
155
- return {
156
- kind: "spawn_workflow",
157
- effectId,
158
- nodes: (Array.isArray(effect.tasks) ? effect.tasks : []).map(raw => {
159
- const task = asObject(raw);
160
- const spec = asObject(task.spec);
161
- return {
162
- agent_id: String(task.task_id ?? ""),
163
- task_id: String(task.task_id ?? ""),
164
- attempt_id: String(task.attempt_id ?? ""),
165
- launch_token: String(task.launch_token ?? ""),
166
- node_id: String(task.node_id ?? ""),
167
- goal: String(spec.goal ?? ""),
168
- role: String(spec.role ?? "custom"),
169
- isolation: String(spec.isolation ?? "shared"),
170
- context_inheritance: String(spec.context_inheritance ?? "none"),
171
- ...(spec.metadata && typeof spec.metadata === "object"
172
- ? asObject(spec.metadata)
173
- : {}),
174
- };
175
- }),
176
- ...(effect.budget ? { budget: asObject(effect.budget) } : {}),
177
- };
178
- case "preempt_tasks": {
179
- const attempts = (Array.isArray(effect.attempts) ? effect.attempts : []).map(raw => {
180
- const attempt = asObject(raw);
78
+ const action = asObject(projection.action);
79
+ const payload = asObject(action.payload);
80
+ const effectId = String(action.effect_id ?? "");
81
+ if (action.kind === "query_memory") {
82
+ return {
83
+ kind: "query_memory",
84
+ effectId,
85
+ query: asObject(payload.query),
86
+ requestedK: Number(payload.requested_k ?? 0),
87
+ };
88
+ }
89
+ if (action.kind === "execute_tools") {
90
+ return {
91
+ kind: "execute_tool",
92
+ effectId,
93
+ calls: (Array.isArray(payload.calls) ? payload.calls : []).map(raw => {
94
+ const call = asObject(raw);
181
95
  return {
182
- task_id: String(attempt.task_id ?? ""),
183
- attempt_id: String(attempt.attempt_id ?? ""),
96
+ id: String(call.call_id ?? ""),
97
+ name: String(call.name ?? ""),
98
+ arguments: JSON.stringify(call.arguments ?? {}),
184
99
  };
185
- });
186
- return {
187
- kind: "preempt_sub_agents",
188
- effectId,
189
- attempts,
190
- agentIds: attempts.map(attempt => attempt.task_id),
191
- reason: String(effect.reason ?? ""),
192
- };
193
- }
194
- case "persist_memory":
195
- return {
196
- kind: "persist_memory",
197
- effectId,
198
- memory: asObject(effect.memory),
199
- };
200
- case "query_memory":
201
- return {
202
- kind: "query_memory",
203
- effectId,
204
- query: asObject(effect.query),
205
- requestedK: Number(effect.requested_k ?? 0),
206
- };
207
- case "archive_page_out": {
208
- const payload = asObject(effect.payload);
209
- let archived = [];
210
- try {
211
- const decoded = JSON.parse(String(payload.content ?? ""));
212
- if (Array.isArray(decoded)) {
213
- archived = decoded.map(value => kernelMessageToSdk(asObject(value)));
214
- }
215
- }
216
- catch {
217
- // Persistence still uses the opaque body and digest. Only optional presentation-side
218
- // summarization is skipped if the archived message batch cannot be decoded.
219
- }
220
- const compressed = (plannedStep.observations ?? [])
221
- .find(observation => observation.kind === "compressed");
222
- const pressureAction = compressed ? String(compressed.action ?? "") : "";
223
- return {
224
- kind: "archive_page_out",
225
- effectId,
226
- handleId: String(effect.handle_id ?? ""),
227
- payload,
228
- archived,
229
- ...(pressureAction ? { action: pressureAction } : {}),
230
- ...(compressed?.summary ? { summary: String(compressed.summary) } : {}),
231
- ...(pressureAction
232
- ? {
233
- tier: ["context_collapse", "auto_compact"].includes(pressureAction)
234
- ? "semantic"
235
- : "durable",
236
- }
237
- : {}),
238
- };
100
+ }),
101
+ };
102
+ }
103
+ if (action.kind === "call_provider") {
104
+ const context = asObject(payload.context);
105
+ return {
106
+ kind: "call_provider",
107
+ effectId,
108
+ context: renderedContextToSdk(context),
109
+ tools: (Array.isArray(payload.tools) ? payload.tools : []).map(raw => {
110
+ const tool = asObject(raw);
111
+ return {
112
+ name: String(tool.name ?? ""),
113
+ description: String(tool.description ?? ""),
114
+ parameters: JSON.stringify(tool.parameters ?? {}),
115
+ };
116
+ }),
117
+ };
118
+ }
119
+ if (action.kind === "request_approval") {
120
+ return {
121
+ kind: "request_approval",
122
+ effectId,
123
+ requests: (Array.isArray(payload.requests) ? payload.requests : []).map(raw => {
124
+ const request = asObject(raw);
125
+ return {
126
+ callId: String(request.call_id ?? ""),
127
+ tool: String(request.tool_name ?? ""),
128
+ arguments: JSON.stringify(request.arguments ?? {}),
129
+ reason: String(request.reason ?? ""),
130
+ };
131
+ }),
132
+ };
133
+ }
134
+ if (action.kind === "load_payload") {
135
+ return {
136
+ kind: "load_payload",
137
+ effectId,
138
+ handleId: String(payload.handle_id ?? ""),
139
+ payloadRef: String(payload.payload_ref ?? ""),
140
+ };
141
+ }
142
+ if (action.kind === "evaluate_milestone") {
143
+ const request = asObject(payload.request);
144
+ return {
145
+ kind: "evaluate_milestone",
146
+ effectId,
147
+ phaseId: String(request.phase_id ?? ""),
148
+ criteria: [],
149
+ requiredEvidence: [],
150
+ };
151
+ }
152
+ if (action.kind === "spawn_tasks") {
153
+ return {
154
+ kind: "spawn_workflow",
155
+ effectId,
156
+ nodes: (Array.isArray(payload.tasks) ? payload.tasks : []).map(raw => {
157
+ const task = asObject(raw);
158
+ const spec = asObject(task.spec);
159
+ return {
160
+ agent_id: String(task.task_id ?? ""), task_id: String(task.task_id ?? ""),
161
+ attempt_id: String(task.attempt_id ?? ""), launch_token: String(task.launch_token ?? ""),
162
+ node_id: String(task.node_id ?? ""), goal: String(spec.goal ?? ""),
163
+ role: String(spec.role ?? "custom"), isolation: String(spec.isolation ?? "shared"),
164
+ context_inheritance: String(spec.context_inheritance ?? "none"),
165
+ ...(spec.metadata && typeof spec.metadata === "object" ? asObject(spec.metadata) : {}),
166
+ };
167
+ }),
168
+ ...(payload.budget ? { budget: asObject(payload.budget) } : {}),
169
+ };
170
+ }
171
+ if (action.kind === "preempt_tasks") {
172
+ const attempts = (Array.isArray(payload.attempts) ? payload.attempts : []).map(raw => {
173
+ const attempt = asObject(raw);
174
+ return { task_id: String(attempt.task_id ?? ""), attempt_id: String(attempt.attempt_id ?? "") };
175
+ });
176
+ return { kind: "preempt_sub_agents", effectId, attempts, agentIds: attempts.map(a => a.task_id), reason: String(payload.reason ?? "") };
177
+ }
178
+ if (action.kind === "persist_memory") {
179
+ return { kind: "persist_memory", effectId, memory: asObject(payload.memory) };
180
+ }
181
+ if (action.kind === "archive_page_out") {
182
+ const archivePayload = asObject(payload.payload);
183
+ let archived = [];
184
+ try {
185
+ const decoded = JSON.parse(String(archivePayload.content ?? ""));
186
+ if (Array.isArray(decoded))
187
+ archived = decoded.map(value => kernelMessageToSdk(asObject(value)));
239
188
  }
240
- case "load_payload":
241
- return {
242
- kind: "load_payload",
243
- effectId,
244
- handleId: String(effect.handle_id ?? ""),
245
- payloadRef: String(effect.payload_ref ?? ""),
246
- };
247
- case "evaluate_milestone": {
248
- const request = asObject(effect.request);
249
- return {
250
- kind: "evaluate_milestone",
251
- effectId,
252
- phaseId: String(request.phase_id ?? ""),
253
- criteria: [],
254
- requiredEvidence: [],
255
- };
189
+ catch {
190
+ // The opaque archive payload remains authoritative even when presentation decoding fails.
256
191
  }
257
- default:
258
- return {
259
- kind: "unsupported_effect",
260
- effectId,
261
- effectKind: String(effect.kind),
262
- };
192
+ return {
193
+ kind: "archive_page_out",
194
+ effectId,
195
+ handleId: String(payload.handle_id ?? ""),
196
+ payload: {
197
+ content: String(archivePayload.content ?? ""),
198
+ digest: String(archivePayload.digest ?? ""),
199
+ original_size: String(archivePayload.original_size ?? "0"),
200
+ ...(archivePayload.preview ? { preview: String(archivePayload.preview) } : {}),
201
+ },
202
+ archived,
203
+ };
263
204
  }
205
+ return {
206
+ kind: "unsupported_effect",
207
+ effectId,
208
+ effectKind: String(action.kind ?? ""),
209
+ };
264
210
  }
265
211
  export class CanonicalKernelRejectedError extends Error {
266
212
  fault;
@@ -1165,6 +1111,16 @@ export class CanonicalRunnerRuntime {
1165
1111
  throw new Error("canonical observation is missing kind");
1166
1112
  this.hostObservations.push({ ...raw, kind });
1167
1113
  }
1114
+ // §7.11 · a committed step that publishes effects is a fact worth recording in the
1115
+ // host event log: the journal stores only a digest of the step, so this manifest is
1116
+ // what makes the published effect ids + kinds recoverable post-hoc without replaying.
1117
+ const published = JSON.parse(this.host.kernel.publishedEffectsManifestJson(JSON.stringify(transition.plannedStep)));
1118
+ if (published.length > 0) {
1119
+ this.hostObservations.push({
1120
+ kind: "step_published_effects",
1121
+ effects: published,
1122
+ });
1123
+ }
1168
1124
  if (transition.checkpointAdvice) {
1169
1125
  this.hostObservations.push({
1170
1126
  kind: "checkpoint_advised",
@@ -1178,7 +1134,7 @@ export class CanonicalRunnerRuntime {
1178
1134
  });
1179
1135
  }
1180
1136
  }
1181
- this.lastAction = canonicalActionFromPlannedStep(transition.plannedStep);
1137
+ this.lastAction = canonicalActionFromProjectionJson(this.host.kernel.projectPlannedStepJson(JSON.stringify(transition.plannedStep)));
1182
1138
  }
1183
1139
  if (this.lastAction?.kind !== "unsupported_effect")
1184
1140
  return this.lastAction;
@@ -1186,16 +1142,7 @@ export class CanonicalRunnerRuntime {
1186
1142
  }
1187
1143
  }
1188
1144
  currentAction() {
1189
- const terminal = this.host.kernel.terminalJson();
1190
- if (terminal) {
1191
- return canonicalActionFromPlannedStep({
1192
- disposition: { kind: "terminal", terminal: JSON.parse(terminal) },
1193
- });
1194
- }
1195
- const effects = this.pendingEffects();
1196
- return canonicalActionFromPlannedStep({
1197
- disposition: { kind: "effects", effects },
1198
- });
1145
+ return canonicalActionFromProjectionJson(this.host.kernel.currentProjectionJson());
1199
1146
  }
1200
1147
  pendingEffects() {
1201
1148
  return JSON.parse(this.host.kernel.pendingEffectsJson());
@@ -0,0 +1,118 @@
1
+ /**
2
+ * P4 (0.2.64 Execution Evidence Plane): wasm mirror of the host-side object model connecting
3
+ * kernel-minted effects to real provider execution — ModelInvocation / ProviderAttempt /
4
+ * ResolvedProviderRoute / UsageAccountingPolicy. Everything here is L2 host evidence (B7):
5
+ * it lands in SessionLog for cross-verification against the journal (C6/C8) and is NEVER
6
+ * fed back as kernel input (B4/DEC-2 discipline: wall-clock and wire facts stay host-side).
7
+ */
8
+ import type { ProviderWireEvidence } from "../types.js";
9
+ import type { NormalizedProviderUsage, ResolvedProviderRoute } from "../providers/request-plan.js";
10
+ /** Canonical stop-reason vocabulary already carried on the wire usage frame (types.ts). */
11
+ export type CanonicalStopReason = "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | "content_filtered";
12
+ /**
13
+ * P4 §1.1: one logical model call = the fact-connected chain of CallProvider effects the
14
+ * kernel walked to obtain one turn of model output. Derived identity, zero minting:
15
+ * `invocationId` IS the first effect's effect_id. Authority = journal; the SessionLog
16
+ * projection (`llm_completed.invocation_id`) is evidence only.
17
+ */
18
+ export interface ModelInvocation {
19
+ invocationId: string;
20
+ turn: number;
21
+ /** Every effect_id on the chain, in order. Length 1 = first attempt succeeded. */
22
+ effectChain: string[];
23
+ outcome?: InvocationOutcome;
24
+ }
25
+ /** P4 §1.4: the invocation's terminal projection. */
26
+ export interface InvocationOutcome {
27
+ invocationId: string;
28
+ /** The effect the kernel adopted as the outcome (the successful one). */
29
+ selectedEffectId: string;
30
+ stopReason?: CanonicalStopReason;
31
+ /** Absent on a failed chain (nothing settled). */
32
+ settlement?: UsageSettlement;
33
+ }
34
+ export type ProviderAttemptStatus = "success" | "transport_exhausted" | "aborted" | "rejected";
35
+ /**
36
+ * P4 §1.2: one effect's execution against one route, one physical attempt. The kernel-minted
37
+ * `effectId` is the primary key (H7 — no parallel id minting). Transport-ladder rungs are
38
+ * summarized as a count plus the final error class; rung-level evidence belongs to adapter
39
+ * debug logs, not SessionLog.
40
+ */
41
+ export interface ProviderAttempt {
42
+ effectId: string;
43
+ /** Failover sequence within one effect execution (1-based). Always 1 today (P4 §0.2). */
44
+ attemptSeq: number;
45
+ route: ResolvedProviderRoute;
46
+ /** → ProviderRequestPlan.fingerprint (G2). */
47
+ requestFingerprint: string;
48
+ status: ProviderAttemptStatus;
49
+ transportRungs: number;
50
+ /** classifyProviderError's class, never the raw vendor text (B1 spirit). */
51
+ lastErrorClass?: string;
52
+ /** Host wall-clock, pure evidence, never kernel input (DEC-2 discipline). */
53
+ startedAtMs: number;
54
+ finishedAtMs: number;
55
+ /** Full measurement fields (P4 §2); only the settlement crosses the kernel boundary (B4). */
56
+ usage?: NormalizedProviderUsage;
57
+ wireEvidence?: ProviderWireEvidence;
58
+ }
59
+ /**
60
+ * The SessionLog wire payload of a ProviderAttempt (P4 §3): the §1.2 fields flattened into
61
+ * the event, snake_case per SessionLog convention. Nested objects keep their native shape
62
+ * (same convention as `prompt_measured.measurement`).
63
+ */
64
+ export interface ProviderAttemptRecord {
65
+ effect_id: string;
66
+ attempt_seq: number;
67
+ route: ResolvedProviderRoute;
68
+ request_fingerprint: string;
69
+ status: ProviderAttemptStatus;
70
+ transport_rungs: number;
71
+ last_error_class?: string;
72
+ started_at_ms: number;
73
+ finished_at_ms: number;
74
+ usage?: NormalizedProviderUsage;
75
+ wire_evidence?: ProviderWireEvidence;
76
+ /** P4 §2.1: the accounting policy this attempt's settlement was/will be derived with —
77
+ * pinned on the attempt so settlement is deterministically recomputable from
78
+ * (measurement, policy_id). */
79
+ accounting_policy_id?: string;
80
+ }
81
+ export declare function providerAttemptToRecord(attempt: ProviderAttempt, accountingPolicyId?: string): ProviderAttemptRecord;
82
+ /**
83
+ * P4 §2: the only two numbers that cross the kernel boundary (B4). Field names match the
84
+ * existing ResolveEffect wire shape — this is what the runner already feeds the kernel as
85
+ * `observed_input_tokens` / `observed_output_tokens`.
86
+ */
87
+ export interface UsageSettlement {
88
+ observed_input_tokens: number;
89
+ observed_output_tokens: number;
90
+ }
91
+ /**
92
+ * P4 §2.1: the named, pinnable, replayable policy turning a measurement into a settlement.
93
+ * `settle` must be a pure function of the measurement — given (usage, policyId) any auditor
94
+ * recomputes the identical settlement.
95
+ */
96
+ export interface UsageAccountingPolicy {
97
+ policyId: string;
98
+ settle(usage: NormalizedProviderUsage): UsageSettlement;
99
+ }
100
+ /**
101
+ * The default policy = today's implicit runner behavior exactly (full input footprint + full
102
+ * output footprint — the two numbers the runner has always fed `observed_*`). P4 changes no
103
+ * default numbers; it only makes the conversion a named object. The date stamp is the
104
+ * policy's identity: any future semantics change MUST ship under a new policyId.
105
+ */
106
+ export declare const FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY: UsageAccountingPolicy;
107
+ /**
108
+ * Defensive measurement assembly for the attempt evidence path: an invalid frame (cache
109
+ * subsets exceeding input, etc.) degrades to NO measurement instead of breaking the run —
110
+ * evidence is never worth a run failure, and the settlement falls back to the raw counts.
111
+ */
112
+ export declare function tryNormalizeProviderUsage(usage: {
113
+ inputTokens: number;
114
+ outputTokens: number;
115
+ cacheReadInputTokens?: number;
116
+ cacheCreationInputTokens?: number;
117
+ reasoningTokens?: number;
118
+ }): NormalizedProviderUsage | undefined;
@@ -0,0 +1,45 @@
1
+ import { normalizeProviderUsage } from "../providers/request-plan.js";
2
+ export function providerAttemptToRecord(attempt, accountingPolicyId) {
3
+ return {
4
+ effect_id: attempt.effectId,
5
+ attempt_seq: attempt.attemptSeq,
6
+ route: attempt.route,
7
+ request_fingerprint: attempt.requestFingerprint,
8
+ status: attempt.status,
9
+ transport_rungs: attempt.transportRungs,
10
+ ...(attempt.lastErrorClass !== undefined ? { last_error_class: attempt.lastErrorClass } : {}),
11
+ started_at_ms: attempt.startedAtMs,
12
+ finished_at_ms: attempt.finishedAtMs,
13
+ ...(attempt.usage !== undefined ? { usage: attempt.usage } : {}),
14
+ ...(attempt.wireEvidence !== undefined ? { wire_evidence: attempt.wireEvidence } : {}),
15
+ ...(accountingPolicyId !== undefined ? { accounting_policy_id: accountingPolicyId } : {}),
16
+ };
17
+ }
18
+ /**
19
+ * The default policy = today's implicit runner behavior exactly (full input footprint + full
20
+ * output footprint — the two numbers the runner has always fed `observed_*`). P4 changes no
21
+ * default numbers; it only makes the conversion a named object. The date stamp is the
22
+ * policy's identity: any future semantics change MUST ship under a new policyId.
23
+ */
24
+ export const FULL_FOOTPRINT_USAGE_ACCOUNTING_POLICY = {
25
+ policyId: "deepstrike.full-footprint@2026-09-15",
26
+ settle(usage) {
27
+ return {
28
+ observed_input_tokens: usage.inputTokens,
29
+ observed_output_tokens: usage.outputTokens,
30
+ };
31
+ },
32
+ };
33
+ /**
34
+ * Defensive measurement assembly for the attempt evidence path: an invalid frame (cache
35
+ * subsets exceeding input, etc.) degrades to NO measurement instead of breaking the run —
36
+ * evidence is never worth a run failure, and the settlement falls back to the raw counts.
37
+ */
38
+ export function tryNormalizeProviderUsage(usage) {
39
+ try {
40
+ return normalizeProviderUsage(usage);
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
@@ -1,5 +1,6 @@
1
- export type { SessionEvent, SessionLog } from "./session-log.js";
1
+ export type { SessionEvent, SessionEventKind, SessionLog } from "./session-log.js";
2
2
  export { InMemorySessionLog } from "./session-log.js";
3
+ export { SESSION_EVENT_KINDS } from "./session-log.js";
3
4
  export { DriverKernelJournal, InMemoryJournalDriver, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, } from "./kernel-journal.js";
4
5
  export type { CheckpointCandidate, InstalledCheckpoint, JournalAppendReceipt, JournalEntry, JournalHead, JournalPruneReceipt, JournalRecordInput, JournalStorageDriver, KernelJournal, } from "./kernel-journal.js";
5
6
  export * from "./context-policy.js";
@@ -9,7 +10,7 @@ export type { MemoryPolicy, MemoryWriteRateLimit, OperationCancellationReason, P
9
10
  export { RuntimeRunner, collectText } from "./runner.js";
10
11
  export { MemoryPayloadDriver, PayloadStore } from "./payload-store.js";
11
12
  export type { PayloadStorageDriver, PayloadStoreConfig } from "./payload-store.js";
12
- export { CanonicalKernelHost, CanonicalKernelRejectedError, CanonicalKernelRebuildRequiredError, CanonicalRunnerRuntime, canonicalActionFromPlannedStep, sha256, } from "./canonical-kernel-step.js";
13
+ export { CanonicalKernelHost, CanonicalKernelRejectedError, CanonicalKernelRebuildRequiredError, CanonicalRunnerRuntime, sha256, } from "./canonical-kernel-step.js";
13
14
  export type { CanonicalKernelInput, CanonicalPlannedStep, CanonicalRunnerRuntimeOptions, CanonicalTransition, CanonicalTransitionOptions, } from "./canonical-kernel-step.js";
14
15
  export { runAgent, runFanout } from "./facade.js";
15
16
  export type { RunAgentOptions, RunFanoutOptions } from "./facade.js";
@@ -1,11 +1,13 @@
1
1
  export { InMemorySessionLog } from "./session-log.js";
2
+ // Registered session-event vocabulary (F9/S3; manifest-pinned by sdk-conformance, P7-S4)
3
+ export { SESSION_EVENT_KINDS } from "./session-log.js";
2
4
  // Durable transaction capability (Canonical Kernel ABI §9.1)
3
5
  export { DriverKernelJournal, InMemoryJournalDriver, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, } from "./kernel-journal.js";
4
6
  export * from "./context-policy.js";
5
7
  export { LocalExecutionPlane } from "./execution-plane.js";
6
8
  export { RuntimeRunner, collectText } from "./runner.js";
7
9
  export { MemoryPayloadDriver, PayloadStore } from "./payload-store.js";
8
- export { CanonicalKernelHost, CanonicalKernelRejectedError, CanonicalKernelRebuildRequiredError, CanonicalRunnerRuntime, canonicalActionFromPlannedStep, sha256, } from "./canonical-kernel-step.js";
10
+ export { CanonicalKernelHost, CanonicalKernelRejectedError, CanonicalKernelRebuildRequiredError, CanonicalRunnerRuntime, sha256, } from "./canonical-kernel-step.js";
9
11
  export { runAgent, runFanout } from "./facade.js";
10
12
  export { builtinReducers, resolveReducer } from "./reducers.js";
11
13
  export { getKernel } from "./kernel.js";
@@ -22,6 +22,11 @@ export declare const CANONICAL_CONTENT_PARTS_PREFIX = "[[deepstrike-content-part
22
22
  /**
23
23
  * Browser/worker-safe transport for typed content. `btoa` and `atob` operate on
24
24
  * binary strings, so explicitly bridge UTF-8 bytes rather than assuming Latin-1.
25
+ *
26
+ * Byte contract (content-parts-v1, F14/B5): compact JSON with literal UTF-8, insertion key
27
+ * order, **base64url alphabet, no padding** — identical bytes to the Node and Python SDKs.
28
+ * Decode stays lenient (both alphabets, optional padding) so payloads written before the
29
+ * url-alphabet alignment remain readable.
25
30
  */
26
31
  export declare function encodeCanonicalContentParts(parts: unknown[]): string;
27
32
  export declare function decodeCanonicalContentParts(content: string): Array<Record<string, unknown>> | undefined;
@@ -84,11 +89,7 @@ export type KernelRunnerAction = {
84
89
  } | {
85
90
  kind: "archive_page_out";
86
91
  effectId: string;
87
- turn?: number;
88
- action?: string;
89
- summary?: string;
90
92
  archived: Message[];
91
- tier?: string;
92
93
  handleId?: string;
93
94
  payload?: {
94
95
  content: string;
@@ -204,7 +205,17 @@ export interface KernelObservation {
204
205
  rollbacks_in_window?: number;
205
206
  window_turns?: number;
206
207
  threshold?: number;
208
+ effects?: Array<{
209
+ effect_id: string;
210
+ kind: string;
211
+ }>;
207
212
  }
213
+ /** Presentation/policy facts for archive actions are sourced from committed observations. */
214
+ export declare function archivePresentationFromObservations(observations: readonly KernelObservation[]): {
215
+ action?: string;
216
+ summary?: string;
217
+ tier?: "semantic" | "durable";
218
+ };
208
219
  export declare function toolSchemaToKernel(schema: ToolSchema): Record<string, unknown>;
209
220
  export declare function skillMetadataToKernel(skill: SkillMetadata): Record<string, unknown>;
210
221
  export declare function messageToKernelMessage(message: Message): Record<string, unknown>;
@@ -2,19 +2,28 @@ export const CANONICAL_CONTENT_PARTS_PREFIX = "[[deepstrike-content-parts]]";
2
2
  /**
3
3
  * Browser/worker-safe transport for typed content. `btoa` and `atob` operate on
4
4
  * binary strings, so explicitly bridge UTF-8 bytes rather than assuming Latin-1.
5
+ *
6
+ * Byte contract (content-parts-v1, F14/B5): compact JSON with literal UTF-8, insertion key
7
+ * order, **base64url alphabet, no padding** — identical bytes to the Node and Python SDKs.
8
+ * Decode stays lenient (both alphabets, optional padding) so payloads written before the
9
+ * url-alphabet alignment remain readable.
5
10
  */
6
11
  export function encodeCanonicalContentParts(parts) {
7
12
  const bytes = new TextEncoder().encode(JSON.stringify(parts));
8
13
  let binary = "";
9
14
  for (const byte of bytes)
10
15
  binary += String.fromCharCode(byte);
11
- return `${CANONICAL_CONTENT_PARTS_PREFIX}${btoa(binary)}`;
16
+ const payload = btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
17
+ return `${CANONICAL_CONTENT_PARTS_PREFIX}${payload}`;
12
18
  }
13
19
  export function decodeCanonicalContentParts(content) {
14
20
  if (!content.startsWith(CANONICAL_CONTENT_PARTS_PREFIX))
15
21
  return undefined;
16
22
  try {
17
- const binary = atob(content.slice(CANONICAL_CONTENT_PARTS_PREFIX.length));
23
+ const raw = content.slice(CANONICAL_CONTENT_PARTS_PREFIX.length);
24
+ const standard = raw.replaceAll("-", "+").replaceAll("_", "/");
25
+ const padded = standard + "=".repeat((4 - (standard.length % 4)) % 4);
26
+ const binary = atob(padded);
18
27
  const bytes = Uint8Array.from(binary, character => character.charCodeAt(0));
19
28
  const decoded = JSON.parse(new TextDecoder().decode(bytes));
20
29
  return Array.isArray(decoded)
@@ -25,6 +34,18 @@ export function decodeCanonicalContentParts(content) {
25
34
  return undefined;
26
35
  }
27
36
  }
37
+ /** Presentation/policy facts for archive actions are sourced from committed observations. */
38
+ export function archivePresentationFromObservations(observations) {
39
+ const compressed = [...observations].reverse().find(observation => observation.kind === "compressed");
40
+ const action = compressed?.action;
41
+ if (action !== "snip_compact" && action !== "micro_compact" && action !== "context_collapse" && action !== "auto_compact")
42
+ return {};
43
+ return {
44
+ action,
45
+ ...(compressed?.summary ? { summary: compressed.summary } : {}),
46
+ tier: action === "context_collapse" || action === "auto_compact" ? "semantic" : "durable",
47
+ };
48
+ }
28
49
  function tryParseJson(s) {
29
50
  try {
30
51
  return JSON.parse(s);
@@ -8,7 +8,7 @@ import { sanitizeReplayText } from "./replay-sanitize.js";
8
8
  import { decodeDurableContent, decodeDurableToolResult, durableBlocksToToolOutput, toolOutputBlocksToDurable } from "./durable-content.js";
9
9
  import { formatToolError } from "../tools/errors.js";
10
10
  import { buildLlmCompletedEvent, buildRunTerminalEvent, buildWorkflowNodeCompletedEvent, buildWorkflowNodesSubmittedEvent, } from "./session-repair.js";
11
- import { messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
11
+ import { messageToKernelMessage, archivePresentationFromObservations, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
12
12
  import { agentRunSpecToKernel, MILESTONE_UNVERIFIED_REASON, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowBudgetNote, workflowNodeSpecToKernel, workflowNodeOutcomeFromKernel, workflowNodeStatusFromTermination, workflowNodeToManifest, workflowNodeToSpec, workflowSpecToKernel, } from "./types/agent.js";
13
13
  import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
14
14
  import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
@@ -899,8 +899,8 @@ export class RuntimeRunner {
899
899
  error = formatToolError(cause);
900
900
  }
901
901
  const archived = action.archived;
902
- const archiveAction = compressionAction(action.action) ?? "auto_compact";
903
- const archiveTier = action.tier;
902
+ const archiveAction = archiveMeta.action ?? "auto_compact";
903
+ const archiveTier = archiveMeta.tier;
904
904
  if (!error)
905
905
  this.activePageOutArchive = undefined;
906
906
  action = await this.commitKernelAction(runtime, this.pendingObservations, {
@@ -1767,7 +1767,11 @@ export class RuntimeRunner {
1767
1767
  const compressedSeq = await this.opts.sessionLog.append(sessionId, event);
1768
1768
  if (event.kind === "compressed") {
1769
1769
  if ((obs.archived_count ?? 0) > 0) {
1770
- this.pendingPageOutArchives.push({ archiveStart: nextArchiveStart, compressedSeq });
1770
+ this.pendingPageOutArchives.push({
1771
+ archiveStart: nextArchiveStart,
1772
+ compressedSeq,
1773
+ ...archivePresentationFromObservations([obs]),
1774
+ });
1771
1775
  }
1772
1776
  nextArchiveStart = compressedSeq + 1;
1773
1777
  }
@@ -1,8 +1,8 @@
1
- import type { ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
1
+ import type { ProviderReplay, ProviderWireEvidence, ToolCall, ToolErrorKind } from "../types.js";
2
2
  import type { MemoryRecall, MemoryScope } from "../memory/index.js";
3
3
  import type { KernelPrimitive } from "./kernel-event-log.js";
4
4
  import type { KernelJournal } from "./kernel-journal.js";
5
- import type { RecordedPromptMeasurement } from "../providers/request-plan.js";
5
+ import type { NormalizedProviderUsage, RecordedPromptMeasurement, ResolvedProviderRoute } from "../providers/request-plan.js";
6
6
  export type RollbackReason = {
7
7
  kind: "fatal_tool_error";
8
8
  tool_name: string;
@@ -22,6 +22,25 @@ export type RollbackReason = {
22
22
  kind: "malformed_replay";
23
23
  reason: string;
24
24
  };
25
+ /**
26
+ * P4 §3 mirror: the SessionLog wire payload of a ProviderAttempt (P4 §1.2 fields, flattened,
27
+ * snake_case). Nested objects keep their native shape. The kernel-minted effect_id joins this
28
+ * host evidence to the journal effect chain 1:1 (C6); step_seq NEVER enters SessionLog (P2 §4).
29
+ */
30
+ export interface ProviderAttemptRecord {
31
+ effect_id: string;
32
+ attempt_seq: number;
33
+ route: ResolvedProviderRoute;
34
+ request_fingerprint: string;
35
+ status: "success" | "transport_exhausted" | "aborted" | "rejected";
36
+ transport_rungs: number;
37
+ last_error_class?: string;
38
+ started_at_ms: number;
39
+ finished_at_ms: number;
40
+ usage?: NormalizedProviderUsage;
41
+ wire_evidence?: ProviderWireEvidence;
42
+ accounting_policy_id?: string;
43
+ }
25
44
  export type SessionEvent = {
26
45
  kind: "run_started";
27
46
  run_id: string;
@@ -30,6 +49,7 @@ export type SessionEvent = {
30
49
  agent_id?: string;
31
50
  system_prompt?: string;
32
51
  attachments?: import("../types.js").ContentPart[];
52
+ route?: ResolvedProviderRoute;
33
53
  } | {
34
54
  kind: "llm_completed";
35
55
  turn: number;
@@ -37,11 +57,17 @@ export type SessionEvent = {
37
57
  token_count?: number;
38
58
  tool_calls: ToolCall[];
39
59
  provider_replay?: ProviderReplay;
60
+ effect_id?: string;
61
+ invocation_id?: string;
62
+ wire_evidence?: ProviderWireEvidence;
40
63
  } | {
41
64
  kind: "prompt_measured";
42
65
  turn: number;
43
66
  measurement: RecordedPromptMeasurement;
44
- } | {
67
+ effect_id?: string;
68
+ } | ({
69
+ kind: "provider_attempt";
70
+ } & ProviderAttemptRecord) | {
45
71
  kind: "tool_requested";
46
72
  turn: number;
47
73
  calls: ToolCall[];
@@ -59,6 +85,7 @@ export type SessionEvent = {
59
85
  blocks: Record<string, unknown>[];
60
86
  };
61
87
  }>;
88
+ effect_id?: string;
62
89
  } | {
63
90
  kind: "tool_argument_repaired";
64
91
  turn: number;
@@ -98,6 +125,18 @@ export type SessionEvent = {
98
125
  tier_hint?: string;
99
126
  message_count?: number;
100
127
  archive_ref?: string;
128
+ } | {
129
+ kind: "semantic_archive_pending";
130
+ effect_id: string;
131
+ action?: string;
132
+ } | {
133
+ kind: "semantic_archive_completed";
134
+ effect_id: string;
135
+ record_id: string;
136
+ } | {
137
+ kind: "semantic_archive_failed";
138
+ effect_id: string;
139
+ error: string;
101
140
  } | {
102
141
  kind: "page_in";
103
142
  turn: number;
@@ -228,6 +267,17 @@ export type SessionEvent = {
228
267
  turn: number;
229
268
  record_id: string;
230
269
  error: string;
270
+ } | {
271
+ kind: "memory_write_failed";
272
+ turn: number;
273
+ record_id: string;
274
+ error: string;
275
+ } | {
276
+ kind: "memory_query_failed";
277
+ turn: number;
278
+ scope: MemoryScope;
279
+ query: string;
280
+ error: string;
231
281
  } | {
232
282
  kind: "memory_retrieval_result";
233
283
  hits: MemoryRecall[];
@@ -278,7 +328,39 @@ export type SessionEvent = {
278
328
  kind: "summary_upgraded";
279
329
  compressed_seq: number;
280
330
  summary: string;
331
+ } | {
332
+ kind: "group_member_joined";
333
+ session_id: string;
334
+ role?: string;
335
+ member_kind?: "peer" | "vehicle";
336
+ } | {
337
+ kind: "group_budget_charged";
338
+ tokens: number;
339
+ subagents: number;
340
+ rounds?: number;
341
+ } | {
342
+ kind: "round_started";
343
+ /** 1-based round number within the loop. */
344
+ round: number;
345
+ goal: string;
346
+ } | {
347
+ kind: "round_paced";
348
+ round: number;
349
+ action: "continue" | "sleep" | "stop";
350
+ delay_ms?: number;
351
+ /** Absolute wake time for sleep — lets a stateless host re-arm from the log alone. */
352
+ wake_at_ms?: number;
353
+ reason: string;
354
+ coerced_from?: string;
281
355
  };
356
+ export type SessionEventKind = SessionEvent["kind"];
357
+ /**
358
+ * The registered session-event vocabulary (F9 / S3, P7-S4). This list must equal the Node SDK's
359
+ * `SESSION_EVENT_KINDS` — the cross-SDK manifest fixture
360
+ * `tests/fixtures/sdk-conformance/canonical/session-event-vocabulary.json` pins both, and any
361
+ * same-commit desync turns conformance red. Declared in `SessionEvent` union order.
362
+ */
363
+ export declare const SESSION_EVENT_KINDS: readonly ["run_started", "llm_completed", "prompt_measured", "provider_attempt", "tool_requested", "tool_completed", "tool_argument_repaired", "tool_denied", "permission_requested", "permission_resolved", "compressed", "page_out", "semantic_archive_pending", "semantic_archive_completed", "semantic_archive_failed", "page_in", "rollbacked", "capability_changed", "context_renewed", "suspended", "resumed", "tool_gated", "signal_delivery_disposed", "budget_exceeded", "budget_usage_reported", "operation_cancelled", "milestone_advanced", "milestone_blocked", "checkpoint_taken", "entropy_sample", "entropy_alert", "agent_process_changed", "memory_written", "memory_queried", "memory_validation_failed", "memory_write_failed", "memory_query_failed", "memory_retrieval_result", "workflow_node_completed", "workflow_nodes_submitted", "workflow_batch_spawned", "workflow_completed", "kernel_observation", "run_terminal", "summary_upgraded", "group_member_joined", "group_budget_charged", "round_started", "round_paced"];
282
364
  /**
283
365
  * The business-projection log (spec §9.2): run started/terminal, stream events, observations,
284
366
  * provider/tool presentation, and audit metadata. Canonical durable records live exclusively in
@@ -1,5 +1,64 @@
1
1
  import { primitiveForKind } from "./kernel-event-log.js";
2
2
  import { InMemoryKernelJournal } from "./kernel-journal.js";
3
+ /**
4
+ * The registered session-event vocabulary (F9 / S3, P7-S4). This list must equal the Node SDK's
5
+ * `SESSION_EVENT_KINDS` — the cross-SDK manifest fixture
6
+ * `tests/fixtures/sdk-conformance/canonical/session-event-vocabulary.json` pins both, and any
7
+ * same-commit desync turns conformance red. Declared in `SessionEvent` union order.
8
+ */
9
+ export const SESSION_EVENT_KINDS = [
10
+ "run_started",
11
+ "llm_completed",
12
+ "prompt_measured",
13
+ "provider_attempt",
14
+ "tool_requested",
15
+ "tool_completed",
16
+ "tool_argument_repaired",
17
+ "tool_denied",
18
+ "permission_requested",
19
+ "permission_resolved",
20
+ "compressed",
21
+ "page_out",
22
+ "semantic_archive_pending",
23
+ "semantic_archive_completed",
24
+ "semantic_archive_failed",
25
+ "page_in",
26
+ "rollbacked",
27
+ "capability_changed",
28
+ "context_renewed",
29
+ "suspended",
30
+ "resumed",
31
+ "tool_gated",
32
+ "signal_delivery_disposed",
33
+ "budget_exceeded",
34
+ "budget_usage_reported",
35
+ "operation_cancelled",
36
+ "milestone_advanced",
37
+ "milestone_blocked",
38
+ "checkpoint_taken",
39
+ "entropy_sample",
40
+ "entropy_alert",
41
+ "agent_process_changed",
42
+ "memory_written",
43
+ "memory_queried",
44
+ "memory_validation_failed",
45
+ "memory_write_failed",
46
+ "memory_query_failed",
47
+ "memory_retrieval_result",
48
+ "workflow_node_completed",
49
+ "workflow_nodes_submitted",
50
+ "workflow_batch_spawned",
51
+ "workflow_completed",
52
+ "kernel_observation",
53
+ "run_terminal",
54
+ "summary_upgraded",
55
+ "group_member_joined",
56
+ "group_budget_charged",
57
+ "round_started",
58
+ "round_paced",
59
+ ];
60
+ const _vocabularyCoversUnion = true;
61
+ void _vocabularyCoversUnion;
3
62
  /**
4
63
  * **Single-isolate dev/test implementation** of both capabilities (spec §9.4: one class may
5
64
  * implement several capabilities; the *interfaces* stay separate). Its `KernelJournal` half is
package/dist/types.d.ts CHANGED
@@ -273,6 +273,21 @@ export interface ProviderReplay {
273
273
  native_message?: unknown;
274
274
  tool_calls?: unknown[];
275
275
  }
276
+ /** P3 §3.3 (D1) mirror of the node ProviderWireEvidence — SessionLog wire evidence bundle. */
277
+ export interface ProviderWireEvidence {
278
+ protocol: ProviderProtocol;
279
+ /** → ProviderRequestPlan.fingerprint. Mandatory non-empty (G2). */
280
+ request_fingerprint: string;
281
+ response_id?: string;
282
+ /** BoundedJson semantics: producers truncate to ≤4KB. */
283
+ raw_usage?: unknown;
284
+ replay_state?: ProviderReplay;
285
+ }
286
+ /** P4 §1.2 mirror: host-observed transport facts for one provider execution. */
287
+ export interface ProviderTransportTelemetry {
288
+ rungs: number;
289
+ responseId?: string;
290
+ }
276
291
  export interface LLMProvider {
277
292
  createRunState?(): ProviderRunState;
278
293
  runtimePolicy?(): {
@@ -291,6 +306,8 @@ export interface LLMProvider {
291
306
  };
292
307
  peekProviderReplay?(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
293
308
  seedProviderReplay?(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
309
+ /** P4-S1 mirror: transport facts of the most recent execution (host evidence only, B7). */
310
+ peekTransportTelemetry?(): ProviderTransportTelemetry | undefined;
294
311
  countTokens?(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<PromptMeasurement>;
295
312
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
296
313
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@deepstrike/wasm",
3
- "version": "0.2.61",
3
+ "version": "0.2.63",
4
4
  "description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
5
+ "license": "SEE LICENSE IN LICENSE",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
@@ -13,10 +14,10 @@
13
14
  "build:wasm": "wasm-pack build ../crates/deepstrike-wasm --target bundler --out-dir ../../wasm/pkg",
14
15
  "build": "tsc",
15
16
  "test": "node --experimental-vm-modules node_modules/.bin/jest",
16
- "test:canonical-binding": "wasm-pack build ../crates/deepstrike-wasm --target nodejs --dev --out-dir ../../wasm/pkg-node && node tests/canonical-binding.node.cjs"
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"
17
18
  },
18
19
  "dependencies": {
19
- "@deepstrike/wasm-kernel": "0.2.61"
20
+ "@deepstrike/wasm-kernel": "0.2.63"
20
21
  },
21
22
  "devDependencies": {
22
23
  "@types/jest": "^30.0.0",