@sema-agent/core 5.2.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.
- package/CHANGELOG.md +21 -0
- package/dist/core/a2a-task-state.d.ts +15 -0
- package/dist/core/a2a-task-state.js +68 -0
- package/dist/core/a2a.d.ts +42 -0
- package/dist/core/a2a.js +651 -0
- package/dist/core/checkpoint-store.d.ts +6 -1
- package/dist/core/checkpoint-store.js +3 -1
- package/dist/core/mcp.d.ts +11 -4
- package/dist/core/mcp.js +11 -31
- package/dist/core/protocol-naming.d.ts +7 -0
- package/dist/core/protocol-naming.js +32 -0
- package/dist/core/protocol-table.d.ts +3 -1
- package/dist/core/protocol-table.js +37 -32
- package/dist/core/runner/prepare-task.d.ts +7 -0
- package/dist/core/runner/prepare-task.js +43 -14
- package/dist/core/runner/runtask.js +31 -4
- package/dist/core/runner/tool-disclosure.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.js +1 -1
- package/dist/core/runner/turn-attachments.d.ts +1 -2
- package/dist/core/runner/turn-attachments.js +1 -12
- package/dist/core/store-contracts/background-agent-store-contract.d.ts +5 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +213 -0
- package/dist/core/task-registry-agent.d.ts +14 -1
- package/dist/core/task-registry-agent.js +1 -1
- package/dist/core/types.d.ts +16 -2
- package/dist/index.d.ts +8 -3
- package/dist/index.js +6 -2
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/package.json +1 -1
|
@@ -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,
|
package/dist/core/types.d.ts
CHANGED
|
@@ -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 {
|
|
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";
|
|
@@ -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 {
|
|
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 {
|
|
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";
|
|
@@ -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 {
|
|
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";
|
|
@@ -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" },
|