@deepstrike/wasm 0.1.15 → 0.2.1
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 +1 -1
- package/dist/governance.d.ts +13 -1
- package/dist/governance.js +34 -9
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/runtime/execution-plane.js +15 -7
- package/dist/runtime/filtered-plane.d.ts +14 -0
- package/dist/runtime/filtered-plane.js +45 -0
- package/dist/runtime/kernel-step.d.ts +88 -0
- package/dist/runtime/kernel-step.js +181 -0
- package/dist/runtime/provider-replay.js +7 -2
- package/dist/runtime/replay-sanitize.d.ts +4 -0
- package/dist/runtime/replay-sanitize.js +26 -0
- package/dist/runtime/runner.d.ts +25 -2
- package/dist/runtime/runner.js +386 -63
- package/dist/runtime/session-log.d.ts +93 -1
- package/dist/runtime/session-repair.d.ts +33 -0
- package/dist/runtime/session-repair.js +73 -0
- package/dist/runtime/sub-agent-orchestrator.d.ts +17 -0
- package/dist/runtime/sub-agent-orchestrator.js +112 -0
- package/dist/runtime/types/agent.d.ts +68 -0
- package/dist/runtime/types/agent.js +78 -0
- package/dist/types.d.ts +18 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ src/
|
|
|
74
74
|
```
|
|
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
78
|
- `ContextEngine` — 5-partition context with pressure-based compression
|
|
79
79
|
- `Governance` — tool veto authority
|
|
80
80
|
- `SignalRouter` — external interrupt queue
|
package/dist/governance.d.ts
CHANGED
|
@@ -3,12 +3,24 @@ export interface GovernanceVerdict {
|
|
|
3
3
|
reason?: string;
|
|
4
4
|
retryAfterMs?: number;
|
|
5
5
|
}
|
|
6
|
+
type DefaultAction = "allow" | "deny" | "ask_user";
|
|
7
|
+
type RuleAction = "allow" | "deny" | "ask_user";
|
|
6
8
|
export declare class Governance {
|
|
7
9
|
private _inner;
|
|
8
|
-
private
|
|
10
|
+
private _defaultAction;
|
|
11
|
+
private _pendingCalls;
|
|
12
|
+
constructor(defaultAction?: DefaultAction);
|
|
9
13
|
/** Called by Agent after the WASM kernel module is loaded. */
|
|
10
14
|
_attach(kernel: typeof import("@deepstrike/wasm-kernel")): void;
|
|
15
|
+
private _apply;
|
|
16
|
+
setIdentity(agentId: string, sessionId: string): this;
|
|
17
|
+
addPermissionRule(pattern: string, action: RuleAction): this;
|
|
11
18
|
blockTool(name: string): this;
|
|
19
|
+
setRateLimit(toolName: string, maxCalls: number, windowMs: number): this;
|
|
20
|
+
requireParam(toolName: string, paramPath: string): this;
|
|
21
|
+
allowParamValues(toolName: string, paramPath: string, allowedValues: string[]): this;
|
|
22
|
+
limitParamRange(toolName: string, paramPath: string, min?: number, max?: number): this;
|
|
12
23
|
setTime(nowMs: number): this;
|
|
13
24
|
evaluate(toolName: string, argsJson: string): GovernanceVerdict;
|
|
14
25
|
}
|
|
26
|
+
export {};
|
package/dist/governance.js
CHANGED
|
@@ -1,24 +1,49 @@
|
|
|
1
1
|
export class Governance {
|
|
2
2
|
_inner = null;
|
|
3
|
-
|
|
3
|
+
_defaultAction;
|
|
4
|
+
_pendingCalls = [];
|
|
5
|
+
constructor(defaultAction = "allow") {
|
|
6
|
+
this._defaultAction = defaultAction;
|
|
7
|
+
}
|
|
4
8
|
/** Called by Agent after the WASM kernel module is loaded. */
|
|
5
9
|
_attach(kernel) {
|
|
6
10
|
if (this._inner)
|
|
7
11
|
return;
|
|
8
|
-
this._inner = new kernel.Governance();
|
|
9
|
-
for (const
|
|
10
|
-
this._inner
|
|
12
|
+
this._inner = new kernel.Governance(this._defaultAction);
|
|
13
|
+
for (const fn_ of this._pendingCalls)
|
|
14
|
+
fn_(this._inner);
|
|
15
|
+
this._pendingCalls = [];
|
|
11
16
|
}
|
|
12
|
-
|
|
17
|
+
_apply(fn) {
|
|
13
18
|
if (this._inner)
|
|
14
|
-
this._inner
|
|
19
|
+
fn(this._inner);
|
|
15
20
|
else
|
|
16
|
-
this.
|
|
21
|
+
this._pendingCalls.push(fn);
|
|
17
22
|
return this;
|
|
18
23
|
}
|
|
24
|
+
setIdentity(agentId, sessionId) {
|
|
25
|
+
return this._apply(g => g.setIdentity(agentId, sessionId));
|
|
26
|
+
}
|
|
27
|
+
addPermissionRule(pattern, action) {
|
|
28
|
+
return this._apply(g => g.addPermissionRule(pattern, action));
|
|
29
|
+
}
|
|
30
|
+
blockTool(name) {
|
|
31
|
+
return this._apply(g => g.blockTool(name));
|
|
32
|
+
}
|
|
33
|
+
setRateLimit(toolName, maxCalls, windowMs) {
|
|
34
|
+
return this._apply(g => g.setRateLimit(toolName, maxCalls, windowMs));
|
|
35
|
+
}
|
|
36
|
+
requireParam(toolName, paramPath) {
|
|
37
|
+
return this._apply(g => g.requireParam(toolName, paramPath));
|
|
38
|
+
}
|
|
39
|
+
allowParamValues(toolName, paramPath, allowedValues) {
|
|
40
|
+
return this._apply(g => g.allowParamValues(toolName, paramPath, allowedValues));
|
|
41
|
+
}
|
|
42
|
+
limitParamRange(toolName, paramPath, min, max) {
|
|
43
|
+
return this._apply(g => g.limitParamRange(toolName, paramPath, min, max));
|
|
44
|
+
}
|
|
19
45
|
setTime(nowMs) {
|
|
20
|
-
this.
|
|
21
|
-
return this;
|
|
46
|
+
return this._apply(g => g.setTime(nowMs));
|
|
22
47
|
}
|
|
23
48
|
evaluate(toolName, argsJson) {
|
|
24
49
|
if (!this._inner)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { RuntimeRunner, collectText, InMemorySessionLog, LocalExecutionPlane, } from "./runtime/index.js";
|
|
2
2
|
export type { RuntimeOptions, SessionEvent, SessionLog, RunContext, ExecutionPlane, } from "./runtime/index.js";
|
|
3
|
+
export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
|
|
4
|
+
export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
|
|
5
|
+
export type { SubAgentRunContext } from "./runtime/sub-agent-orchestrator.js";
|
|
6
|
+
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentSpawnedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, } from "./runtime/types/agent.js";
|
|
3
7
|
export { Governance } from "./governance.js";
|
|
4
8
|
export type { GovernanceVerdict } from "./governance.js";
|
|
5
9
|
export { AnthropicProvider } from "./providers/anthropic.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { RuntimeRunner, collectText, InMemorySessionLog, LocalExecutionPlane, } from "./runtime/index.js";
|
|
2
|
+
export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
|
|
3
|
+
export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
|
|
2
4
|
export { Governance } from "./governance.js";
|
|
3
5
|
export { AnthropicProvider } from "./providers/anthropic.js";
|
|
4
6
|
export { OpenAIProvider, QwenProvider, DeepSeekProvider, MiniMaxProvider, KimiProvider } from "./providers/openai.js";
|
|
@@ -27,18 +27,18 @@ export class LocalExecutionPlane {
|
|
|
27
27
|
ctx.governance.setTime(Date.now());
|
|
28
28
|
const v = ctx.governance.evaluate(c.name, c.arguments);
|
|
29
29
|
if (v.kind === "deny") {
|
|
30
|
-
yield { type: "
|
|
31
|
-
yield { type: "tool_result", callId: c.id, name: c.name, content: `permission denied: ${v.reason ?? ""}`, isError: true };
|
|
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
32
|
continue;
|
|
33
33
|
}
|
|
34
34
|
if (v.kind === "rate_limited") {
|
|
35
|
-
yield { type: "
|
|
36
|
-
yield { type: "tool_result", callId: c.id, name: c.name, content: "rate limited", isError: true };
|
|
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
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
if (v.kind === "ask_user") {
|
|
40
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 };
|
|
41
|
+
yield { type: "tool_result", callId: c.id, name: c.name, content: "awaiting user approval", isError: true, isFatal: false, errorKind: "recoverable" };
|
|
42
42
|
continue;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -84,7 +84,7 @@ export class LocalExecutionPlane {
|
|
|
84
84
|
for (const call of regularCalls) {
|
|
85
85
|
const registered = this.tools.get(call.name);
|
|
86
86
|
if (!registered) {
|
|
87
|
-
yield { type: "tool_result", callId: call.id, name: call.name, content: `unknown tool: ${call.name}`, isError: true };
|
|
87
|
+
yield { type: "tool_result", callId: call.id, name: call.name, content: `unknown tool: ${call.name}`, isError: true, isFatal: false, errorKind: "recoverable" };
|
|
88
88
|
continue;
|
|
89
89
|
}
|
|
90
90
|
try {
|
|
@@ -93,7 +93,15 @@ export class LocalExecutionPlane {
|
|
|
93
93
|
yield { type: "tool_result", callId: call.id, name: call.name, content: String(output), isError: false };
|
|
94
94
|
}
|
|
95
95
|
catch (err) {
|
|
96
|
-
yield {
|
|
96
|
+
yield {
|
|
97
|
+
type: "tool_result",
|
|
98
|
+
callId: call.id,
|
|
99
|
+
name: call.name,
|
|
100
|
+
content: String(err),
|
|
101
|
+
isError: true,
|
|
102
|
+
isFatal: Boolean(err?.isFatal),
|
|
103
|
+
errorKind: err?.errorKind,
|
|
104
|
+
};
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
107
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolCall, ToolSchema, StreamEvent } from "../types.js";
|
|
2
|
+
import type { RegisteredTool } from "../tools/index.js";
|
|
3
|
+
import type { ExecutionPlane, RunContext } from "./execution-plane.js";
|
|
4
|
+
/** Wraps an execution plane, allowing only manifest-permitted tool IDs (+ meta-tools). */
|
|
5
|
+
export declare class FilteredExecutionPlane implements ExecutionPlane {
|
|
6
|
+
private readonly inner;
|
|
7
|
+
private readonly permittedIds;
|
|
8
|
+
private readonly metaTools;
|
|
9
|
+
constructor(inner: ExecutionPlane, permittedIds: Set<string>, metaTools?: Set<string>);
|
|
10
|
+
register(...tools: RegisteredTool[]): this;
|
|
11
|
+
unregister(name: string): this;
|
|
12
|
+
schemas(): ToolSchema[];
|
|
13
|
+
executeAll(calls: ToolCall[], ctx: RunContext): AsyncIterable<StreamEvent>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const DEFAULT_META_TOOLS = new Set(["skill", "memory", "knowledge", "update_plan"]);
|
|
2
|
+
/** Wraps an execution plane, allowing only manifest-permitted tool IDs (+ meta-tools). */
|
|
3
|
+
export class FilteredExecutionPlane {
|
|
4
|
+
inner;
|
|
5
|
+
permittedIds;
|
|
6
|
+
metaTools;
|
|
7
|
+
constructor(inner, permittedIds, metaTools = DEFAULT_META_TOOLS) {
|
|
8
|
+
this.inner = inner;
|
|
9
|
+
this.permittedIds = permittedIds;
|
|
10
|
+
this.metaTools = metaTools;
|
|
11
|
+
}
|
|
12
|
+
register(...tools) {
|
|
13
|
+
this.inner.register(...tools);
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
unregister(name) {
|
|
17
|
+
this.inner.unregister(name);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
schemas() {
|
|
21
|
+
return this.inner.schemas().filter(s => this.permittedIds.has(s.name) || this.metaTools.has(s.name));
|
|
22
|
+
}
|
|
23
|
+
async *executeAll(calls, ctx) {
|
|
24
|
+
const permitted = [];
|
|
25
|
+
for (const call of calls) {
|
|
26
|
+
if (this.metaTools.has(call.name) || this.permittedIds.has(call.name)) {
|
|
27
|
+
permitted.push(call);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const reason = `capability not permitted for sub-agent: ${call.name}`;
|
|
31
|
+
yield { type: "tool_denied", callId: call.id, toolName: call.name, reason };
|
|
32
|
+
yield {
|
|
33
|
+
type: "tool_result",
|
|
34
|
+
callId: call.id,
|
|
35
|
+
name: call.name,
|
|
36
|
+
content: reason,
|
|
37
|
+
isError: true,
|
|
38
|
+
errorKind: "governance_denied",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (permitted.length > 0) {
|
|
42
|
+
yield* this.inner.executeAll(permitted, ctx);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Message, RenderedContext, ToolCall, ToolResult, ToolSchema } from "../types.js";
|
|
2
|
+
import type { RollbackReason } from "./session-log.js";
|
|
3
|
+
interface TaskUpdate {
|
|
4
|
+
plan?: string[];
|
|
5
|
+
currentStep?: number;
|
|
6
|
+
progress?: string;
|
|
7
|
+
scratchpad?: string;
|
|
8
|
+
blockedOn?: string[];
|
|
9
|
+
preservedRefs?: string[];
|
|
10
|
+
}
|
|
11
|
+
interface SkillMetadata {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
whenToUse?: string;
|
|
15
|
+
effort?: number;
|
|
16
|
+
estimatedTokens?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare const KERNEL_ABI_VERSION = 1;
|
|
19
|
+
export interface KernelRuntimeHandle {
|
|
20
|
+
step(inputJson: string): string;
|
|
21
|
+
isTerminal(): boolean;
|
|
22
|
+
turn(): number;
|
|
23
|
+
recoveryContentBytes(): number;
|
|
24
|
+
render(): RenderedContext;
|
|
25
|
+
drainNewMessages(): Message[];
|
|
26
|
+
preservedRefs(): string[];
|
|
27
|
+
}
|
|
28
|
+
export interface KernelLoopResult {
|
|
29
|
+
termination: string;
|
|
30
|
+
turnsUsed: number;
|
|
31
|
+
totalTokensUsed: number;
|
|
32
|
+
}
|
|
33
|
+
export type KernelRunnerAction = {
|
|
34
|
+
kind: "call_provider";
|
|
35
|
+
context: RenderedContext;
|
|
36
|
+
tools: ToolSchema[];
|
|
37
|
+
} | {
|
|
38
|
+
kind: "execute_tool";
|
|
39
|
+
calls: ToolCall[];
|
|
40
|
+
} | {
|
|
41
|
+
kind: "evaluate_milestone";
|
|
42
|
+
phaseId: string;
|
|
43
|
+
criteria: string[];
|
|
44
|
+
requiredEvidence?: string[];
|
|
45
|
+
} | {
|
|
46
|
+
kind: "done";
|
|
47
|
+
result: KernelLoopResult;
|
|
48
|
+
};
|
|
49
|
+
export interface KernelObservation {
|
|
50
|
+
kind: string;
|
|
51
|
+
action?: string;
|
|
52
|
+
rho_after?: number;
|
|
53
|
+
sprint?: number;
|
|
54
|
+
summary?: string;
|
|
55
|
+
archived?: Message[];
|
|
56
|
+
turn?: number;
|
|
57
|
+
checkpoint_history_len?: number;
|
|
58
|
+
added?: string[];
|
|
59
|
+
removed?: string[];
|
|
60
|
+
change_kind?: string;
|
|
61
|
+
capability_id?: string;
|
|
62
|
+
version?: string;
|
|
63
|
+
mounted_by?: string;
|
|
64
|
+
mount_reason?: string;
|
|
65
|
+
phase_id?: string;
|
|
66
|
+
capabilities_unlocked?: string[];
|
|
67
|
+
evidence?: string[];
|
|
68
|
+
reason?: RollbackReason;
|
|
69
|
+
agent_id?: string;
|
|
70
|
+
parent_session_id?: string;
|
|
71
|
+
role?: string;
|
|
72
|
+
isolation?: string;
|
|
73
|
+
context_inheritance?: string;
|
|
74
|
+
permitted_capability_ids?: string[];
|
|
75
|
+
history_len?: number;
|
|
76
|
+
}
|
|
77
|
+
export declare function toolSchemaToKernel(schema: ToolSchema): Record<string, unknown>;
|
|
78
|
+
export declare function skillMetadataToKernel(skill: SkillMetadata): Record<string, unknown>;
|
|
79
|
+
export declare function messageToKernelMessage(message: Message): Record<string, unknown>;
|
|
80
|
+
export declare function toolResultToKernel(result: ToolResult): Record<string, unknown>;
|
|
81
|
+
export declare function taskUpdateToKernel(update: TaskUpdate): Record<string, unknown>;
|
|
82
|
+
export declare function capabilityTool(schema: ToolSchema): Record<string, unknown>;
|
|
83
|
+
export declare function capabilitySkill(skill: SkillMetadata): Record<string, unknown>;
|
|
84
|
+
export declare function capabilityMarker(kind: string, id: string, description: string): Record<string, unknown>;
|
|
85
|
+
export declare function kernelApply(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelObservation[];
|
|
86
|
+
export declare function kernelAction(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelRunnerAction;
|
|
87
|
+
export declare function forceCompact(runtime: KernelRuntimeHandle, pending: KernelObservation[]): boolean;
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
export const KERNEL_ABI_VERSION = 1;
|
|
2
|
+
function tryParseJson(s) {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(s);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function toolSchemaToKernel(schema) {
|
|
11
|
+
return {
|
|
12
|
+
name: schema.name,
|
|
13
|
+
description: schema.description,
|
|
14
|
+
parameters: tryParseJson(schema.parameters) ?? {},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function skillMetadataToKernel(skill) {
|
|
18
|
+
const out = {
|
|
19
|
+
name: skill.name,
|
|
20
|
+
description: skill.description,
|
|
21
|
+
estimated_tokens: skill.estimatedTokens ?? 0,
|
|
22
|
+
};
|
|
23
|
+
if (skill.whenToUse)
|
|
24
|
+
out.when_to_use = skill.whenToUse;
|
|
25
|
+
if (skill.effort !== undefined)
|
|
26
|
+
out.effort = skill.effort;
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
export function messageToKernelMessage(message) {
|
|
30
|
+
const out = {
|
|
31
|
+
role: message.role,
|
|
32
|
+
tool_calls: (message.toolCalls ?? []).map(tc => ({
|
|
33
|
+
id: tc.id,
|
|
34
|
+
name: tc.name,
|
|
35
|
+
arguments: tryParseJson(tc.arguments) ?? {},
|
|
36
|
+
})),
|
|
37
|
+
};
|
|
38
|
+
if (message.tokenCount !== undefined) {
|
|
39
|
+
out.token_count = message.tokenCount;
|
|
40
|
+
}
|
|
41
|
+
out.content = message.content;
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
export function toolResultToKernel(result) {
|
|
45
|
+
const out = {
|
|
46
|
+
call_id: result.callId,
|
|
47
|
+
output: result.output,
|
|
48
|
+
is_error: result.isError,
|
|
49
|
+
is_fatal: result.isFatal ?? false,
|
|
50
|
+
token_count: result.tokenCount ?? null,
|
|
51
|
+
};
|
|
52
|
+
if (result.errorKind !== undefined) {
|
|
53
|
+
out.error_kind = result.errorKind;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
export function taskUpdateToKernel(update) {
|
|
58
|
+
return {
|
|
59
|
+
plan: update.plan,
|
|
60
|
+
current_step: update.currentStep,
|
|
61
|
+
progress: update.progress,
|
|
62
|
+
scratchpad: update.scratchpad,
|
|
63
|
+
blocked_on: update.blockedOn,
|
|
64
|
+
preserved_refs: update.preservedRefs,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function capabilityTool(schema) {
|
|
68
|
+
return {
|
|
69
|
+
id: schema.name,
|
|
70
|
+
kind: "tool",
|
|
71
|
+
description: schema.description,
|
|
72
|
+
tool_schema: toolSchemaToKernel(schema),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function capabilitySkill(skill) {
|
|
76
|
+
return {
|
|
77
|
+
id: skill.name,
|
|
78
|
+
kind: "skill",
|
|
79
|
+
description: skill.description,
|
|
80
|
+
skill: skillMetadataToKernel(skill),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function capabilityMarker(kind, id, description) {
|
|
84
|
+
return { id, kind, description };
|
|
85
|
+
}
|
|
86
|
+
function parseStep(raw) {
|
|
87
|
+
return JSON.parse(raw);
|
|
88
|
+
}
|
|
89
|
+
function kernelMessageToSdk(raw) {
|
|
90
|
+
const content = raw.content;
|
|
91
|
+
const message = {
|
|
92
|
+
role: raw.role,
|
|
93
|
+
content: typeof content === "string"
|
|
94
|
+
? content
|
|
95
|
+
: Array.isArray(content)
|
|
96
|
+
? content
|
|
97
|
+
.filter((part) => {
|
|
98
|
+
return typeof part === "object" && part !== null && part.type === "text";
|
|
99
|
+
})
|
|
100
|
+
.map(part => String(part.text ?? ""))
|
|
101
|
+
.join("")
|
|
102
|
+
: "",
|
|
103
|
+
toolCalls: (raw.tool_calls ?? []).map(tc => ({
|
|
104
|
+
id: String(tc.id ?? ""),
|
|
105
|
+
name: String(tc.name ?? ""),
|
|
106
|
+
arguments: JSON.stringify(tc.arguments ?? {}),
|
|
107
|
+
})),
|
|
108
|
+
};
|
|
109
|
+
if (typeof raw.token_count === "number") {
|
|
110
|
+
message.tokenCount = raw.token_count;
|
|
111
|
+
}
|
|
112
|
+
return message;
|
|
113
|
+
}
|
|
114
|
+
function renderedContextToSdk(raw) {
|
|
115
|
+
return {
|
|
116
|
+
systemText: String(raw.system_text ?? raw.systemText ?? ""),
|
|
117
|
+
turns: (raw.turns ?? []).map(kernelMessageToSdk),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function mapKernelAction(raw) {
|
|
121
|
+
switch (raw.kind) {
|
|
122
|
+
case "call_provider":
|
|
123
|
+
return {
|
|
124
|
+
kind: "call_provider",
|
|
125
|
+
context: renderedContextToSdk(raw.context ?? {}),
|
|
126
|
+
tools: (raw.tools ?? []).map(t => ({
|
|
127
|
+
name: String(t.name ?? ""),
|
|
128
|
+
description: String(t.description ?? ""),
|
|
129
|
+
parameters: JSON.stringify(t.parameters ?? {}),
|
|
130
|
+
})),
|
|
131
|
+
};
|
|
132
|
+
case "execute_tool":
|
|
133
|
+
return {
|
|
134
|
+
kind: "execute_tool",
|
|
135
|
+
calls: (raw.calls ?? []).map(c => ({
|
|
136
|
+
id: String(c.id ?? ""),
|
|
137
|
+
name: String(c.name ?? ""),
|
|
138
|
+
arguments: JSON.stringify(c.arguments ?? {}),
|
|
139
|
+
})),
|
|
140
|
+
};
|
|
141
|
+
case "evaluate_milestone":
|
|
142
|
+
return {
|
|
143
|
+
kind: "evaluate_milestone",
|
|
144
|
+
phaseId: String(raw.phase_id ?? ""),
|
|
145
|
+
criteria: raw.criteria ?? [],
|
|
146
|
+
requiredEvidence: raw.required_evidence ?? [],
|
|
147
|
+
};
|
|
148
|
+
case "done": {
|
|
149
|
+
const result = raw.result ?? {};
|
|
150
|
+
return {
|
|
151
|
+
kind: "done",
|
|
152
|
+
result: {
|
|
153
|
+
termination: String(result.termination ?? "error"),
|
|
154
|
+
turnsUsed: Number(result.turns_used ?? 0),
|
|
155
|
+
totalTokensUsed: Number(result.total_tokens_used ?? 0),
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
default:
|
|
160
|
+
throw new Error(`unknown KernelAction kind: ${String(raw.kind)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function stepInput(event) {
|
|
164
|
+
return JSON.stringify({ version: KERNEL_ABI_VERSION, event });
|
|
165
|
+
}
|
|
166
|
+
export function kernelApply(runtime, pending, event) {
|
|
167
|
+
const step = parseStep(runtime.step(stepInput(event)));
|
|
168
|
+
pending.push(...step.observations);
|
|
169
|
+
return step.observations;
|
|
170
|
+
}
|
|
171
|
+
export function kernelAction(runtime, pending, event) {
|
|
172
|
+
const step = parseStep(runtime.step(stepInput(event)));
|
|
173
|
+
pending.push(...step.observations);
|
|
174
|
+
const raw = step.actions[0];
|
|
175
|
+
if (!raw)
|
|
176
|
+
throw new Error("kernel transition must return one action");
|
|
177
|
+
return mapKernelAction(raw);
|
|
178
|
+
}
|
|
179
|
+
export function forceCompact(runtime, pending) {
|
|
180
|
+
return kernelApply(runtime, pending, { kind: "force_compact" }).some(o => o.kind === "compressed");
|
|
181
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { effectiveProviderReplay } from "./session-repair.js";
|
|
1
2
|
export function assistantReplayKey(message) {
|
|
2
3
|
return JSON.stringify({
|
|
3
4
|
content: message.content,
|
|
@@ -8,9 +9,13 @@ export function seedProviderReplayFromEvents(provider, events) {
|
|
|
8
9
|
if (!provider.seedProviderReplay)
|
|
9
10
|
return;
|
|
10
11
|
for (const { event } of events) {
|
|
11
|
-
if (event.kind !== "llm_completed"
|
|
12
|
+
if (event.kind !== "llm_completed")
|
|
12
13
|
continue;
|
|
13
|
-
|
|
14
|
+
const toolCalls = event.tool_calls ?? [];
|
|
15
|
+
const replay = effectiveProviderReplay(event.content, toolCalls, event.provider_replay);
|
|
16
|
+
if (!replay)
|
|
17
|
+
continue;
|
|
18
|
+
provider.seedProviderReplay({ content: event.content, toolCalls }, replay);
|
|
14
19
|
}
|
|
15
20
|
}
|
|
16
21
|
export function peekProviderReplay(provider, content, toolCalls) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** UTF-8-safe text helpers for session replay (defense in depth). */
|
|
2
|
+
export declare const REPLAY_CONTENT_MAX_BYTES = 32768;
|
|
3
|
+
export declare function truncateBytesAtCharBoundary(text: string, maxBytes: number): string;
|
|
4
|
+
export declare function sanitizeReplayText(text: string, maxBytes?: number): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** UTF-8-safe text helpers for session replay (defense in depth). */
|
|
2
|
+
export const REPLAY_CONTENT_MAX_BYTES = 32_768;
|
|
3
|
+
export function truncateBytesAtCharBoundary(text, maxBytes) {
|
|
4
|
+
const data = new TextEncoder().encode(text);
|
|
5
|
+
if (data.length <= maxBytes)
|
|
6
|
+
return text;
|
|
7
|
+
let end = maxBytes;
|
|
8
|
+
while (end > 0) {
|
|
9
|
+
try {
|
|
10
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(data.subarray(0, end));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
end -= 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
export function sanitizeReplayText(text, maxBytes = REPLAY_CONTENT_MAX_BYTES) {
|
|
19
|
+
if (!text)
|
|
20
|
+
return text;
|
|
21
|
+
const bytes = new TextEncoder().encode(text);
|
|
22
|
+
if (bytes.length <= maxBytes)
|
|
23
|
+
return text;
|
|
24
|
+
const prefix = truncateBytesAtCharBoundary(text, maxBytes);
|
|
25
|
+
return `${prefix}… [replay truncated]`;
|
|
26
|
+
}
|
package/dist/runtime/runner.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { LLMProvider, StreamEvent } from "../types.js";
|
|
1
|
+
import type { LLMProvider, Message, StreamEvent } from "../types.js";
|
|
2
2
|
import type { ToolSuspendEvent } from "./execution-plane.js";
|
|
3
3
|
import type { DreamStore, DreamResult } from "../memory/index.js";
|
|
4
4
|
import type { KnowledgeSource } from "../knowledge/index.js";
|
|
5
5
|
import type { SignalSource } from "../signals/index.js";
|
|
6
|
-
import type { SessionLog } from "./session-log.js";
|
|
6
|
+
import type { SessionLog, SessionEvent } from "./session-log.js";
|
|
7
7
|
import type { ExecutionPlane } from "./execution-plane.js";
|
|
8
8
|
import type { Governance } from "../governance.js";
|
|
9
|
+
import type { AgentRunSpec, SubAgentResult, MilestonePolicy, MilestoneContract, MilestoneCheckResult } from "./types/agent.js";
|
|
10
|
+
import { type SubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
9
11
|
export interface RuntimeOptions {
|
|
10
12
|
provider: LLMProvider;
|
|
11
13
|
sessionLog: SessionLog;
|
|
@@ -24,21 +26,42 @@ export interface RuntimeOptions {
|
|
|
24
26
|
extensions?: Record<string, unknown>;
|
|
25
27
|
governance?: Governance;
|
|
26
28
|
onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
|
|
29
|
+
subAgentOrchestrator?: SubAgentOrchestrator;
|
|
30
|
+
milestonePolicy?: MilestonePolicy;
|
|
31
|
+
milestoneContract?: MilestoneContract;
|
|
32
|
+
onMilestoneEvaluate?: (ctx: {
|
|
33
|
+
phaseId: string;
|
|
34
|
+
criteria: string[];
|
|
35
|
+
requiredEvidence: string[];
|
|
36
|
+
}) => Promise<MilestoneCheckResult> | MilestoneCheckResult;
|
|
37
|
+
runSpec?: AgentRunSpec;
|
|
27
38
|
}
|
|
28
39
|
export declare class RuntimeRunner {
|
|
29
40
|
private readonly opts;
|
|
30
41
|
private interrupted;
|
|
42
|
+
private pendingObservations;
|
|
43
|
+
private activeKernel;
|
|
44
|
+
private currentSessionId;
|
|
45
|
+
private nextArchiveStart;
|
|
31
46
|
constructor(opts: RuntimeOptions);
|
|
47
|
+
get hostOptions(): RuntimeOptions;
|
|
32
48
|
interrupt(): void;
|
|
33
49
|
run(req: {
|
|
34
50
|
sessionId: string;
|
|
35
51
|
goal: string;
|
|
36
52
|
criteria?: string[];
|
|
37
53
|
extensions?: Record<string, unknown>;
|
|
54
|
+
inheritEvents?: Array<{
|
|
55
|
+
seq: number;
|
|
56
|
+
event: SessionEvent;
|
|
57
|
+
}>;
|
|
38
58
|
}): AsyncIterable<StreamEvent>;
|
|
39
59
|
wake(sessionId: string, extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
|
|
60
|
+
/** Push a large artifact into the kernel artifacts partition (not inlined in history). */
|
|
61
|
+
pushArtifact(message: Message, tokens?: number): void;
|
|
40
62
|
dream(agentId: string, nowMs?: number): Promise<DreamResult>;
|
|
41
63
|
private execute;
|
|
64
|
+
spawnSubAgent(spec: AgentRunSpec): Promise<SubAgentResult>;
|
|
42
65
|
private appendObservations;
|
|
43
66
|
}
|
|
44
67
|
export declare function collectText(stream: AsyncIterable<StreamEvent>): Promise<string>;
|