@sema-agent/core 5.1.0 → 5.3.0

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/agents/roster-store.js +6 -1
  3. package/dist/bin/sema-tb.js +3 -4
  4. package/dist/brain/openai.js +3 -5
  5. package/dist/brain/terminal-cause.d.ts +1 -1
  6. package/dist/core/a2a-task-state.d.ts +15 -0
  7. package/dist/core/a2a-task-state.js +68 -0
  8. package/dist/core/a2a.d.ts +42 -0
  9. package/dist/core/a2a.js +651 -0
  10. package/dist/core/checkpoint-store.d.ts +6 -1
  11. package/dist/core/checkpoint-store.js +3 -1
  12. package/dist/core/hooks.js +8 -3
  13. package/dist/core/mcp.d.ts +12 -5
  14. package/dist/core/mcp.js +11 -31
  15. package/dist/core/memory-engine/dual-root.js +2 -1
  16. package/dist/core/memory-engine/engine.d.ts +4 -0
  17. package/dist/core/memory-engine/engine.js +25 -6
  18. package/dist/core/memory-engine/file-backend.d.ts +7 -5
  19. package/dist/core/memory-engine/file-backend.js +2 -2
  20. package/dist/core/memory-engine/index.d.ts +1 -1
  21. package/dist/core/memory-engine/index.js +1 -1
  22. package/dist/core/memory-engine/layout.d.ts +6 -2
  23. package/dist/core/memory-engine/layout.js +73 -31
  24. package/dist/core/memory.js +6 -0
  25. package/dist/core/protocol-naming.d.ts +7 -0
  26. package/dist/core/protocol-naming.js +32 -0
  27. package/dist/core/protocol-table.d.ts +13 -8
  28. package/dist/core/protocol-table.js +34 -15
  29. package/dist/core/runner/prepare-memory.js +4 -4
  30. package/dist/core/runner/prepare-task.d.ts +7 -0
  31. package/dist/core/runner/prepare-task.js +73 -28
  32. package/dist/core/runner/runtask.js +42 -9
  33. package/dist/core/runner/tool-disclosure.d.ts +1 -1
  34. package/dist/core/runner/tool-disclosure.js +7 -2
  35. package/dist/core/runner/turn-attachments.d.ts +1 -2
  36. package/dist/core/runner/turn-attachments.js +1 -12
  37. package/dist/core/store-contracts/background-agent-store-contract.d.ts +5 -0
  38. package/dist/core/store-contracts/background-agent-store-contract.js +213 -0
  39. package/dist/core/task-registry-agent.d.ts +14 -1
  40. package/dist/core/task-registry-agent.js +1 -1
  41. package/dist/core/tool-policy.d.ts +1 -0
  42. package/dist/core/tool-policy.js +12 -2
  43. package/dist/core/types.d.ts +16 -2
  44. package/dist/index.d.ts +10 -5
  45. package/dist/index.js +7 -3
  46. package/dist/orchestration/run-workflow-tool.js +5 -1
  47. package/dist/prompt-assembly/assemble.js +0 -1
  48. package/dist/prompt-assembly/event-registry.js +1 -0
  49. package/dist/stores/cc/mailbox-store.js +58 -14
  50. package/dist/stores/file/file-snapshot-store.d.ts +9 -1
  51. package/dist/stores/file/file-snapshot-store.js +28 -5
  52. package/dist/stores/file/fs-atomic.d.ts +4 -1
  53. package/dist/stores/file/fs-atomic.js +2 -1
  54. package/dist/stores/file/index.d.ts +10 -3
  55. package/dist/stores/file/index.js +4 -3
  56. package/dist/stores/file/mailbox-store.d.ts +5 -0
  57. package/dist/stores/file/mailbox-store.js +15 -3
  58. package/dist/stores/file/session-policy-store.d.ts +11 -8
  59. package/dist/stores/file/session-policy-store.js +21 -4
  60. package/dist/stores/file/session-store.d.ts +9 -1
  61. package/dist/stores/file/session-store.js +19 -4
  62. package/dist/tools/fs/fs-search-tools.js +9 -0
  63. package/dist/tools/fs/fs-shared.d.ts +1 -1
  64. package/dist/tools/fs/fs-shared.js +1 -1
  65. package/dist/tools/todo.js +13 -6
  66. package/package.json +1 -1
