@deepstrike/wasm 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -2
- package/dist/governance.d.ts +32 -0
- package/dist/governance.js +18 -0
- package/dist/index.d.ts +2 -2
- package/dist/providers/anthropic.js +20 -3
- package/dist/providers/base.js +11 -1
- package/dist/runtime/execution-plane.d.ts +6 -3
- package/dist/runtime/execution-plane.js +54 -23
- package/dist/runtime/kernel-event-log.d.ts +26 -0
- package/dist/runtime/kernel-event-log.js +212 -0
- package/dist/runtime/kernel-step.d.ts +21 -1
- package/dist/runtime/kernel-step.js +9 -0
- package/dist/runtime/large-result-spool.d.ts +49 -0
- package/dist/runtime/large-result-spool.js +137 -0
- package/dist/runtime/os-profile.d.ts +7 -0
- package/dist/runtime/os-profile.js +6 -0
- package/dist/runtime/os-snapshot.d.ts +31 -0
- package/dist/runtime/os-snapshot.js +108 -0
- package/dist/runtime/runner.d.ts +20 -5
- package/dist/runtime/runner.js +305 -147
- package/dist/runtime/session-log.d.ts +110 -3
- package/dist/runtime/session-log.js +10 -2
- package/dist/runtime/sub-agent-orchestrator.d.ts +2 -2
- package/dist/runtime/sub-agent-orchestrator.js +14 -23
- package/dist/runtime/types/agent.d.ts +12 -3
- package/dist/runtime/types/agent.js +18 -0
- package/dist/types.d.ts +24 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ src/
|
|
|
75
75
|
|
|
76
76
|
The kernel (`@deepstrike/wasm-kernel`, Rust/wasm-bindgen) owns:
|
|
77
77
|
- `KernelRuntime.step()` — drives `call_provider → execute_tool → evaluate_milestone → done`
|
|
78
|
-
- `ContextEngine` —
|
|
78
|
+
- `ContextEngine` — 4-slot context with tiered history compression
|
|
79
79
|
- `Governance` — tool veto authority
|
|
80
80
|
- `SignalRouter` — external interrupt queue
|
|
81
81
|
|
|
@@ -146,6 +146,27 @@ plane.register(fetchUrl)
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
+
## Context model (four slots)
|
|
150
|
+
|
|
151
|
+
Same as Node/Python — only **history** is compressed. WASM exposes `systemStable`, `systemKnowledge`, and `turns` on `call_provider.context`.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const runner = new RuntimeRunner({
|
|
155
|
+
provider,
|
|
156
|
+
sessionLog: new InMemorySessionLog(),
|
|
157
|
+
executionPlane: plane,
|
|
158
|
+
maxTokens: 32_000,
|
|
159
|
+
initialMemory: ["User prefers concise answers."], // → Slot 2
|
|
160
|
+
systemPrompt: "You are a helpful assistant.", // → Slot 1
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
IndexedDB / KV can back `DreamStore` for cross-session memory. Meta-tool retrieval still lands in **history**.
|
|
165
|
+
|
|
166
|
+
See [docs/concepts/context-slots-compression.md](../docs/concepts/context-slots-compression.md).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
149
170
|
## Governance
|
|
150
171
|
|
|
151
172
|
```typescript
|
|
@@ -167,7 +188,7 @@ const runner = new RuntimeRunner({
|
|
|
167
188
|
|
|
168
189
|
## Memory
|
|
169
190
|
|
|
170
|
-
`WorkingMemory` is an
|
|
191
|
+
`WorkingMemory` is an SDK-side scratch pad — not the removed kernel `working` partition. Structured task state renders into Slot 3 (`turns[0]`).
|
|
171
192
|
|
|
172
193
|
```typescript
|
|
173
194
|
import { WorkingMemory } from "@deepstrike/wasm"
|
|
@@ -177,10 +198,14 @@ mem.set("step", 1)
|
|
|
177
198
|
mem.get("step") // 1
|
|
178
199
|
```
|
|
179
200
|
|
|
201
|
+
For cross-session recall, implement `DreamStore` and set `agentId` on `RuntimeRunner`. In-session `memory(query)` results appear in **history**; preload durable blocks with `initialMemory` → Slot 2.
|
|
202
|
+
|
|
180
203
|
---
|
|
181
204
|
|
|
182
205
|
## Knowledge
|
|
183
206
|
|
|
207
|
+
Runtime `knowledge(query)` results → **history** (tool results). Durable preload → Slot 2 via `initialMemory`.
|
|
208
|
+
|
|
184
209
|
```typescript
|
|
185
210
|
import type { KnowledgeSource } from "@deepstrike/wasm"
|
|
186
211
|
|
|
@@ -230,6 +255,8 @@ for await (const event of loop.runStreaming({
|
|
|
230
255
|
|
|
231
256
|
## Signals & interrupts
|
|
232
257
|
|
|
258
|
+
Delivered signals fold into Slot 3 (`turns[0]`) and are cleared after each render — they do not survive renewal.
|
|
259
|
+
|
|
233
260
|
```typescript
|
|
234
261
|
import { ScheduledPrompt } from "@deepstrike/wasm"
|
|
235
262
|
import type { SignalSource, RuntimeSignal } from "@deepstrike/wasm"
|
package/dist/governance.d.ts
CHANGED
|
@@ -23,4 +23,36 @@ export declare class Governance {
|
|
|
23
23
|
setTime(nowMs: number): this;
|
|
24
24
|
evaluate(toolName: string, argsJson: string): GovernanceVerdict;
|
|
25
25
|
}
|
|
26
|
+
type GovernancePolicyAction = "allow" | "deny" | "ask_user";
|
|
27
|
+
export interface GovernancePolicy {
|
|
28
|
+
defaultAction?: GovernancePolicyAction;
|
|
29
|
+
rules?: {
|
|
30
|
+
pattern: string;
|
|
31
|
+
action: GovernancePolicyAction;
|
|
32
|
+
}[];
|
|
33
|
+
vetoes?: string[];
|
|
34
|
+
rateLimits?: {
|
|
35
|
+
tool: string;
|
|
36
|
+
maxCalls: number;
|
|
37
|
+
windowMs: number;
|
|
38
|
+
}[];
|
|
39
|
+
constraints?: GovernanceConstraint[];
|
|
40
|
+
}
|
|
41
|
+
export type GovernanceConstraint = {
|
|
42
|
+
kind: "required";
|
|
43
|
+
tool: string;
|
|
44
|
+
path: string;
|
|
45
|
+
} | {
|
|
46
|
+
kind: "enum";
|
|
47
|
+
tool: string;
|
|
48
|
+
path: string;
|
|
49
|
+
values: string[];
|
|
50
|
+
} | {
|
|
51
|
+
kind: "range";
|
|
52
|
+
tool: string;
|
|
53
|
+
path: string;
|
|
54
|
+
min?: number;
|
|
55
|
+
max?: number;
|
|
56
|
+
};
|
|
57
|
+
export declare function governancePolicyToKernelEvent(policy: GovernancePolicy): Record<string, unknown>;
|
|
26
58
|
export {};
|
package/dist/governance.js
CHANGED
|
@@ -51,3 +51,21 @@ export class Governance {
|
|
|
51
51
|
return this._inner.evaluate(toolName, argsJson);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
export function governancePolicyToKernelEvent(policy) {
|
|
55
|
+
return {
|
|
56
|
+
kind: "load_governance_policy",
|
|
57
|
+
...(policy.defaultAction ? { default_action: policy.defaultAction } : {}),
|
|
58
|
+
rules: (policy.rules ?? []).map(r => ({ tool_pattern: r.pattern, action: r.action })),
|
|
59
|
+
vetoed_tools: policy.vetoes ?? [],
|
|
60
|
+
rate_limits: (policy.rateLimits ?? []).map(rl => ({
|
|
61
|
+
tool: rl.tool,
|
|
62
|
+
max_calls: rl.maxCalls,
|
|
63
|
+
window_ms: rl.windowMs,
|
|
64
|
+
})),
|
|
65
|
+
constraints: (policy.constraints ?? []).map(c => c.kind === "enum"
|
|
66
|
+
? { kind: "enum", tool: c.tool, path: c.path, values: c.values }
|
|
67
|
+
: c.kind === "range"
|
|
68
|
+
? { kind: "range", tool: c.tool, path: c.path, ...(c.min !== undefined ? { min: c.min } : {}), ...(c.max !== undefined ? { max: c.max } : {}) }
|
|
69
|
+
: { kind: "required", tool: c.tool, path: c.path }),
|
|
70
|
+
};
|
|
71
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { RuntimeOptions, SessionEvent, SessionLog, RunContext, ExecutionPla
|
|
|
3
3
|
export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
|
|
4
4
|
export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
|
|
5
5
|
export type { SubAgentRunContext } from "./runtime/sub-agent-orchestrator.js";
|
|
6
|
-
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec,
|
|
6
|
+
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, } from "./runtime/types/agent.js";
|
|
7
7
|
export { Governance } from "./governance.js";
|
|
8
8
|
export type { GovernanceVerdict } from "./governance.js";
|
|
9
9
|
export { AnthropicProvider } from "./providers/anthropic.js";
|
|
@@ -19,4 +19,4 @@ export { ScheduledPrompt } from "./signals/index.js";
|
|
|
19
19
|
export type { RuntimeSignal, SignalSource } from "./signals/index.js";
|
|
20
20
|
export { PermissionManager, PermissionMode } from "./safety/index.js";
|
|
21
21
|
export type { PermissionDecision } from "./safety/index.js";
|
|
22
|
-
export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, LLMProvider, } from "./types.js";
|
|
22
|
+
export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, } from "./types.js";
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { assistantReplayKey, collectStreamMessage, toAnthropicMessages } from "./base.js";
|
|
2
2
|
function buildAnthropicTools(tools) {
|
|
3
|
-
return tools.map(
|
|
3
|
+
return tools.map((t, i) => ({
|
|
4
|
+
name: t.name,
|
|
5
|
+
description: t.description,
|
|
6
|
+
input_schema: JSON.parse(t.parameters),
|
|
7
|
+
...(i === tools.length - 1 ? { cache_control: { type: "ephemeral" } } : {}),
|
|
8
|
+
}));
|
|
4
9
|
}
|
|
5
10
|
export class AnthropicProvider {
|
|
6
11
|
apiKey;
|
|
@@ -25,7 +30,14 @@ export class AnthropicProvider {
|
|
|
25
30
|
return collectStreamMessage(this.stream(context, tools, extensions));
|
|
26
31
|
}
|
|
27
32
|
async *stream(context, tools, extensions) {
|
|
28
|
-
const
|
|
33
|
+
const systemBlocks = [];
|
|
34
|
+
if (context.systemStable) {
|
|
35
|
+
systemBlocks.push({ type: "text", text: context.systemStable, cache_control: { type: "ephemeral" } });
|
|
36
|
+
}
|
|
37
|
+
if (context.systemKnowledge) {
|
|
38
|
+
systemBlocks.push({ type: "text", text: context.systemKnowledge, cache_control: { type: "ephemeral" } });
|
|
39
|
+
}
|
|
40
|
+
const system = systemBlocks.length ? systemBlocks : (context.systemText || undefined);
|
|
29
41
|
const msgs = toAnthropicMessages(context, message => this.nativeAssistantBlocks.get(assistantReplayKey(message)));
|
|
30
42
|
const body = {
|
|
31
43
|
model: this.model,
|
|
@@ -44,6 +56,7 @@ export class AnthropicProvider {
|
|
|
44
56
|
"x-api-key": this.apiKey,
|
|
45
57
|
"anthropic-version": "2023-06-01",
|
|
46
58
|
"content-type": "application/json",
|
|
59
|
+
"anthropic-beta": "prompt-caching-2024-07-31",
|
|
47
60
|
},
|
|
48
61
|
body: JSON.stringify(body),
|
|
49
62
|
});
|
|
@@ -74,9 +87,13 @@ export class AnthropicProvider {
|
|
|
74
87
|
if (evt.type === "message_start" || evt.type === "message_delta") {
|
|
75
88
|
const usage = (evt.usage ?? evt.message?.usage);
|
|
76
89
|
if (usage?.input_tokens != null) {
|
|
90
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
91
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
77
92
|
yield {
|
|
78
93
|
type: "usage",
|
|
79
|
-
totalTokens:
|
|
94
|
+
totalTokens: inputTokens + outputTokens,
|
|
95
|
+
inputTokens,
|
|
96
|
+
outputTokens,
|
|
80
97
|
};
|
|
81
98
|
}
|
|
82
99
|
}
|
package/dist/providers/base.js
CHANGED
|
@@ -57,19 +57,29 @@ export function toAnthropicMessages(context, nativeReplay) {
|
|
|
57
57
|
}
|
|
58
58
|
result.push({ role: msg.role, content: msg.content });
|
|
59
59
|
}
|
|
60
|
+
if (context.systemVolatile && result.length > 0) {
|
|
61
|
+
const last = result[result.length - 1];
|
|
62
|
+
if (last.role === "user") {
|
|
63
|
+
last.content = `${String(last.content ?? "")}\n\n[SYSTEM REMINDER]\n${context.systemVolatile}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
60
66
|
return result;
|
|
61
67
|
}
|
|
62
68
|
/** Collect a non-streaming assistant Message from stream events. */
|
|
63
69
|
export async function collectStreamMessage(stream) {
|
|
64
70
|
let content = "";
|
|
65
71
|
const toolCalls = [];
|
|
72
|
+
let outputTokens;
|
|
66
73
|
for await (const evt of stream) {
|
|
67
74
|
if (evt.type === "text_delta" && evt.delta)
|
|
68
75
|
content += evt.delta;
|
|
69
76
|
else if (evt.type === "tool_call" && evt.id && evt.name) {
|
|
70
77
|
toolCalls.push({ id: evt.id, name: evt.name, arguments: JSON.stringify(evt.arguments ?? {}) });
|
|
71
78
|
}
|
|
79
|
+
else if (evt.type === "usage") {
|
|
80
|
+
outputTokens = evt.outputTokens ?? evt.totalTokens;
|
|
81
|
+
}
|
|
72
82
|
}
|
|
73
|
-
return { role: "assistant", content, ...(toolCalls.length ? { toolCalls } : {}) };
|
|
83
|
+
return { role: "assistant", content, ...(outputTokens ? { tokenCount: outputTokens } : {}), ...(toolCalls.length ? { toolCalls } : {}) };
|
|
74
84
|
}
|
|
75
85
|
export { assistantReplayKey };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ToolCall, ToolSchema, StreamEvent } from "../types.js";
|
|
1
|
+
import type { ToolCall, ToolSchema, StreamEvent, PermissionRequestEvent, PermissionResponse } from "../types.js";
|
|
2
2
|
import type { RegisteredTool } from "../tools/index.js";
|
|
3
3
|
import type { DreamStore } from "../memory/index.js";
|
|
4
4
|
import type { KnowledgeSource } from "../knowledge/index.js";
|
|
5
|
-
import
|
|
5
|
+
import { LargeResultSpool } from "./large-result-spool.js";
|
|
6
6
|
export interface ToolSuspendEvent {
|
|
7
7
|
type: "tool_suspend";
|
|
8
8
|
callId: string;
|
|
@@ -15,8 +15,9 @@ export interface RunContext {
|
|
|
15
15
|
skillContentMap?: Map<string, string>;
|
|
16
16
|
dreamStore?: DreamStore;
|
|
17
17
|
knowledgeSource?: KnowledgeSource;
|
|
18
|
-
governance?: Governance;
|
|
19
18
|
onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
|
|
19
|
+
onPermissionRequest?: (event: PermissionRequestEvent) => Promise<PermissionResponse | boolean> | PermissionResponse | boolean;
|
|
20
|
+
resultSpool?: LargeResultSpool;
|
|
20
21
|
}
|
|
21
22
|
export interface ExecutionPlane {
|
|
22
23
|
register(...tools: RegisteredTool[]): this;
|
|
@@ -30,4 +31,6 @@ export declare class LocalExecutionPlane implements ExecutionPlane {
|
|
|
30
31
|
unregister(name: string): this;
|
|
31
32
|
schemas(): ToolSchema[];
|
|
32
33
|
executeAll(calls: ToolCall[], ctx: RunContext): AsyncIterable<StreamEvent>;
|
|
34
|
+
private tryReadSpooledArgument;
|
|
33
35
|
}
|
|
36
|
+
export declare function resolvePermissionRequest(request: PermissionRequestEvent, ctx: RunContext): Promise<PermissionResponse>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LargeResultSpool } from "./large-result-spool.js";
|
|
1
2
|
function stripFrontmatter(content) {
|
|
2
3
|
const s = content.trimStart();
|
|
3
4
|
if (!s.startsWith("---"))
|
|
@@ -21,29 +22,7 @@ export class LocalExecutionPlane {
|
|
|
21
22
|
return Array.from(this.tools.values()).map(t => t.schema);
|
|
22
23
|
}
|
|
23
24
|
async *executeAll(calls, ctx) {
|
|
24
|
-
const permitted =
|
|
25
|
-
for (const c of calls) {
|
|
26
|
-
if (ctx.governance) {
|
|
27
|
-
ctx.governance.setTime(Date.now());
|
|
28
|
-
const v = ctx.governance.evaluate(c.name, c.arguments);
|
|
29
|
-
if (v.kind === "deny") {
|
|
30
|
-
yield { type: "tool_denied", callId: c.id, toolName: c.name, reason: v.reason ?? "" };
|
|
31
|
-
yield { type: "tool_result", callId: c.id, name: c.name, content: `permission denied: ${v.reason ?? ""}`, isError: true, isFatal: false, errorKind: "governance_denied" };
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (v.kind === "rate_limited") {
|
|
35
|
-
yield { type: "tool_denied", callId: c.id, toolName: c.name, reason: "rate limited" };
|
|
36
|
-
yield { type: "tool_result", callId: c.id, name: c.name, content: "rate limited", isError: true, isFatal: false, errorKind: "recoverable" };
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (v.kind === "ask_user") {
|
|
40
|
-
yield { type: "permission_request", callId: c.id, toolName: c.name, arguments: c.arguments, reason: v.reason ?? "" };
|
|
41
|
-
yield { type: "tool_result", callId: c.id, name: c.name, content: "awaiting user approval", isError: true, isFatal: false, errorKind: "recoverable" };
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
permitted.push(c);
|
|
46
|
-
}
|
|
25
|
+
const permitted = calls;
|
|
47
26
|
const skillCalls = permitted.filter(c => c.name === "skill");
|
|
48
27
|
const memoryCalls = permitted.filter(c => c.name === "memory");
|
|
49
28
|
const knowledgeCalls = permitted.filter(c => c.name === "knowledge");
|
|
@@ -82,6 +61,11 @@ export class LocalExecutionPlane {
|
|
|
82
61
|
yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
|
|
83
62
|
}
|
|
84
63
|
for (const call of regularCalls) {
|
|
64
|
+
const spooledContent = await this.tryReadSpooledArgument(call, ctx);
|
|
65
|
+
if (spooledContent !== null) {
|
|
66
|
+
yield { type: "tool_result", callId: call.id, name: call.name, content: spooledContent, isError: false };
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
85
69
|
const registered = this.tools.get(call.name);
|
|
86
70
|
if (!registered) {
|
|
87
71
|
yield { type: "tool_result", callId: call.id, name: call.name, content: `unknown tool: ${call.name}`, isError: true, isFatal: false, errorKind: "recoverable" };
|
|
@@ -105,6 +89,25 @@ export class LocalExecutionPlane {
|
|
|
105
89
|
}
|
|
106
90
|
}
|
|
107
91
|
}
|
|
92
|
+
async tryReadSpooledArgument(call, ctx) {
|
|
93
|
+
const isReadTool = ["read", "read_file", "view_file", "read_spooled_result"].includes(call.name);
|
|
94
|
+
if (!isReadTool)
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
const args = JSON.parse(call.arguments || "{}");
|
|
98
|
+
for (const val of Object.values(args)) {
|
|
99
|
+
if (typeof val === "string" && (val.startsWith(".spool/") || val.includes("/.spool/"))) {
|
|
100
|
+
const spool = ctx.resultSpool ?? new LargeResultSpool();
|
|
101
|
+
const content = await spool.readSpooledResult(val);
|
|
102
|
+
return content;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Ignore errors
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
108
111
|
}
|
|
109
112
|
function tryParseJson(s) {
|
|
110
113
|
try {
|
|
@@ -114,3 +117,31 @@ function tryParseJson(s) {
|
|
|
114
117
|
return null;
|
|
115
118
|
}
|
|
116
119
|
}
|
|
120
|
+
export async function resolvePermissionRequest(request, ctx) {
|
|
121
|
+
if (!ctx.onPermissionRequest) {
|
|
122
|
+
return {
|
|
123
|
+
approved: false,
|
|
124
|
+
responder: "policy_gate",
|
|
125
|
+
reason: "no permission handler configured",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
return normalizePermissionResponse(await ctx.onPermissionRequest(request));
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return {
|
|
133
|
+
approved: false,
|
|
134
|
+
responder: "permission_handler",
|
|
135
|
+
reason: `permission handler failed: ${String(err)}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function normalizePermissionResponse(value) {
|
|
140
|
+
if (typeof value === "boolean")
|
|
141
|
+
return { approved: value, responder: "host" };
|
|
142
|
+
return {
|
|
143
|
+
approved: Boolean(value.approved),
|
|
144
|
+
responder: value.responder ?? "host",
|
|
145
|
+
...(value.reason ? { reason: value.reason } : {}),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { KernelObservation } from "./kernel-step.js";
|
|
2
|
+
import type { SessionEvent } from "./session-log.js";
|
|
3
|
+
/** Agent OS kernel event category (Phase 5). */
|
|
4
|
+
export type KernelEventCategory = "syscall" | "sched" | "mm" | "proc" | "ipc";
|
|
5
|
+
export declare function categoryForKind(kind: string): KernelEventCategory;
|
|
6
|
+
export declare function withCategory<T extends {
|
|
7
|
+
kind: string;
|
|
8
|
+
}>(event: T): T & {
|
|
9
|
+
category: KernelEventCategory;
|
|
10
|
+
primitive: KernelPrimitive;
|
|
11
|
+
};
|
|
12
|
+
type CompressionAction = Extract<SessionEvent, {
|
|
13
|
+
kind: "compressed";
|
|
14
|
+
}>["action"];
|
|
15
|
+
export declare function kernelObservationToSessionEvent(obs: KernelObservation, turn: number, opts?: {
|
|
16
|
+
nextArchiveStart?: number;
|
|
17
|
+
latestSeq?: number;
|
|
18
|
+
archiveRef?: string;
|
|
19
|
+
preservedRefs?: string[];
|
|
20
|
+
compressionAction?: (action?: string) => CompressionAction;
|
|
21
|
+
spoolRef?: string;
|
|
22
|
+
}): SessionEvent | null;
|
|
23
|
+
export type KernelPrimitive = "syscall" | "sched" | "mm";
|
|
24
|
+
export declare function primitiveForCategory(category: KernelEventCategory): KernelPrimitive;
|
|
25
|
+
export declare function primitiveForKind(kind: string): KernelPrimitive;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
export function categoryForKind(kind) {
|
|
2
|
+
switch (kind) {
|
|
3
|
+
case "tool_gated":
|
|
4
|
+
case "capability_changed":
|
|
5
|
+
return "syscall";
|
|
6
|
+
case "compressed":
|
|
7
|
+
case "page_out":
|
|
8
|
+
case "page_in":
|
|
9
|
+
case "page_in_requested":
|
|
10
|
+
case "renewed":
|
|
11
|
+
case "context_renewed":
|
|
12
|
+
case "large_result_spooled":
|
|
13
|
+
case "memory_written":
|
|
14
|
+
case "memory_queried":
|
|
15
|
+
return "mm";
|
|
16
|
+
case "agent_process_changed":
|
|
17
|
+
return "proc";
|
|
18
|
+
case "signal_disposed":
|
|
19
|
+
return "ipc";
|
|
20
|
+
default:
|
|
21
|
+
return "sched";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function withCategory(event) {
|
|
25
|
+
const category = categoryForKind(event.kind);
|
|
26
|
+
return {
|
|
27
|
+
...event,
|
|
28
|
+
category,
|
|
29
|
+
primitive: primitiveForCategory(category),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
33
|
+
const t = obs.turn ?? turn;
|
|
34
|
+
const compressionAction = opts.compressionAction ?? (() => undefined);
|
|
35
|
+
switch (obs.kind) {
|
|
36
|
+
case "page_out":
|
|
37
|
+
return withCategory({
|
|
38
|
+
kind: "page_out",
|
|
39
|
+
turn: t,
|
|
40
|
+
action: compressionAction(obs.action),
|
|
41
|
+
summary: obs.summary,
|
|
42
|
+
tier_hint: obs.tier_hint ?? "durable",
|
|
43
|
+
message_count: Array.isArray(obs.archived) ? obs.archived.length : 0,
|
|
44
|
+
});
|
|
45
|
+
case "compressed": {
|
|
46
|
+
const latest = opts.latestSeq ?? -1;
|
|
47
|
+
const start = opts.nextArchiveStart ?? 0;
|
|
48
|
+
if (latest < start)
|
|
49
|
+
return null;
|
|
50
|
+
return withCategory({
|
|
51
|
+
kind: "compressed",
|
|
52
|
+
turn: t,
|
|
53
|
+
archived_seq_range: [start, latest],
|
|
54
|
+
action: compressionAction(obs.action),
|
|
55
|
+
summary: obs.summary,
|
|
56
|
+
summary_tokens: obs.summary ? Math.max(1, Math.ceil(obs.summary.length / 4)) : undefined,
|
|
57
|
+
archive_ref: opts.archiveRef,
|
|
58
|
+
preserved_refs: opts.preservedRefs ?? [],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
case "renewed":
|
|
62
|
+
return withCategory({
|
|
63
|
+
kind: "context_renewed",
|
|
64
|
+
turn: t,
|
|
65
|
+
sprint: obs.sprint ?? 0,
|
|
66
|
+
handoff_ref: "",
|
|
67
|
+
});
|
|
68
|
+
case "rollbacked":
|
|
69
|
+
return withCategory({
|
|
70
|
+
kind: "rollbacked",
|
|
71
|
+
turn: t,
|
|
72
|
+
checkpoint_history_len: obs.checkpoint_history_len ?? 0,
|
|
73
|
+
reason: obs.reason,
|
|
74
|
+
});
|
|
75
|
+
case "capability_changed":
|
|
76
|
+
return withCategory({
|
|
77
|
+
kind: "capability_changed",
|
|
78
|
+
turn: t,
|
|
79
|
+
added: obs.added ?? [],
|
|
80
|
+
removed: obs.removed ?? [],
|
|
81
|
+
...(obs.change_kind != null && { change_kind: obs.change_kind }),
|
|
82
|
+
...(obs.capability_id != null && { capability_id: obs.capability_id }),
|
|
83
|
+
...(obs.version != null && { version: obs.version }),
|
|
84
|
+
...(obs.mounted_by != null && { mounted_by: obs.mounted_by }),
|
|
85
|
+
...(obs.mount_reason != null && { mount_reason: obs.mount_reason }),
|
|
86
|
+
});
|
|
87
|
+
case "milestone_advanced":
|
|
88
|
+
return withCategory({
|
|
89
|
+
kind: "milestone_advanced",
|
|
90
|
+
turn: t,
|
|
91
|
+
phase_id: obs.phase_id ?? "",
|
|
92
|
+
capabilities_unlocked: obs.capabilities_unlocked ?? [],
|
|
93
|
+
});
|
|
94
|
+
case "milestone_blocked":
|
|
95
|
+
return withCategory({
|
|
96
|
+
kind: "milestone_blocked",
|
|
97
|
+
turn: t,
|
|
98
|
+
phase_id: obs.phase_id ?? "",
|
|
99
|
+
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
100
|
+
});
|
|
101
|
+
case "milestone_evidence":
|
|
102
|
+
return withCategory({
|
|
103
|
+
kind: "milestone_evidence",
|
|
104
|
+
turn: t,
|
|
105
|
+
phase_id: obs.phase_id ?? "",
|
|
106
|
+
evidence: obs.evidence ?? [],
|
|
107
|
+
});
|
|
108
|
+
case "checkpoint_taken":
|
|
109
|
+
return withCategory({
|
|
110
|
+
kind: "checkpoint_taken",
|
|
111
|
+
turn: t,
|
|
112
|
+
history_len: obs.history_len ?? 0,
|
|
113
|
+
});
|
|
114
|
+
case "agent_process_changed":
|
|
115
|
+
return withCategory({
|
|
116
|
+
kind: "agent_process_changed",
|
|
117
|
+
turn: t,
|
|
118
|
+
agent_id: obs.agent_id ?? "",
|
|
119
|
+
parent_session_id: obs.parent_session_id ?? "",
|
|
120
|
+
role: obs.role ?? "",
|
|
121
|
+
isolation: obs.isolation ?? "",
|
|
122
|
+
context_inheritance: obs.context_inheritance ?? "",
|
|
123
|
+
state: obs.state ?? "running",
|
|
124
|
+
permitted_capability_ids: obs.permitted_capability_ids ?? [],
|
|
125
|
+
...(obs.result_termination
|
|
126
|
+
? { result_termination: obs.result_termination }
|
|
127
|
+
: {}),
|
|
128
|
+
});
|
|
129
|
+
case "tool_gated":
|
|
130
|
+
return withCategory({
|
|
131
|
+
kind: "tool_gated",
|
|
132
|
+
turn: t,
|
|
133
|
+
call_id: obs.call_id ?? "",
|
|
134
|
+
tool: obs.tool ?? "",
|
|
135
|
+
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
136
|
+
});
|
|
137
|
+
case "signal_disposed":
|
|
138
|
+
return withCategory({
|
|
139
|
+
kind: "signal_disposed",
|
|
140
|
+
turn: t,
|
|
141
|
+
signal_id: obs.signal_id ?? "",
|
|
142
|
+
disposition: obs.disposition ?? "",
|
|
143
|
+
queue_depth: obs.queue_depth ?? 0,
|
|
144
|
+
});
|
|
145
|
+
case "budget_exceeded":
|
|
146
|
+
return withCategory({
|
|
147
|
+
kind: "budget_exceeded",
|
|
148
|
+
turn: t,
|
|
149
|
+
budget: obs.budget ?? "",
|
|
150
|
+
});
|
|
151
|
+
case "suspended":
|
|
152
|
+
return withCategory({
|
|
153
|
+
kind: "suspended",
|
|
154
|
+
turn: t,
|
|
155
|
+
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
156
|
+
pending_calls: obs.pending_calls ?? [],
|
|
157
|
+
});
|
|
158
|
+
case "resumed":
|
|
159
|
+
return withCategory({
|
|
160
|
+
kind: "resumed",
|
|
161
|
+
turn: t,
|
|
162
|
+
approved: obs.approved ?? [],
|
|
163
|
+
denied: obs.denied ?? [],
|
|
164
|
+
});
|
|
165
|
+
case "page_in_requested":
|
|
166
|
+
return null;
|
|
167
|
+
case "large_result_spooled":
|
|
168
|
+
return withCategory({
|
|
169
|
+
kind: "large_result_spooled",
|
|
170
|
+
turn: t,
|
|
171
|
+
call_id: obs.call_id ?? "",
|
|
172
|
+
tool: obs.tool ?? "",
|
|
173
|
+
original_size: obs.original_size ?? 0,
|
|
174
|
+
preview_size: obs.preview_size ?? 0,
|
|
175
|
+
spool_ref: opts.spoolRef,
|
|
176
|
+
});
|
|
177
|
+
case "memory_written":
|
|
178
|
+
return withCategory({
|
|
179
|
+
kind: "memory_written",
|
|
180
|
+
turn: t,
|
|
181
|
+
memory_id: obs.memory_id ?? "",
|
|
182
|
+
memory_kind: obs.memory_kind ?? "",
|
|
183
|
+
size_bytes: obs.size_bytes ?? 0,
|
|
184
|
+
});
|
|
185
|
+
case "memory_queried":
|
|
186
|
+
return withCategory({
|
|
187
|
+
kind: "memory_queried",
|
|
188
|
+
turn: t,
|
|
189
|
+
query_context: obs.query_context ?? "",
|
|
190
|
+
requested_k: obs.requested_k ?? 0,
|
|
191
|
+
requires_async_response: obs.requires_async_response ?? false,
|
|
192
|
+
});
|
|
193
|
+
default:
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export function primitiveForCategory(category) {
|
|
198
|
+
switch (category) {
|
|
199
|
+
case "syscall":
|
|
200
|
+
return "syscall";
|
|
201
|
+
case "mm":
|
|
202
|
+
return "mm";
|
|
203
|
+
case "proc":
|
|
204
|
+
case "ipc":
|
|
205
|
+
case "sched":
|
|
206
|
+
default:
|
|
207
|
+
return "sched";
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export function primitiveForKind(kind) {
|
|
211
|
+
return primitiveForCategory(categoryForKind(kind));
|
|
212
|
+
}
|
|
@@ -65,7 +65,7 @@ export interface KernelObservation {
|
|
|
65
65
|
phase_id?: string;
|
|
66
66
|
capabilities_unlocked?: string[];
|
|
67
67
|
evidence?: string[];
|
|
68
|
-
reason?: RollbackReason;
|
|
68
|
+
reason?: RollbackReason | string;
|
|
69
69
|
agent_id?: string;
|
|
70
70
|
parent_session_id?: string;
|
|
71
71
|
role?: string;
|
|
@@ -73,6 +73,24 @@ export interface KernelObservation {
|
|
|
73
73
|
context_inheritance?: string;
|
|
74
74
|
permitted_capability_ids?: string[];
|
|
75
75
|
history_len?: number;
|
|
76
|
+
tier_hint?: string;
|
|
77
|
+
call_id?: string;
|
|
78
|
+
tool?: string;
|
|
79
|
+
signal_id?: string;
|
|
80
|
+
disposition?: string;
|
|
81
|
+
queue_depth?: number;
|
|
82
|
+
budget?: string;
|
|
83
|
+
pending_calls?: string[];
|
|
84
|
+
approved?: string[];
|
|
85
|
+
denied?: string[];
|
|
86
|
+
original_size?: number;
|
|
87
|
+
preview_size?: number;
|
|
88
|
+
memory_id?: string;
|
|
89
|
+
memory_kind?: string;
|
|
90
|
+
size_bytes?: number;
|
|
91
|
+
query_context?: string;
|
|
92
|
+
requested_k?: number;
|
|
93
|
+
requires_async_response?: boolean;
|
|
76
94
|
}
|
|
77
95
|
export declare function toolSchemaToKernel(schema: ToolSchema): Record<string, unknown>;
|
|
78
96
|
export declare function skillMetadataToKernel(skill: SkillMetadata): Record<string, unknown>;
|
|
@@ -84,5 +102,7 @@ export declare function capabilitySkill(skill: SkillMetadata): Record<string, un
|
|
|
84
102
|
export declare function capabilityMarker(kind: string, id: string, description: string): Record<string, unknown>;
|
|
85
103
|
export declare function kernelApply(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelObservation[];
|
|
86
104
|
export declare function kernelAction(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelRunnerAction;
|
|
105
|
+
/** Like kernelAction but tolerates zero-action steps (e.g. queued signals). */
|
|
106
|
+
export declare function kernelMaybeAction(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelRunnerAction | null;
|
|
87
107
|
export declare function forceCompact(runtime: KernelRuntimeHandle, pending: KernelObservation[]): boolean;
|
|
88
108
|
export {};
|
|
@@ -114,6 +114,8 @@ function kernelMessageToSdk(raw) {
|
|
|
114
114
|
function renderedContextToSdk(raw) {
|
|
115
115
|
return {
|
|
116
116
|
systemText: String(raw.system_text ?? raw.systemText ?? ""),
|
|
117
|
+
systemStable: String(raw.system_stable ?? raw.systemStable ?? ""),
|
|
118
|
+
systemKnowledge: String(raw.system_knowledge ?? raw.systemKnowledge ?? ""),
|
|
117
119
|
turns: (raw.turns ?? []).map(kernelMessageToSdk),
|
|
118
120
|
};
|
|
119
121
|
}
|
|
@@ -176,6 +178,13 @@ export function kernelAction(runtime, pending, event) {
|
|
|
176
178
|
throw new Error("kernel transition must return one action");
|
|
177
179
|
return mapKernelAction(raw);
|
|
178
180
|
}
|
|
181
|
+
/** Like kernelAction but tolerates zero-action steps (e.g. queued signals). */
|
|
182
|
+
export function kernelMaybeAction(runtime, pending, event) {
|
|
183
|
+
const step = parseStep(runtime.step(stepInput(event)));
|
|
184
|
+
pending.push(...step.observations);
|
|
185
|
+
const raw = step.actions[0];
|
|
186
|
+
return raw ? mapKernelAction(raw) : null;
|
|
187
|
+
}
|
|
179
188
|
export function forceCompact(runtime, pending) {
|
|
180
189
|
return kernelApply(runtime, pending, { kind: "force_compact" }).some(o => o.kind === "compressed");
|
|
181
190
|
}
|