@@ -15,7 +15,7 @@ export declare const TOOL_SEARCH_REMINDER_CONFIG: {
15
15
  export declare const CHANGED_FILES_MAX = 20;
16
16
  export declare const CHANGED_FILES_MTIME_EPS_MS = 2000;
17
17
  export declare const ATTACHMENT_BYTE_CAP: number;
18
- export type AttachmentSource = "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
18
+ export type AttachmentSource = "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
19
19
  export interface AgentListingEntry {
20
20
  name: string;
21
21
  description: string;
@@ -31,7 +31,6 @@ export interface TurnAttachment {
31
31
  body: string;
32
32
  }
33
33
  export interface ListProjection {
34
- statusCounts: Record<string, number>;
35
34
  items: Array<{
36
35
  content: string;
37
36
  status: string;
@@ -47,12 +47,7 @@ export function reduceToolEnd(state, details) {
47
47
  : [];
48
48
  });
49
49
  const allDone = shaped.length > 0 && shaped.every((t) => t.status === "completed");
50
- state.todo = allDone
51
- ? { statusCounts: {}, items: [] }
52
- : {
53
- statusCounts: countStatuses(shaped),
54
- items: shaped.slice(0, PROJECTION_ITEMS_MAX),
55
- };
50
+ state.todo = allDone ? { items: [] } : { items: shaped.slice(0, PROJECTION_ITEMS_MAX) };
56
51
  }
57
52
  else if (d.type === "task") {
58
53
  const map = state.taskItems ?? (state.taskItems = new Map());
@@ -120,12 +115,6 @@ export function rebaseCadenceWindows(state, clock) {
120
115
  state.toolSearchLastUseTurn = clock;
121
116
  state.lastToolSearchReminderTurn = clock;
122
117
  }
123
- function countStatuses(items) {
124
- const counts = {};
125
- for (const t of items)
126
- counts[t.status] = (counts[t.status] ?? 0) + 1;
127
- return counts;
128
- }
129
118
  const EMPTY = Object.freeze([]);
130
119
  export function collectDueAttachments(state, inp) {
131
120
  let out;
@@ -0,0 +1,5 @@
1
+ import { type BackgroundAgentStore } from "../background-agent-store.js";
2
+ import { type ContractAssertionRunner } from "./contract-harness.js";
3
+ export declare const BACKGROUND_AGENT_CONTRACT_SCOPE = "tenant-A";
4
+ export declare function backgroundAgentStoreContract(mk: () => BackgroundAgentStore, runAssertion?: ContractAssertionRunner): Promise<void>;
5
+ export declare function backgroundAgentStoreScopesContract(mk: () => BackgroundAgentStore, runAssertion?: ContractAssertionRunner): Promise<void>;
@@ -0,0 +1,213 @@
1
+ import { strict as assert } from "node:assert";
2
+ import { STALE_RUNNING_REAP_ATTRIBUTION, } from "../background-agent-store.js";
3
+ import { beginContract } from "./contract-harness.js";
4
+ export const BACKGROUND_AGENT_CONTRACT_SCOPE = "tenant-A";
5
+ function record(over = {}) {
6
+ return {
7
+ handle: "a0000000000000001",
8
+ scope: BACKGROUND_AGENT_CONTRACT_SCOPE,
9
+ owner: "task-1",
10
+ sessionScoped: false,
11
+ parentSessionId: "sess-1",
12
+ writerId: "writer-1",
13
+ spawnedAt: 1_000,
14
+ updatedAt: 1_000,
15
+ status: "running",
16
+ rev: 0,
17
+ ...over,
18
+ };
19
+ }
20
+ async function withStores(mk, fn) {
21
+ const live = [];
22
+ const make = () => {
23
+ const s = mk();
24
+ live.push(s);
25
+ return s;
26
+ };
27
+ try {
28
+ await fn(make);
29
+ }
30
+ finally {
31
+ for (const s of live.splice(0))
32
+ s.close?.();
33
+ }
34
+ }
35
+ async function held(store, handle, scope = BACKGROUND_AGENT_CONTRACT_SCOPE) {
36
+ const row = await store.get(handle, scope);
37
+ assert.notEqual(row, null, `row ${handle} should exist in scope ${scope}`);
38
+ return row;
39
+ }
40
+ export async function backgroundAgentStoreContract(mk, runAssertion) {
41
+ const { run: runRaw, settle } = beginContract(runAssertion);
42
+ const run = (name, fn) => runRaw(name, () => withStores(mk, fn));
43
+ const S = BACKGROUND_AGENT_CONTRACT_SCOPE;
44
+ run("put is create-once and scope-partitioned; get round-trips the row and is null cross-scope", async (make) => {
45
+ const store = make();
46
+ await store.put(record({ handle: "a1", finalOutput: "result-text" }));
47
+ await assert.rejects(store.put(record({ handle: "a1" })), (e) => e.code === "agent_record.already_exists", "a second put under the same (handle, scope) must throw the typed already_exists error");
48
+ await store.put(record({ handle: "a1", scope: "tenant-B" }));
49
+ const row = await held(store, "a1");
50
+ assert.equal(row.finalOutput, "result-text");
51
+ assert.equal(row.owner, "task-1");
52
+ assert.equal(await store.get("a1", "tenant-C"), null, "an unrelated scope must not see the row");
53
+ assert.equal(await store.get("a-missing", S), null);
54
+ });
55
+ run("put refuses a scopeless row (a row with no tenant partition would be world-readable)", async (make) => {
56
+ const store = make();
57
+ await assert.rejects(store.put(record({ scope: "" })), "an empty scope must be refused loudly, not stored");
58
+ });
59
+ run("get returns DETACHED copies: mutating a read never reaches the stored row", async (make) => {
60
+ const store = make();
61
+ await store.put(record({ handle: "a1", usage: { totalTokens: 5 } }));
62
+ const first = await held(store, "a1");
63
+ first.status = "failed";
64
+ first.usage.totalTokens = 999;
65
+ const second = await held(store, "a1");
66
+ assert.equal(second.status, "running");
67
+ assert.equal(second.usage?.totalTokens, 5);
68
+ });
69
+ run("update is a rev-CAS: stale rev loses, wrong scope loses, the winner bumps rev by EXACTLY 1", async (make) => {
70
+ const store = make();
71
+ await store.put(record({ handle: "a1" }));
72
+ const row = await held(store, "a1");
73
+ assert.equal(await store.update("a1", "tenant-B", { ...row, status: "completed" }, { rev: row.rev }), false, "wrong scope");
74
+ assert.equal(await store.update("a1", S, { ...row, status: "completed" }, { rev: row.rev + 5 }), false, "rev ahead");
75
+ assert.equal(await store.update("a-missing", S, { ...row, status: "completed" }, { rev: row.rev }), false, "missing row");
76
+ assert.equal(await store.update("a1", S, { ...row, status: "completed" }, { rev: row.rev }), true);
77
+ const after = await held(store, "a1");
78
+ assert.equal(after.status, "completed");
79
+ assert.equal(after.rev, row.rev + 1);
80
+ assert.equal(await store.update("a1", S, { ...row, status: "failed" }, { rev: row.rev }), false);
81
+ assert.equal((await held(store, "a1")).status, "completed");
82
+ });
83
+ run("update keeps the KEY authoritative: a payload naming another handle/scope cannot repartition the row", async (make) => {
84
+ const store = make();
85
+ await store.put(record({ handle: "a1" }));
86
+ const row = await held(store, "a1");
87
+ assert.equal(await store.update("a1", S, { ...row, handle: "a-other", scope: "tenant-B", status: "failed" }, { rev: row.rev }), true);
88
+ const after = await held(store, "a1");
89
+ assert.equal(after.handle, "a1", "the key's handle wins over the payload's");
90
+ assert.equal(after.scope, S, "scope is the partition key and an update must never rewrite it");
91
+ assert.equal(await store.get("a-other", "tenant-B"), null, "no second row may appear");
92
+ });
93
+ run("updateIf keeps the rev guard AND adds the field guards (status / checkpoint token / claim id)", async (make) => {
94
+ const store = make();
95
+ await store.put(record({ handle: "a1", status: "parked", parkedCheckpointToken: "cp-1" }));
96
+ const row = await held(store, "a1");
97
+ assert.equal(await store.updateIf("a1", S, { ...row, status: "running" }, { rev: row.rev + 3 }), false, "stale rev");
98
+ assert.equal(await store.updateIf("a1", S, { ...row, status: "running" }, { rev: row.rev, status: "running" }), false, "status mismatch");
99
+ assert.equal(await store.updateIf("a1", S, { ...row, status: "running" }, { rev: row.rev, status: "parked", parkedCheckpointToken: "cp-OTHER" }), false, "checkpoint token mismatch");
100
+ assert.equal(await store.updateIf("a1", S, { ...row, status: "running" }, { rev: row.rev, parkedCheckpointToken: null }), false, "null must mean 'this field is absent', and it is present");
101
+ assert.equal(await store.updateIf("a1", S, { ...row, status: "running" }, { rev: row.rev, parkClaimId: "claim-1" }), false, "claim id expected but absent");
102
+ const next = { ...row, status: "running", parkClaimId: "claim-1" };
103
+ assert.equal(await store.updateIf("a1", S, next, { rev: row.rev, status: "parked", parkedCheckpointToken: "cp-1", parkClaimId: null }), true, "matching guards (incl. null-as-absent on the claim id) must win");
104
+ const after = await held(store, "a1");
105
+ assert.equal(after.status, "running");
106
+ assert.equal(after.parkClaimId, "claim-1");
107
+ assert.equal(after.rev, row.rev + 1);
108
+ });
109
+ run("listBySession anchors on (sessionScoped ? owner : parentSessionId) OR rootSessionId, newest-first", async (make) => {
110
+ const store = make();
111
+ await store.put(record({ handle: "a1", spawnedAt: 1_000, finalOutput: "SECRET", summary: "s", error: "e", recentSteps: [] }));
112
+ await store.put(record({ handle: "a2", owner: "sess-1", sessionScoped: true, parentSessionId: undefined, spawnedAt: 2_000 }));
113
+ await store.put(record({ handle: "a3", parentSessionId: "sess-mid", rootSessionId: "sess-1", spawnedAt: 3_000 }));
114
+ await store.put(record({ handle: "a4", parentSessionId: "sess-other", spawnedAt: 4_000 }));
115
+ const rows = await store.listBySession(S, "sess-1");
116
+ assert.deepEqual(rows.map((r) => r.handle), ["a3", "a2", "a1"], "newest-first by spawnedAt");
117
+ for (const row of rows) {
118
+ for (const field of ["finalOutput", "summary", "error", "recentSteps", "editedFiles"]) {
119
+ assert.equal(Object.hasOwn(row, field), false, `list projections must not carry ${field}`);
120
+ }
121
+ }
122
+ assert.deepEqual((await store.listBySession(S, "sess-1", { limit: 2 })).map((r) => r.handle), ["a3", "a2"], "limit keeps the NEWEST n");
123
+ assert.deepEqual(await store.listBySession("tenant-B", "sess-1"), [], "another tenant sees nothing");
124
+ assert.deepEqual((await store.listBySession(S, "sess-mid")).map((r) => r.handle), ["a3"], "the intermediate anchor still lists its direct child");
125
+ });
126
+ run("listBySession/listByScope filter one status; listByScope enumerates the whole tenant", async (make) => {
127
+ const store = make();
128
+ await store.put(record({ handle: "a1", status: "running", spawnedAt: 1_000 }));
129
+ await store.put(record({ handle: "a2", status: "completed", spawnedAt: 2_000 }));
130
+ await store.put(record({ handle: "a3", status: "completed", parentSessionId: "sess-other", spawnedAt: 3_000 }));
131
+ await store.put(record({ handle: "a4", status: "completed", scope: "tenant-B", spawnedAt: 4_000 }));
132
+ assert.deepEqual((await store.listByScope(S)).map((r) => r.handle), ["a3", "a2", "a1"], "scope-wide, newest-first");
133
+ assert.deepEqual((await store.listByScope(S, { status: "completed" })).map((r) => r.handle), ["a3", "a2"]);
134
+ assert.deepEqual((await store.listByScope(S, { status: "completed", limit: 1 })).map((r) => r.handle), ["a3"]);
135
+ assert.deepEqual((await store.listBySession(S, "sess-1", { status: "completed" })).map((r) => r.handle), ["a2"]);
136
+ assert.deepEqual((await store.listByScope("tenant-B")).map((r) => r.handle), ["a4"], "tenants are separate ledgers");
137
+ });
138
+ run("delete is row-precise and CONDITIONAL when a rev is supplied (a concurrent revival must win)", async (make) => {
139
+ const store = make();
140
+ await store.put(record({ handle: "a1", status: "completed" }));
141
+ await store.put(record({ handle: "a2", status: "completed" }));
142
+ const row = await held(store, "a1");
143
+ assert.equal(await store.delete("a1", S, { rev: row.rev + 1 }), false, "a stale rev must not delete");
144
+ assert.notEqual(await store.get("a1", S), null);
145
+ assert.equal(await store.delete("a1", "tenant-B"), false, "cross-scope delete is a miss");
146
+ assert.equal(await store.delete("a1", S, { rev: row.rev }), true);
147
+ assert.equal(await store.get("a1", S), null);
148
+ assert.equal(await store.delete("a1", S), false, "deleting a gone row reports false, not true");
149
+ assert.equal(await store.delete("a2", S), true, "an unconditional delete still works");
150
+ });
151
+ run("reap with NO policy is a no-op (retention is always explicit)", async (make) => {
152
+ const store = make();
153
+ await store.put(record({ handle: "a1", status: "completed", settledAt: 1_000 }));
154
+ assert.equal(await store.reap(S, 100_000), 0);
155
+ assert.equal(await store.reap(S, 100_000, {}), 0);
156
+ assert.notEqual(await store.get("a1", S), null);
157
+ });
158
+ run("reap deletes terminal rows by age and by keep-bound; running and parked rows survive BOTH", async (make) => {
159
+ const store = make();
160
+ await store.put(record({ handle: "a1", status: "completed", spawnedAt: 1_000, settledAt: 1_000 }));
161
+ await store.put(record({ handle: "a2", status: "running", spawnedAt: 1_000, updatedAt: 1_000 }));
162
+ await store.put(record({ handle: "a3", status: "parked", spawnedAt: 1_000, updatedAt: 1_000, parkedCheckpointToken: "cp-1" }));
163
+ assert.equal(await store.reap(S, 100_000, { maxAgeMs: 10 }), 1, "only the terminal row ages out");
164
+ assert.equal(await store.get("a1", S), null);
165
+ assert.equal((await held(store, "a2")).status, "running");
166
+ assert.equal((await held(store, "a3")).status, "parked");
167
+ for (const i of [1, 2, 3])
168
+ await store.put(record({ handle: `b${i}`, status: "completed", spawnedAt: 1_000 + i, settledAt: 2_000 + i }));
169
+ assert.equal(await store.reap(S, 100_000, { keep: 2 }), 1);
170
+ assert.deepEqual((await store.listByScope(S, { status: "completed" })).map((r) => r.handle), ["b3", "b2"]);
171
+ assert.notEqual(await store.get("a2", S), null);
172
+ assert.notEqual(await store.get("a3", S), null);
173
+ });
174
+ run("reap's stale-running arm flips to a terminal `failed` WITH the shared attribution, and never overwrites real failure text", async (make) => {
175
+ const store = make();
176
+ await store.put(record({ handle: "a1", status: "running", updatedAt: 1_000 }));
177
+ await store.put(record({ handle: "a2", status: "running", updatedAt: 1_000, error: "the child reported a real failure" }));
178
+ assert.equal(await store.reap(S, 100_000, { staleRunningMaxAgeMs: 50_000 }), 2);
179
+ const flipped = await held(store, "a1");
180
+ assert.equal(flipped.status, "failed", "an interrupted host's row settles as a terminal, not a perpetual running");
181
+ assert.equal(flipped.stoppedBy, "system");
182
+ assert.equal(flipped.settledAt, 100_000);
183
+ assert.equal(flipped.updatedAt, 100_000);
184
+ assert.equal(flipped.error, STALE_RUNNING_REAP_ATTRIBUTION);
185
+ assert.equal(flipped.summary, STALE_RUNNING_REAP_ATTRIBUTION);
186
+ assert.equal((await held(store, "a2")).error, "the child reported a real failure");
187
+ await store.put(record({ handle: "a3", status: "running", updatedAt: 99_000 }));
188
+ assert.equal(await store.reap(S, 100_000, { staleRunningMaxAgeMs: 50_000 }), 0);
189
+ assert.equal((await held(store, "a3")).status, "running");
190
+ });
191
+ run("reap counts each ROW once even when the same sweep flips it AND removes it", async (make) => {
192
+ const store = make();
193
+ await store.put(record({ handle: "a1", status: "running", spawnedAt: 1_000, updatedAt: 1_000 }));
194
+ assert.equal(await store.reap(S, 100_000, { staleRunningMaxAgeMs: 50_000, keep: 0 }), 1, "one row changed, so the count is 1");
195
+ assert.equal(await store.get("a1", S), null, "and it really is gone (flipped, then trimmed)");
196
+ });
197
+ await settle();
198
+ }
199
+ export async function backgroundAgentStoreScopesContract(mk, runAssertion) {
200
+ const { run: runRaw, settle } = beginContract(runAssertion);
201
+ const run = (name, fn) => runRaw(name, () => withStores(mk, fn));
202
+ run("listScopes enumerates the scopes that currently HOLD rows, deduplicated and sorted", async (make) => {
203
+ const store = make();
204
+ assert.equal(typeof store.listScopes, "function", "this layer is only for backends that implement listScopes");
205
+ await store.put(record({ handle: "a1", scope: "tenant-B" }));
206
+ await store.put(record({ handle: "a2", scope: "tenant-A" }));
207
+ await store.put(record({ handle: "a3", scope: "tenant-A" }));
208
+ assert.deepEqual(await store.listScopes(), ["tenant-A", "tenant-B"], "deduplicated and sorted — a retention loop drives itself off this");
209
+ await store.delete("a1", "tenant-B");
210
+ assert.deepEqual(await store.listScopes(), ["tenant-A"]);
211
+ });
212
+ await settle();
213
+ }
@@ -1,5 +1,5 @@
1
1
  import { type BackgroundAgentRecord, type BackgroundAgentStore } from "./background-agent-store.js";
2
- import { type StopSource, type TaskAccess, type UnifiedTaskResult, type BackgroundAgentTaskHandle, type DurableAgentCore, type ParkedClaimTicket, type RegisterBackgroundAgentInput } from "./task-registry-shared.js";
2
+ import { type StopSource, type TaskAccess, type TaskRetrievalStatus, type UnifiedTaskOutput, type UnifiedTaskResult, type BackgroundAgentTaskHandle, type DurableAgentCore, type ParkedClaimTicket, type RegisterBackgroundAgentInput } from "./task-registry-shared.js";
3
3
  import { type ToolResultStore } from "./tool-result-store.js";
4
4
  export declare function ensureDurableHeartbeatLane(core: DurableAgentCore): void;
5
5
  export declare function durableAgentWriteLane(handle: BackgroundAgentTaskHandle, patch: Partial<BackgroundAgentRecord>, clear?: readonly (keyof BackgroundAgentRecord)[]): void;
@@ -126,6 +126,19 @@ export declare function notFoundRunningAgentsTail(footer: {
126
126
  named: string[];
127
127
  background: string[];
128
128
  }): string;
129
+ export interface AgentPollDetailsInput {
130
+ taskId: string;
131
+ status: UnifiedTaskOutput["status"];
132
+ retrievalStatus: TaskRetrievalStatus;
133
+ seq?: number;
134
+ stoppedBy?: StopSource;
135
+ error?: string;
136
+ errorCode?: string;
137
+ errorRetryable?: boolean;
138
+ resultIsPartial?: boolean;
139
+ completionId?: string;
140
+ }
141
+ export declare function buildAgentPollDetails(input: AgentPollDetailsInput): UnifiedTaskOutput;
129
142
  export declare function serveDurableAgentRowLane(row: BackgroundAgentRecord): UnifiedTaskResult;
130
143
  export declare function spillClippedAgentResult(handle: BackgroundAgentTaskHandle, full: string, clipped: string, store: ToolResultStore | undefined, sessionId: string | undefined): Promise<string>;
131
144
  export declare function pollBackgroundAgentLane(handle: BackgroundAgentTaskHandle, deadline?: number, signal?: AbortSignal, oneShot?: boolean, store?: ToolResultStore, sessionId?: string): Promise<UnifiedTaskResult>;
@@ -1008,7 +1008,7 @@ export function notFoundRunningAgentsTail(footer) {
1008
1008
  return ((footer.named.length > 0 ? `. Running named agents: ${footer.named.join(", ")}` : "") +
1009
1009
  (footer.background.length > 0 ? `. Running background agents: ${footer.background.join(", ")}` : ""));
1010
1010
  }
1011
- function buildAgentPollDetails(input) {
1011
+ export function buildAgentPollDetails(input) {
1012
1012
  const failed = input.status === "failed";
1013
1013
  return {
1014
1014
  task_id: input.taskId,
@@ -30,6 +30,7 @@ export declare function decisionText(d: PermissionResult): string | undefined;
30
30
  export interface ToolPolicy {
31
31
  check(req: ToolCallRequest, signal?: AbortSignal): PermissionResult | Promise<PermissionResult>;
32
32
  }
33
+ export declare function refuseOutOfContractDecision(d: PermissionResult): PermissionResult;
33
34
  export interface ToolPolicyNameSets {
34
35
  readonly allow?: readonly string[];
35
36
  readonly deny?: readonly string[];
@@ -6,6 +6,16 @@ export function decisionText(d) {
6
6
  return d.message;
7
7
  }
8
8
  const ALLOW = { action: "allow" };
9
+ const RETIRED_TEXT_FIELD = "reason";
10
+ const RETIRED_TEXT_FIELD_DENY_MESSAGE = `a permission decision carries the retired "${RETIRED_TEXT_FIELD}" field — rename it to "message" (the one text field ` +
11
+ `a decision carries); denied fail-closed rather than executing a decision whose text this layer cannot read`;
12
+ export function refuseOutOfContractDecision(d) {
13
+ if (typeof d !== "object" || d === null)
14
+ return d;
15
+ if (!Object.prototype.hasOwnProperty.call(d, RETIRED_TEXT_FIELD))
16
+ return d;
17
+ return { action: "deny", message: RETIRED_TEXT_FIELD_DENY_MESSAGE, decisionReason: "rule" };
18
+ }
9
19
  function withTimeout(p, ms, onTimeout) {
10
20
  if (ms === undefined) {
11
21
  return p;
@@ -86,7 +96,7 @@ export function createApprovalPolicy(opts) {
86
96
  if (okRaw === true)
87
97
  return ALLOW;
88
98
  if (okRaw !== false) {
89
- return { action: "deny", message: `approval callback for "${req.toolName}" returned an out-of-contract value (${typeof ok}) — denied fail-closed (return true, false, or the {allow} object)` };
99
+ return { action: "deny", message: `approval callback for "${req.toolName}" returned an out-of-contract value (${typeof ok}) — denied fail-closed (this policy's \`approve\` returns a boolean: return true or false)` };
90
100
  }
91
101
  return { action: "deny", message: `approval denied for "${req.toolName}"` };
92
102
  }
@@ -106,7 +116,7 @@ export function combinePolicies(...policies) {
106
116
  let current = req;
107
117
  let rewrite;
108
118
  for (const p of policies) {
109
- const d = await p.check(current, signal);
119
+ const d = refuseOutOfContractDecision(await p.check(current, signal));
110
120
  if (d.action === "deny") {
111
121
  return rewrite?.updatedInput !== undefined ? { ...d, updatedInput: rewrite.updatedInput } : d;
112
122
  }
@@ -197,6 +197,19 @@ export interface McpServerSpec {
197
197
  irreversibility?: "always" | "never";
198
198
  }>;
199
199
  }
200
+ export interface A2aServerSpec {
201
+ name: string;
202
+ url: string;
203
+ cardUrl?: string;
204
+ headers?: Record<string, string>;
205
+ principalHeader?: string;
206
+ allowSkills?: string[];
207
+ toolAxes?: Record<string, {
208
+ effect?: ToolEffect;
209
+ egress?: boolean;
210
+ irreversibility?: "always" | "never";
211
+ }>;
212
+ }
200
213
  export interface McpElicitRequest {
201
214
  server: string;
202
215
  message: string;
@@ -296,6 +309,7 @@ export interface TaskSpec {
296
309
  enableFork?: boolean;
297
310
  shellGate?: "off" | "always" | "classify";
298
311
  mcp?: McpServerSpec[];
312
+ a2a?: A2aServerSpec[];
299
313
  skills?: SkillSpec[];
300
314
  backgroundScope?: "task" | "session";
301
315
  envFacts?: {
@@ -562,7 +576,7 @@ export type TaskEvent = ({
562
576
  reason?: string;
563
577
  } & TaskEventIdentity) | ({
564
578
  type: "steering_injected";
565
- source: "deadline_nudge" | "finalize" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
579
+ source: "deadline_nudge" | "finalize" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
566
580
  preview: string;
567
581
  } & TaskEventIdentity) | ({
568
582
  type: "diagnostics";
@@ -772,7 +786,7 @@ export interface RunnerDeps {
772
786
  hooks?: import("./hooks.js").Hooks;
773
787
  allowImageUrl?: (url: string) => boolean;
774
788
  onError?: (err: unknown, context: {
775
- phase: "compaction" | "prompt-cache" | "prompt-constitution" | "degraded" | "config" | "memory" | "mcp" | "interrupt-reconcile" | "suggestions" | "rewind" | "hook";
789
+ phase: "compaction" | "prompt-cache" | "prompt-constitution" | "degraded" | "config" | "memory" | "mcp" | "a2a" | "interrupt-reconcile" | "suggestions" | "rewind" | "hook";
776
790
  sessionId: string;
777
791
  classification?: string;
778
792
  }) => void;
package/dist/index.d.ts CHANGED
@@ -40,7 +40,8 @@ export { decideAutoPromote, deriveTripwire, FROZEN_DENYLIST_FLOOR, type AutoProm
40
40
  export { runCascade, type CascadeRung, type CascadeConfig, type CascadeAttempt, type CascadeRunResult, type GateVerdict, } from "./agents/cascade.js";
41
41
  export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
42
42
  export { materializeMcpTools, MCP_PREFIX, type MaterializedMcp, type McpServerStatus, type McpRefreshResult } from "./core/mcp.js";
43
- export { PROTOCOL_TABLE, MCP_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
43
+ export { materializeA2aTools, A2aRpcError, type MaterializedA2a, type A2aPeerStatus, type A2aRefreshResult, type A2aToolAxis } from "./core/a2a.js";
44
+ export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
44
45
  export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
45
46
  export { SAFETY_MERGE_CONFORMANCE_CORPUS, type SafetyMergeVector } from "./core/safety-merge-corpus.js";
46
47
  export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
@@ -77,7 +78,7 @@ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpoi
77
78
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
78
79
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
79
80
  export type { FileSnapshotStore, FileSnapshotResult, FileSnapshotError, FileSnapshotBounds } from "./core/file-snapshot-store.js";
80
- export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
81
+ export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileSessionRepoOptions, type FileFileSnapshotStoreOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
81
82
  export { CacheBreakDetector, type CacheBreakFinding, type ToolFingerprintInput } from "./core/cache-break-detector.js";
82
83
  export { maybeCompact, type MaybeCompactOptions, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
83
84
  export { brainToRuntime } from "./core/runtime.js";
@@ -113,7 +114,7 @@ export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/au
113
114
  export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, type PermissionRule, type ParsedPermissionRule, type PermissionRuleIssue, type PermissionRuleCaps, type PermissionRulePolicyOptions, } from "./core/permission-rules.js";
114
115
  export { formatHookFeedback, runToolGate, type Hooks, type HookToolContext, type HookToolOutput, type PreToolUseResult, type PostToolUseResult, type UserPromptSubmitResult, type HookToolFailure, type PostToolUseFailureResult, type PostToolBatchCall, type PostToolBatchResult, type PreCompactContext, type PreCompactResult, type PostCompactContext, type StopFailureContext, type PermissionDeniedPayload, type PermissionDeniedSource, } from "./core/hooks.js";
115
116
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, } from "./core/memory.js";
116
- export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
117
+ export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
117
118
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
118
119
  export { encodeSurfacedKey, buildManifestText, validateSelectedIds, composeSelectiveBody, formatMemoryAge, resolveLinkedIds, RECALL_CAVEAT, DEFAULT_MAX_SELECTED, DEFAULT_MAX_LINKED, type MemorySelector, type MemorySelectRequest, type SelectiveRecallOptions, type SelectiveRecallResult, type LayeredRecallOptions, type LayeredRecallResult, type ScopedNoteHeader, type ScopedNoteRecord, } from "./core/memory-recall.js";
119
120
  export { runMemoryConsolidation, CONSOLIDATION_SYSTEM_PROMPT, DEFAULT_CONSOLIDATION_BAND, DEFAULT_CONSOLIDATION_SEARCH_LIMIT, DEFAULT_CONSOLIDATION_MAX_NOTES, DEFAULT_CONSOLIDATION_TIMEOUT_SEC, normalizeForExactMatch, type ConsolidationParams, type ConsolidationStats, type ConsolidationNote, type ConsolidationLLM, } from "./core/runner/memory-consolidation.js";
@@ -163,8 +164,12 @@ export { sessionRepoContract } from "./core/store-contracts/session-repo-contrac
163
164
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
164
165
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
165
166
  export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
166
- export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, } from "./core/background-agent-store.js";
167
+ export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
168
+ export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, type BackgroundAgentQuery, } from "./core/background-agent-store.js";
169
+ export { serveDurableAgentRowLane, buildAgentPollDetails, type AgentPollDetailsInput, } from "./core/task-registry-agent.js";
170
+ export type { UnifiedTaskResult } from "./core/task-registry-shared.js";
167
171
  export { FileBackgroundAgentStore, type FileBackgroundAgentStoreOptions } from "./stores/file/background-agent-store.js";
172
+ export { A2A_TASK_STATES, type A2ATaskState, type A2ATaskStateReversal, type A2ATaskStateReversalFaithful, type A2ATaskStateReversalLossy, toA2ATaskState, fromA2ATaskState, } from "./core/a2a-task-state.js";
168
173
  export { type WorkflowJournalStore, type WorkflowJournalEntry, InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, } from "./core/workflow-journal-store.js";
169
174
  export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedactedSummary } from "./core/untrusted-egress.js";
170
175
  export type { RedactionFinding, RedactionReport, RedactionConfidence } from "./core/untrusted-egress.js";
@@ -193,7 +198,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
193
198
  export { type BrainTimeoutConfig } from "./brain/timeout.js";
194
199
  export { createAssistantMessageEventStream } from "./internal/llm.js";
195
200
  export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
196
- export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
201
+ export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
197
202
  export { Type } from "typebox";
198
203
  export type { TSchema, Static } from "typebox";
199
204
  export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
package/dist/index.js CHANGED
@@ -37,7 +37,8 @@ export { decideAutoPromote, deriveTripwire, FROZEN_DENYLIST_FLOOR, } from "./cor
37
37
  export { runCascade, } from "./agents/cascade.js";
38
38
  export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
39
39
  export { materializeMcpTools, MCP_PREFIX } from "./core/mcp.js";
40
- export { PROTOCOL_TABLE, MCP_NAMESPACE, protocolOf } from "./core/protocol-table.js";
40
+ export { materializeA2aTools, A2aRpcError } from "./core/a2a.js";
41
+ export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf } from "./core/protocol-table.js";
41
42
  export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, } from "./core/session-policy-store.js";
42
43
  export { SAFETY_MERGE_CONFORMANCE_CORPUS } from "./core/safety-merge-corpus.js";
43
44
  export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
@@ -100,7 +101,7 @@ export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/au
100
101
  export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, } from "./core/permission-rules.js";
101
102
  export { formatHookFeedback, runToolGate, } from "./core/hooks.js";
102
103
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, } from "./core/memory.js";
103
- export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
104
+ export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
104
105
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
105
106
  export { encodeSurfacedKey, buildManifestText, validateSelectedIds, composeSelectiveBody, formatMemoryAge, resolveLinkedIds, RECALL_CAVEAT, DEFAULT_MAX_SELECTED, DEFAULT_MAX_LINKED, } from "./core/memory-recall.js";
106
107
  export { runMemoryConsolidation, CONSOLIDATION_SYSTEM_PROMPT, DEFAULT_CONSOLIDATION_BAND, DEFAULT_CONSOLIDATION_SEARCH_LIMIT, DEFAULT_CONSOLIDATION_MAX_NOTES, DEFAULT_CONSOLIDATION_TIMEOUT_SEC, normalizeForExactMatch, } from "./core/runner/memory-consolidation.js";
@@ -149,8 +150,11 @@ export { sessionRepoContract } from "./core/store-contracts/session-repo-contrac
149
150
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
150
151
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
151
152
  export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
152
- export { canAccessAgentRecord, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, } from "./core/background-agent-store.js";
153
+ export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
154
+ export { canAccessAgentRecord, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, } from "./core/background-agent-store.js";
155
+ export { serveDurableAgentRowLane, buildAgentPollDetails, } from "./core/task-registry-agent.js";
153
156
  export { FileBackgroundAgentStore } from "./stores/file/background-agent-store.js";
157
+ export { A2A_TASK_STATES, toA2ATaskState, fromA2ATaskState, } from "./core/a2a-task-state.js";
154
158
  export { InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, } from "./core/workflow-journal-store.js";
155
159
  export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedactedSummary } from "./core/untrusted-egress.js";
156
160
  export { MemoryRosterStore, FileRosterStore } from "./agents/roster-store.js";
@@ -338,6 +338,10 @@ export async function createRunWorkflowTool(d) {
338
338
  catch (err) {
339
339
  return structuredError(`failed to resolve workflow name: ${redactSecrets(err instanceof Error ? err.message : String(err)).slice(0, 300)}`);
340
340
  }
341
+ const resolvedShape = resolved;
342
+ if (resolvedShape !== undefined && (resolvedShape === null || typeof resolvedShape !== "object")) {
343
+ return structuredError("the wired workflow script store's resolveName returned the retired bare-string form — the resolution shape is now { script, defaultArgs? } (one shape); upgrade the store implementation");
344
+ }
341
345
  }
342
346
  if (resolved === undefined && builtinsEnabled) {
343
347
  resolved = resolveBuiltinWorkflow(rawName);
@@ -347,7 +351,7 @@ export async function createRunWorkflowTool(d) {
347
351
  script = resolved.script;
348
352
  if ("defaultArgs" in resolved)
349
353
  registeredDefaultArgs = resolved.defaultArgs;
350
- if (typeof resolved !== "string" && typeof resolved.stringArgKey === "string" && resolved.stringArgKey.length > 0) {
354
+ if (typeof resolved.stringArgKey === "string" && resolved.stringArgKey.length > 0) {
351
355
  registeredStringArgKey = resolved.stringArgKey;
352
356
  }
353
357
  }
@@ -101,7 +101,6 @@ export function assemblePrompt(inputs) {
101
101
  userSystemPrompt: inputs.userSystemPrompt,
102
102
  userAppendSystemPrompt: inputs.userAppendSystemPrompt,
103
103
  tools: inputs.tools,
104
- consolidationEnabled: false,
105
104
  ...facts,
106
105
  };
107
106
  let pack = SEMA_DEFAULT_PACK;
@@ -5,6 +5,7 @@ export const EVENT_PROMPT_REGISTRY = new Map([
5
5
  { kind: "plan_mode", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#PLAN_MODE_FULL_BODY" },
6
6
  { kind: "date_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "turn-attachments.ts#renderDateChange" },
7
7
  { kind: "instructions_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", maxBytes: 512, defaultPolicy: "always", rendererRef: "turn-attachments.ts#collectInstructionsChange" },
8
+ { kind: "workflow_size_guideline_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "runtask.ts#workflowSizeGuidelineChangeNotice" },
8
9
  { kind: "budget_usd", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderBudgetUsd" },
9
10
  { kind: "background_tasks", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderBackgroundTasks" },
10
11
  { kind: "tools_delta", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderToolsDelta" },