@sema-agent/core 7.24.4 → 7.25.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/CHANGELOG.md +100 -0
- package/dist/agents/peer-session-drain.d.ts +16 -1
- package/dist/agents/peer-session-drain.js +16 -1
- package/dist/agents/send-message-tool.d.ts +10 -2
- package/dist/agents/send-message-tool.js +18 -7
- package/dist/agents/subagent.js +13 -10
- package/dist/core/arg-summary.d.ts +0 -7
- package/dist/core/arg-summary.js +2 -1
- package/dist/core/background-agent-store.d.ts +3 -3
- package/dist/core/checkpoint-store.d.ts +1 -0
- package/dist/core/delegation-frames.d.ts +5 -0
- package/dist/core/gate-fold.js +85 -0
- package/dist/core/gate-lanes.js +23 -1
- package/dist/core/gate-outcome.d.ts +8 -2
- package/dist/core/gate-outcome.js +3 -1
- package/dist/core/hooks.d.ts +29 -0
- package/dist/core/hooks.js +2 -0
- package/dist/core/mailbox-store.d.ts +5 -0
- package/dist/core/mailbox-store.js +1 -1
- package/dist/core/parent-spec-seat.d.ts +7 -1
- package/dist/core/parent-spec-seat.js +2 -0
- package/dist/core/permission-rule-consent.js +29 -47
- package/dist/core/permission-rule-provider.js +4 -3
- package/dist/core/permission-rule-store.d.ts +143 -7
- package/dist/core/permission-rule-store.js +165 -15
- package/dist/core/runner/contracts.d.ts +36 -2
- package/dist/core/runner/gate-exit.d.ts +14 -0
- package/dist/core/runner/gate-exit.js +4 -0
- package/dist/core/runner/prepare-delegation-surface.d.ts +4 -4
- package/dist/core/runner/prepare-delegation-surface.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -0
- package/dist/core/runner/prepare-gate-stations.js +7 -4
- package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
- package/dist/core/runner/prepare-hands-readface.js +25 -10
- package/dist/core/runner/prepare-inherited-gate.d.ts +23 -0
- package/dist/core/runner/prepare-inherited-gate.js +11 -6
- package/dist/core/runner/prepare-policy-chain.d.ts +15 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -4
- package/dist/core/runner/prepare-suspend-saga.d.ts +5 -2
- package/dist/core/runner/prepare-suspend-saga.js +4 -3
- package/dist/core/runner/prepare-task.js +10 -9
- package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -4
- package/dist/core/runner/prepare-wiring-manifest.js +8 -4
- package/dist/core/runner/resume-apply.js +2 -0
- package/dist/core/runner/run-harness-handlers.js +1 -0
- package/dist/core/runner/run-identity-wiring.d.ts +2 -2
- package/dist/core/runner/run-leg.js +26 -0
- package/dist/core/runner/run-notification-lane.d.ts +2 -2
- package/dist/core/runner/run-notification-lane.js +2 -1
- package/dist/core/runner/run-settle-and-teardown.js +1 -0
- package/dist/core/runner/session-rule-policy.d.ts +3 -4
- package/dist/core/runner/session-rule-policy.js +11 -3
- package/dist/core/session-policy-store.d.ts +27 -3
- package/dist/core/session-policy-store.js +12 -4
- package/dist/core/store-contracts/background-agent-store-contract.js +10 -0
- package/dist/core/store-contracts/peer-directory-contract.d.ts +23 -0
- package/dist/core/store-contracts/peer-directory-contract.js +82 -0
- package/dist/core/task-event.d.ts +6 -0
- package/dist/core/task-notification.d.ts +79 -4
- package/dist/core/task-notification.js +90 -1
- package/dist/core/task-registry-agent.js +1 -2
- package/dist/core/task-registry-monitor.js +2 -1
- package/dist/core/task-registry-shared.d.ts +53 -5
- package/dist/core/task-registry-shared.js +13 -2
- package/dist/core/task-registry.js +8 -5
- package/dist/core/task-spec.d.ts +12 -5
- package/dist/core/tool-catalog-entries.js +1 -0
- package/dist/core/tool-policy.js +30 -23
- package/dist/core/tool-spec.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +2 -2
- package/dist/engine/loop/agent-loop.js +1 -1
- package/dist/engine/loop/types.d.ts +4 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -3
- package/dist/prompts/coordinator.d.ts +2 -1
- package/dist/stores/file/adoption/adopt.js +23 -1
- package/dist/stores/file/permission-rule-store.js +3 -1
- package/dist/stores/file/session-policy-store.d.ts +31 -0
- package/dist/stores/file/session-policy-store.js +87 -7
- package/dist/tools/fs/bash-lexer.d.ts +13 -0
- package/dist/tools/fs/bash-lexer.js +61 -0
- package/dist/tools/fs/bash-program-position.d.ts +36 -29
- package/dist/tools/fs/bash-program-position.js +33 -13
- package/dist/tools/fs/bash-readonly-classifier.d.ts +26 -313
- package/dist/tools/fs/bash-readonly-classifier.js +81 -782
- package/dist/tools/fs/fs-bash.d.ts +43 -207
- package/dist/tools/fs/fs-bash.js +20 -341
- package/dist/tools/fs/index.d.ts +12 -13
- package/dist/tools/fs/index.js +3 -4
- package/dist/tools/fs/read-deny.d.ts +25 -0
- package/dist/tools/fs/read-deny.js +19 -0
- package/dist/tools/fs/safety.js +2 -6
- package/dist/tools/fs/shell-read-check.d.ts +99 -0
- package/dist/tools/fs/shell-read-check.js +229 -0
- package/dist/tools/fs/shell-read-establish.d.ts +70 -115
- package/dist/tools/fs/shell-read-establish.js +216 -102
- package/dist/tools/fs/shell-read-judge.d.ts +231 -0
- package/dist/tools/fs/shell-read-judge.js +170 -0
- package/dist/tools/fs/shell-read-plan.d.ts +3 -0
- package/dist/tools/fs/shell-read-plan.js +88 -27
- package/dist/tools/monitor.d.ts +5 -5
- package/dist/tools/monitor.js +3 -5
- package/dist/tools/task-list.d.ts +4 -0
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +19 -3
- package/wire-changes/core@7.25.0.json +671 -0
- package/wire-changes/core@7.25.1.json +64 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { escapeEnvelopeTag, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
2
2
|
import { PEER_MESSAGE_NOTICE } from "../agents/peer-admission.js";
|
|
3
3
|
import { buildCrossSessionEnvelope, CROSS_SESSION_MESSAGE_NOTICE, neutralizePeerBody } from "../agents/cross-session-envelope.js";
|
|
4
|
+
export const NOTIFICATION_INJECTION_OUTCOMES = ["queued", "parked", "parked_durably", "dropped_duplicate"];
|
|
5
|
+
export function isNotificationInjectionOutcome(value) {
|
|
6
|
+
return typeof value === "string" && NOTIFICATION_INJECTION_OUTCOMES.includes(value);
|
|
7
|
+
}
|
|
4
8
|
export const SYSTEM_INJECTION_PRIORITIES = ["now", "next", "later"];
|
|
5
9
|
export function isSystemInjectionPriority(value) {
|
|
6
10
|
return typeof value === "string" && SYSTEM_INJECTION_PRIORITIES.includes(value);
|
|
@@ -107,6 +111,7 @@ const MAX_DEDUP_KEYS = 2_000;
|
|
|
107
111
|
export const MAX_PENDING_EVENTS_PER_TASK = 50;
|
|
108
112
|
export const MAX_PENDING_EVENTS_PER_SESSION = 200;
|
|
109
113
|
export const MAX_PENDING_SESSIONS = 100;
|
|
114
|
+
export const MAX_SESSION_BOX_BINDINGS = 4096;
|
|
110
115
|
const MAX_TOMBSTONES = 5_000;
|
|
111
116
|
const TERMINAL_STATUSES = new Set(["completed", "failed", "killed", "cancelled"]);
|
|
112
117
|
export function isDelegatedAgentTerminal(n) {
|
|
@@ -186,6 +191,22 @@ export class PendingSessionNotifications {
|
|
|
186
191
|
droppedSessions = 0;
|
|
187
192
|
evictedSessions = new Map();
|
|
188
193
|
unattributedDrops = 0;
|
|
194
|
+
sessionBoxes = new Map();
|
|
195
|
+
bindSessionBox(sessionId, box) {
|
|
196
|
+
this.sessionBoxes.delete(sessionId);
|
|
197
|
+
if (box === undefined)
|
|
198
|
+
return;
|
|
199
|
+
this.sessionBoxes.set(sessionId, box);
|
|
200
|
+
while (this.sessionBoxes.size > MAX_SESSION_BOX_BINDINGS) {
|
|
201
|
+
const oldest = this.sessionBoxes.keys().next().value;
|
|
202
|
+
if (oldest === undefined)
|
|
203
|
+
break;
|
|
204
|
+
this.sessionBoxes.delete(oldest);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
sessionBoxFor(sessionId) {
|
|
208
|
+
return this.sessionBoxes.get(sessionId);
|
|
209
|
+
}
|
|
189
210
|
pend(sessionId, n, priority) {
|
|
190
211
|
let s = this.sessions.get(sessionId);
|
|
191
212
|
if (s === undefined) {
|
|
@@ -251,7 +272,36 @@ export class PendingSessionNotifications {
|
|
|
251
272
|
}
|
|
252
273
|
routed = new Map();
|
|
253
274
|
holdsKey(sessionId, dedupKey) {
|
|
254
|
-
return this.sessions.get(sessionId)?.keys.has(dedupKey) === true || this.routed.get(sessionId)?.has(dedupKey) === true;
|
|
275
|
+
return this.sessions.get(sessionId)?.keys.has(dedupKey) === true || this.routed.get(sessionId)?.has(dedupKey) === true || this.durable.get(sessionId)?.has(dedupKey) === true;
|
|
276
|
+
}
|
|
277
|
+
durable = new Map();
|
|
278
|
+
noteDurablePark(sessionId, dedupKey) {
|
|
279
|
+
let mine = this.durable.get(sessionId);
|
|
280
|
+
if (mine === undefined) {
|
|
281
|
+
if (this.durable.size >= MAX_PENDING_SESSIONS) {
|
|
282
|
+
const oldest = this.durable.keys().next().value;
|
|
283
|
+
if (oldest !== undefined)
|
|
284
|
+
this.durable.delete(oldest);
|
|
285
|
+
}
|
|
286
|
+
mine = new Set();
|
|
287
|
+
this.durable.set(sessionId, mine);
|
|
288
|
+
}
|
|
289
|
+
mine.add(dedupKey);
|
|
290
|
+
if (mine.size > MAX_PENDING_EVENTS_PER_SESSION) {
|
|
291
|
+
for (const k of mine) {
|
|
292
|
+
mine.delete(k);
|
|
293
|
+
if (mine.size <= MAX_PENDING_EVENTS_PER_SESSION)
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
forgetDurablePark(sessionId, dedupKey) {
|
|
299
|
+
const mine = this.durable.get(sessionId);
|
|
300
|
+
if (mine === undefined)
|
|
301
|
+
return;
|
|
302
|
+
mine.delete(dedupKey);
|
|
303
|
+
if (mine.size === 0)
|
|
304
|
+
this.durable.delete(sessionId);
|
|
255
305
|
}
|
|
256
306
|
markDelivered(sessionId, dedupKey) {
|
|
257
307
|
let mine = this.routed.get(sessionId);
|
|
@@ -285,6 +335,30 @@ export function routeOrParkNotification(store, sessionId, payload, priority, onD
|
|
|
285
335
|
}
|
|
286
336
|
const routed = store.liveLanes.deliver(sessionId, payload, priority, { ...(onDisposition !== undefined ? { onDisposition } : {}) });
|
|
287
337
|
if (routed === "unavailable") {
|
|
338
|
+
const box = store.sessionBoxFor(sessionId);
|
|
339
|
+
const carrier = payload.agentMessage;
|
|
340
|
+
if (box !== undefined && carrier !== undefined) {
|
|
341
|
+
store.noteDurablePark(sessionId, dedupKey);
|
|
342
|
+
const record = sessionBoxRecordOf({ ...payload, agentMessage: carrier }, box);
|
|
343
|
+
let appended;
|
|
344
|
+
try {
|
|
345
|
+
appended = Promise.resolve(box.mailbox.append(box.scope, box.handle, record));
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
appended = Promise.reject(e);
|
|
349
|
+
}
|
|
350
|
+
appended.then(() => onDisposition?.("parked_durably"), (e) => {
|
|
351
|
+
store.forgetDurablePark(sessionId, dedupKey);
|
|
352
|
+
try {
|
|
353
|
+
box.onError?.(e);
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
}
|
|
357
|
+
store.pend(sessionId, payload, priority);
|
|
358
|
+
onDisposition?.("parked");
|
|
359
|
+
});
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
288
362
|
store.pend(sessionId, payload, priority);
|
|
289
363
|
onDisposition?.("parked");
|
|
290
364
|
}
|
|
@@ -292,6 +366,21 @@ export function routeOrParkNotification(store, sessionId, payload, priority, onD
|
|
|
292
366
|
onDisposition?.("queued");
|
|
293
367
|
}
|
|
294
368
|
}
|
|
369
|
+
export function sessionBoxRecordOf(payload, box) {
|
|
370
|
+
const peer = payload.peer;
|
|
371
|
+
return {
|
|
372
|
+
from: payload.agentMessage.from,
|
|
373
|
+
content: payload.agentMessage.body,
|
|
374
|
+
sentAt: Date.now(),
|
|
375
|
+
hopChain: peer !== undefined ? [...peer.hopChain] : [],
|
|
376
|
+
peerMeta: {
|
|
377
|
+
...(peer?.fromSession !== undefined ? { fromSession: peer.fromSession } : {}),
|
|
378
|
+
...(peer?.senderKey !== undefined ? { senderKey: peer.senderKey } : {}),
|
|
379
|
+
fromRoot: box.sessionId,
|
|
380
|
+
kind: "peer_message",
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|
|
295
384
|
function evictOldest(s, match) {
|
|
296
385
|
let idx = s.items.findIndex((i) => match(i) && !TERMINAL_STATUSES.has(i.status));
|
|
297
386
|
if (idx === -1)
|
|
@@ -419,7 +419,6 @@ export function registerBackgroundAgentLane(core, input) {
|
|
|
419
419
|
...(input.agentType !== undefined ? { agentType: input.agentType } : {}),
|
|
420
420
|
...(input.description !== undefined ? { description: input.description } : {}),
|
|
421
421
|
...(input.model !== undefined ? { model: input.model } : {}),
|
|
422
|
-
...(input.teamName !== undefined ? { teamName: input.teamName } : {}),
|
|
423
422
|
writerId: core.writerId,
|
|
424
423
|
writerEpoch: 1,
|
|
425
424
|
spawnedAt: now,
|
|
@@ -1236,7 +1235,7 @@ export async function deliverToRunningAgentLane(core, id, access, notification,
|
|
|
1236
1235
|
let result;
|
|
1237
1236
|
try {
|
|
1238
1237
|
const d = await handle.notify?.(notification, opts);
|
|
1239
|
-
if (d === "parked") {
|
|
1238
|
+
if (d === "parked" || d === "parked_durably") {
|
|
1240
1239
|
result = handle.retainedContinuation === true ? { ok: true, disposition: "parked" } : { ok: false, reason: "not_running" };
|
|
1241
1240
|
}
|
|
1242
1241
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { delimitUntrusted } from "./untrusted-text.js";
|
|
2
|
-
import { assertOwnership, defaultMonitorTimers, MONITOR_MAX_TIMEOUT_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_BATCH_WINDOW_MS, MONITOR_MAX_BATCHES_PER_MINUTE, MONITOR_STORM_BURST, MONITOR_STORM_KILL_AFTER_MS, MONITOR_LINE_BUF_CAP, MONITOR_SPILL_CAP_CHARS, TASK_OUTPUT_MAX_CHARS, mintCompletionId, clipMonitorEvent, clipMonitorLine, terminalTaskSummary, accountDroppedBytes, renderSpoolBody, rollSpoolText, statusFromBackground, droppedGapNote, firstDropNote, alreadyTerminalStopNote, clipTaskOutput, sleepPollStep, } from "./task-registry-shared.js";
|
|
2
|
+
import { assertOwnership, defaultMonitorTimers, MONITOR_MAX_TIMEOUT_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_BATCH_WINDOW_MS, MONITOR_MAX_BATCHES_PER_MINUTE, MONITOR_STORM_BURST, MONITOR_STORM_KILL_AFTER_MS, MONITOR_LINE_BUF_CAP, MONITOR_SPILL_CAP_CHARS, TASK_OUTPUT_MAX_CHARS, mintCompletionId, clipMonitorEvent, clipMonitorLine, terminalTaskSummary, accountDroppedBytes, renderSpoolBody, SPOOL_REPLAY, rollSpoolText, statusFromBackground, droppedGapNote, firstDropNote, alreadyTerminalStopNote, clipTaskOutput, sleepPollStep, } from "./task-registry-shared.js";
|
|
3
3
|
import { buildToolResultRef, OFFLOAD_TOOL_NAME, toolResultProvenanceOf } from "./tool-result-store.js";
|
|
4
4
|
import { thrownText } from "./thrown-value.js";
|
|
5
5
|
export function registerMonitorLane(core, input) {
|
|
@@ -339,6 +339,7 @@ export async function pollMonitorLane(handle, filter, deadline, signal) {
|
|
|
339
339
|
details: {
|
|
340
340
|
status: running ? "running" : handle.status,
|
|
341
341
|
exitCode: spool.exitCode,
|
|
342
|
+
replay: SPOOL_REPLAY,
|
|
342
343
|
...(spool.droppedBytes !== undefined ? { bytesDroppedBeforeCursor: spool.droppedBytes } : {}),
|
|
343
344
|
...(spool.timedOut === true ? { timedOut: true, ...(spool.timeoutSec !== undefined ? { timeoutSec: spool.timeoutSec } : {}) } : {}),
|
|
344
345
|
},
|
|
@@ -5,6 +5,7 @@ import type { BackgroundAgentRecord, BackgroundAgentStore } from "./background-a
|
|
|
5
5
|
import type { WorkflowHandle, WorkflowRun } from "../orchestration/workflow.js";
|
|
6
6
|
import type { TaskNotificationPayload } from "./task-notification.js";
|
|
7
7
|
import type { ToolResultStore } from "./tool-result-store.js";
|
|
8
|
+
import type { AssertAllKeysHandled } from "./ask-origin.js";
|
|
8
9
|
export type SemaTaskType = "background_bash" | "workflow" | "background_agent" | "monitor";
|
|
9
10
|
/** design/134 §3.3 (R3): WHO initiated a kill — recorded at the initiation site (first-marker-wins),
|
|
10
11
|
* because the settle-side then/catch context has already lost it. OPEN ENUM on the wire, now in the
|
|
@@ -254,7 +255,7 @@ export interface BackgroundAgentTaskHandle extends SemaTaskHandle {
|
|
|
254
255
|
* ends park per session inside the injector itself (the lane-teardown branch). */
|
|
255
256
|
notify?: (notification: import("./task-notification.js").TaskNotificationPayload, opts?: {
|
|
256
257
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
257
|
-
}) => "
|
|
258
|
+
}) => import("./task-notification.js").NotificationInjectionOutcome | Promise<import("./task-notification.js").NotificationInjectionOutcome>;
|
|
258
259
|
/** design/147 S2a — messages that arrived in the STARTUP window (row already
|
|
259
260
|
* running, lane not yet bound). Bounded; flushed in order by attachAgentNotify. Discarded at
|
|
260
261
|
* terminal settle: a run that failed during prepare never had a lane to park through, and the
|
|
@@ -658,6 +659,54 @@ export declare function spoolDropNote(acct: {
|
|
|
658
659
|
droppedBytes?: number;
|
|
659
660
|
dropUnknown?: true;
|
|
660
661
|
}): string;
|
|
662
|
+
/**
|
|
663
|
+
* HOW a poll's output body may be read AGAIN — the machine word beside `details`, previously legible
|
|
664
|
+
* only from the stdout heading's prose.
|
|
665
|
+
*
|
|
666
|
+
* `full` = the whole output of the task, re-rendered from the registry's own spool on every poll: a
|
|
667
|
+
* later poll answers the same bytes plus whatever arrived, so a consumer REPLACES what it holds.
|
|
668
|
+
* `cursor` = only what is NEW since the previous read: the env cursor was consumed and those bytes
|
|
669
|
+
* cannot be served twice, so a consumer APPENDS.
|
|
670
|
+
*
|
|
671
|
+
* The distinction was machine-invisible and the one key nearby reads the two faces OPPOSITELY:
|
|
672
|
+
* `bytesDroppedBeforeCursor` rides the spool faces only when something was actually dropped, and the
|
|
673
|
+
* increment face unconditionally (value possibly 0). A consumer discriminating on that key's PRESENCE
|
|
674
|
+
* therefore reads a spool that happened to drop bytes as an increment — and appends a body that was a
|
|
675
|
+
* full re-render, printing the same text twice.
|
|
676
|
+
*/
|
|
677
|
+
export declare const TASK_OUTPUT_REPLAY_KINDS: readonly ["full", "cursor"];
|
|
678
|
+
export type TaskOutputReplay = (typeof TASK_OUTPUT_REPLAY_KINDS)[number];
|
|
679
|
+
/**
|
|
680
|
+
* The ONE table the word and the prose both come out of. Each face's stdout/stderr headings live here
|
|
681
|
+
* rather than at the three legs that render them, so the banner a person reads and the key a program
|
|
682
|
+
* reads cannot drift — the failure mode this whole field exists to end (the two spool renderers were
|
|
683
|
+
* hand-copied twins before {@link renderSpoolBody}, and their drift was three disclosure bugs).
|
|
684
|
+
*
|
|
685
|
+
* `stdoutWhenGapped` is the heading a face falls back to once a gap has been disclosed. `undefined` is
|
|
686
|
+
* a ROW, not an omission: an increment window claims nothing about completeness to begin with ("new
|
|
687
|
+
* stdout" is true whether or not bytes were lost before it), so it has no claim to downgrade — while a
|
|
688
|
+
* spool advertising itself as "full" with a disclosed gap would be saying something false.
|
|
689
|
+
*/
|
|
690
|
+
export declare const REPLAY_FACE: {
|
|
691
|
+
readonly full: {
|
|
692
|
+
readonly stdout: "stdout (full, re-readable)";
|
|
693
|
+
readonly stdoutWhenGapped: "stdout (re-readable spool — INCOMPLETE, see note above)";
|
|
694
|
+
readonly stderr: "stderr";
|
|
695
|
+
};
|
|
696
|
+
readonly cursor: {
|
|
697
|
+
readonly stdout: "new stdout";
|
|
698
|
+
readonly stdoutWhenGapped: undefined;
|
|
699
|
+
readonly stderr: "new stderr";
|
|
700
|
+
};
|
|
701
|
+
};
|
|
702
|
+
export type ReplayHeadingTableCoversEveryReplay = AssertAllKeysHandled<Exclude<TaskOutputReplay, keyof typeof REPLAY_FACE>>;
|
|
703
|
+
/** The re-readable spool face: the monitor lane and the bash spool lane, both rendered by
|
|
704
|
+
* {@link renderSpoolBody}. Named once so the three legs that report it cannot each spell it. */
|
|
705
|
+
export declare const SPOOL_REPLAY = "full";
|
|
706
|
+
/** The consume-once increment face: the bash blocked wait, which accumulates env-cursor increments. */
|
|
707
|
+
export declare const INCREMENT_REPLAY = "cursor";
|
|
708
|
+
/** The stdout heading of a face, downgraded when a gap has been disclosed (see {@link REPLAY_FACE}). */
|
|
709
|
+
export declare function stdoutHeadingOf(replay: TaskOutputReplay, gapDisclosed: boolean): string;
|
|
661
710
|
/** The re-readable spool fields {@link renderSpoolBody} reads — the intersection of the bash handle's
|
|
662
711
|
* optional `spool` and the monitor handle's mandatory one (both carry supersets: `mirrorFailed` is
|
|
663
712
|
* bash-only, `drainFailed`/`dropNotified` monitor-only). Declared as a named shape, not inlined, so
|
|
@@ -878,15 +927,14 @@ export interface RegisterBackgroundAgentInput extends TaskAccess {
|
|
|
878
927
|
* internals chain; equals parentSessionId at depth 1). Persisted on the handle, the durable row
|
|
879
928
|
* and the roster so recovery faces enumerate the whole tree under the root without alias walks. */
|
|
880
929
|
rootSessionId?: string;
|
|
881
|
-
/** design/151 S3b — revival lookup
|
|
882
|
-
*
|
|
883
|
-
* named-teammate spawn would.
|
|
930
|
+
/** design/151 S3b — the revival lookup key (CC meta-sidecar shape): the model RECORD KEY,
|
|
931
|
+
* persisted on the durable row so a tier-3 revival rebuilds the spec the way a fresh
|
|
932
|
+
* named-teammate spawn would. A lookup key only, never a serialized spec. `model` is NOT the
|
|
884
933
|
* resolved model id: a spawn that named a model in WORDS records the caller's spelling verbatim
|
|
885
934
|
* (catalog key / tier word / CC alias) so the revival can re-resolve it against the catalog in
|
|
886
935
|
* force at WAKE time; only a spawn that carried a Model OBJECT records that object's id. Same
|
|
887
936
|
* value and same rule as the roster row's `model` column. */
|
|
888
937
|
model?: string;
|
|
889
|
-
teamName?: string;
|
|
890
938
|
toolUseId?: string;
|
|
891
939
|
abort: AbortController;
|
|
892
940
|
now?: number;
|
|
@@ -101,14 +101,25 @@ export function spoolDropNote(acct) {
|
|
|
101
101
|
return "[!] an unknown amount of earlier output was permanently dropped before this window (buffer evicted)\n";
|
|
102
102
|
return "";
|
|
103
103
|
}
|
|
104
|
+
export const TASK_OUTPUT_REPLAY_KINDS = ["full", "cursor"];
|
|
105
|
+
export const REPLAY_FACE = {
|
|
106
|
+
full: { stdout: "stdout (full, re-readable)", stdoutWhenGapped: "stdout (re-readable spool — INCOMPLETE, see note above)", stderr: "stderr" },
|
|
107
|
+
cursor: { stdout: "new stdout", stdoutWhenGapped: undefined, stderr: "new stderr" },
|
|
108
|
+
};
|
|
109
|
+
export const SPOOL_REPLAY = "full";
|
|
110
|
+
export const INCREMENT_REPLAY = "cursor";
|
|
111
|
+
export function stdoutHeadingOf(replay, gapDisclosed) {
|
|
112
|
+
const face = REPLAY_FACE[replay];
|
|
113
|
+
return gapDisclosed ? (face.stdoutWhenGapped ?? face.stdout) : face.stdout;
|
|
114
|
+
}
|
|
104
115
|
export function renderSpoolBody(spool, opts) {
|
|
105
116
|
const timedOutClause = spool.timedOut === true ? ` (timed out after ${spool.timeoutSec !== undefined ? `${spool.timeoutSec}s` : "its background time budget"})` : "";
|
|
106
117
|
const displayStatus = (spool.exitCode !== undefined ? `exited(code ${spool.exitCode})` : opts.running ? "running" : opts.handleStatus) + timedOutClause;
|
|
107
118
|
const rolledNote = spool.rolledChars > 0 ? `[!] ${spool.rolledChars} earlier char(s) dropped from the spool (memory bound)${opts.rolledExtraClause}\n` : "";
|
|
108
119
|
const droppedNote = spoolDropNote(spool);
|
|
109
|
-
const stdoutHeading = droppedNote !== "" || opts.drainNote !== ""
|
|
120
|
+
const stdoutHeading = stdoutHeadingOf(SPOOL_REPLAY, droppedNote !== "" || opts.drainNote !== "");
|
|
110
121
|
return (`status: ${displayStatus}\n${rolledNote}${droppedNote}${opts.drainNote}--- ${stdoutHeading} ---\n${opts.shape(spool.stdout) || "(none)"}\n` +
|
|
111
|
-
`--- stderr ---\n${opts.shape(spool.stderr) || "(none)"}`);
|
|
122
|
+
`--- ${REPLAY_FACE[SPOOL_REPLAY].stderr} ---\n${opts.shape(spool.stderr) || "(none)"}`);
|
|
112
123
|
}
|
|
113
124
|
export function droppedGapNote(spool) {
|
|
114
125
|
if ((spool.droppedBytes ?? 0) > 0)
|
|
@@ -8,7 +8,7 @@ import { createSafeNotifier } from "./safe-notify.js";
|
|
|
8
8
|
import { stripCwdSentinel } from "../tools/fs/fs-shared.js";
|
|
9
9
|
import { registerMonitorLane, pollMonitorLane, stopMonitorLane } from "./task-registry-monitor.js";
|
|
10
10
|
import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task-registry-workflow.js";
|
|
11
|
-
import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
|
|
11
|
+
import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, stdoutHeadingOf, REPLAY_FACE, SPOOL_REPLAY, INCREMENT_REPLAY, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
|
|
12
12
|
export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
|
|
13
13
|
import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
|
|
14
14
|
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, activeDelegationHandlesLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
@@ -1075,6 +1075,7 @@ The durable record is still marked running (last update ${new Date(row.updatedAt
|
|
|
1075
1075
|
details: {
|
|
1076
1076
|
status: running ? "running" : handle.status,
|
|
1077
1077
|
exitCode: spool.exitCode,
|
|
1078
|
+
replay: SPOOL_REPLAY,
|
|
1078
1079
|
...(spool.droppedBytes !== undefined ? { bytesDroppedBeforeCursor: spool.droppedBytes } : {}),
|
|
1079
1080
|
...(spool.timedOut === true ? { timedOut: true, ...(spool.timeoutSec !== undefined ? { timeoutSec: spool.timeoutSec } : {}) } : {}),
|
|
1080
1081
|
},
|
|
@@ -1099,12 +1100,13 @@ The durable record is still marked running (last update ${new Date(row.updatedAt
|
|
|
1099
1100
|
if (r.error.code === "not_found")
|
|
1100
1101
|
return noTask(requestedId, runningAgentFooterLane(this.core, access));
|
|
1101
1102
|
const retrieval_status = r.error.code === "timeout" ? "timeout" : "not_ready";
|
|
1102
|
-
const
|
|
1103
|
+
const carriedOutput = stdout.length > 0 || stderr.length > 0;
|
|
1104
|
+
const salvaged = carriedOutput
|
|
1103
1105
|
? `\n--- output accumulated before the error ---\n${clipTaskOutput(stdout, handle.outputFile)}${stderr ? `\n--- stderr ---\n${clipTaskOutput(stderr, handle.outputFile)}` : ""}`
|
|
1104
1106
|
: "";
|
|
1105
1107
|
return {
|
|
1106
1108
|
content: `Error (TaskOutput): ${r.error.message}${salvaged}`,
|
|
1107
|
-
details: { task_id: handle.id, type: "background_bash", status: handle.status, retrieval_status, error: r.error.code },
|
|
1109
|
+
details: { task_id: handle.id, type: "background_bash", status: handle.status, retrieval_status, ...(carriedOutput ? { details: { replay: INCREMENT_REPLAY } } : {}), error: r.error.code },
|
|
1108
1110
|
isError: true,
|
|
1109
1111
|
};
|
|
1110
1112
|
}
|
|
@@ -1125,8 +1127,8 @@ The durable record is still marked running (last update ${new Date(row.updatedAt
|
|
|
1125
1127
|
const displayStatus = (r.value.status === "exited" ? `exited(code ${r.value.exitCode})` : r.value.status) + timedOutClause;
|
|
1126
1128
|
const droppedNote = spoolDropNote(dropAcct) +
|
|
1127
1129
|
(rolledChars > 0 ? `[!] ${rolledChars} accumulated char(s) dropped from the middle during the blocked wait (memory bound)\n` : "");
|
|
1128
|
-
const body = `status: ${displayStatus}\n${droppedNote}---
|
|
1129
|
-
`---
|
|
1130
|
+
const body = `status: ${displayStatus}\n${droppedNote}--- ${stdoutHeadingOf(INCREMENT_REPLAY, droppedNote !== "")} ---\n${shape(stdout) || "(none)"}\n` +
|
|
1131
|
+
`--- ${REPLAY_FACE[INCREMENT_REPLAY].stderr} ---\n${shape(stderr) || "(none)"}`;
|
|
1130
1132
|
return {
|
|
1131
1133
|
content: delimitUntrusted(`TaskOutput ${handle.id}`, body),
|
|
1132
1134
|
details: {
|
|
@@ -1139,6 +1141,7 @@ The durable record is still marked running (last update ${new Date(row.updatedAt
|
|
|
1139
1141
|
details: {
|
|
1140
1142
|
status: r.value.status,
|
|
1141
1143
|
exitCode: r.value.exitCode,
|
|
1144
|
+
replay: INCREMENT_REPLAY,
|
|
1142
1145
|
bytesDroppedBeforeCursor: dropAcct.droppedBytes ?? 0,
|
|
1143
1146
|
...(r.value.timedOut === true ? { timedOut: true, ...(r.value.timeoutSec !== undefined ? { timeoutSec: r.value.timeoutSec } : {}) } : {}),
|
|
1144
1147
|
},
|
package/dist/core/task-spec.d.ts
CHANGED
|
@@ -783,9 +783,12 @@ export interface TaskSpec {
|
|
|
783
783
|
/**
|
|
784
784
|
* design/199 件B — TASK-layer ADDITIONS to the built-in sensitive-path READ deny set
|
|
785
785
|
* ({@link import("../tools/fs/read-deny.js").READ_FACE_DEFAULT_DENY_ENTRIES}). Judged by the
|
|
786
|
-
* structured read faces (Read/Grep/Glob/RepoMap, their traversals, the
|
|
787
|
-
*
|
|
788
|
-
* {@link
|
|
786
|
+
* structured read faces (Read/Grep/Glob/RepoMap, their traversals, the compaction attachment reader) and
|
|
787
|
+
* by the shell READ STATION under every doctrine — the full shell (`Bash`, `Monitor`, whatever
|
|
788
|
+
* {@link shellGate} says) and the `bash_readonly` shell mounted by {@link handsReadOnly} alike: a
|
|
789
|
+
* deny-listed shell read is REFUSED at the gate (`deniedBy: "read_boundary"`), never asked, with the same
|
|
790
|
+
* sentence the structured faces refuse with — one deny judge for every read face — in BOTH containment
|
|
791
|
+
* modes. Add-only at
|
|
789
792
|
* the task layer: entries here UNION with the active built-ins and the deployment's
|
|
790
793
|
* {@link RunnerDeps.readDenyPatterns}; `[]` ≡ absent (union identity); NOTHING at the task layer
|
|
791
794
|
* can remove a built-in — the one removal channel is the DEPLOYMENT's built-in configuration
|
|
@@ -873,8 +876,12 @@ export interface TaskSpec {
|
|
|
873
876
|
* - `"always"`: every `bash` command tightens to an `irreversible_ask` durable suspend (fail-closed; the
|
|
874
877
|
* correct default for an unattended/supervisor deployment with no classifier).
|
|
875
878
|
* - `"classify"`: mark `bash` `irreversibility:"maybe"` with {@link import("../tools/fs/index.js").bashReversibilityProbe}
|
|
876
|
-
* — a provably-benign single allowlisted read-only command (no operators)
|
|
877
|
-
* (writes, egress, pipes, unknown commands) tightens to ask.
|
|
879
|
+
* — the SHAPE classifier alone: a provably-benign single allowlisted read-only command (no operators)
|
|
880
|
+
* auto-allows; everything else (writes, egress, pipes, unknown commands) tightens to ask. WHERE a command
|
|
881
|
+
* reads is not this doctrine's question under any value: the gate's shell read station judges every
|
|
882
|
+
* shell call's read candidates against the deny set and the containment roots (a deny-listed read is
|
|
883
|
+
* refused, an out-of-root read is a mandated ask) whether `shellGate` is `"off"`, `"classify"` or
|
|
884
|
+
* `"always"`. An egress command (e.g. `curl`) suspends under
|
|
878
885
|
* the IRREVERSIBLE axis (the shell mark is irreversibility, not egress) — the kind is non-budgetable either
|
|
879
886
|
* way, so the budget resolver still never auto-approves it; the axis label is informational.
|
|
880
887
|
* NOT unconditional: a POSITIVE per-tool mark on the shell tool keeps its seat — an explicit
|
|
@@ -154,6 +154,7 @@ export const ENGINE_CARDS = Object.freeze({
|
|
|
154
154
|
a2a: "src/core/a2a.ts",
|
|
155
155
|
path_not_in_root: "src/tools/fs/safety.ts",
|
|
156
156
|
read_path_denied: "src/tools/fs/safety.ts",
|
|
157
|
+
readonly_out_of_root: "src/tools/fs/shell-read-check.ts",
|
|
157
158
|
});
|
|
158
159
|
const byId = new Map();
|
|
159
160
|
for (const e of TOOL_CATALOG_ENTRIES) {
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -13,6 +13,7 @@ import { thrownText } from "./thrown-value.js";
|
|
|
13
13
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermissionRule } from "./permission-rules.js";
|
|
14
14
|
import { protocolOf } from "./protocol-table.js";
|
|
15
15
|
import { isAbsoluteForFamily, isAbsolutePathForm, joinForFamily, normalizeAbsPathLexically, pathFamilyOf, writeTargetPath } from "../tools/fs/safety.js";
|
|
16
|
+
import { ASSIGNMENT_PREFIX, writtenAssignmentPrefix } from "../tools/fs/bash-program-position.js";
|
|
16
17
|
export function advertisedWritableRootsSeat(seat) {
|
|
17
18
|
return seat === undefined ? {} : { advertisedWritableRoots: Object.freeze([...seat.roots]) };
|
|
18
19
|
}
|
|
@@ -618,22 +619,28 @@ export function findUnverifiableRecursiveDelete(command, safeVars = new Set(UNVE
|
|
|
618
619
|
}
|
|
619
620
|
return false;
|
|
620
621
|
};
|
|
622
|
+
const applyAssignmentWord = (words, at) => {
|
|
623
|
+
const written = writtenAssignmentPrefix(words[at]);
|
|
624
|
+
if (written === undefined) {
|
|
625
|
+
assigned.delete(words[at].replace(/\[.*$/, ""));
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const value = restOfAssignment(words, at, written.prefix.length - 1);
|
|
629
|
+
if ((!written.settlesWholeName && !assigned.has(written.name)) || valueIsOpaque(value, assigned, safeVars))
|
|
630
|
+
assigned.delete(written.name);
|
|
631
|
+
else
|
|
632
|
+
assigned.add(written.name);
|
|
633
|
+
if (valueEscapesRoot(value, safeVars))
|
|
634
|
+
assignedEscapesRoot.add(written.name);
|
|
635
|
+
else if (written.settlesWholeName)
|
|
636
|
+
assignedEscapesRoot.delete(written.name);
|
|
637
|
+
};
|
|
621
638
|
const statements = command.replace(/\\\r?\n/g, " ").split(STATEMENT_SPLIT);
|
|
622
639
|
for (const stmt of statements) {
|
|
623
640
|
const tokens = stmt.trim().split(/\s+/).filter(Boolean);
|
|
624
641
|
let i = 0;
|
|
625
|
-
while (i < tokens.length &&
|
|
626
|
-
|
|
627
|
-
const name = tokens[i].slice(0, eq);
|
|
628
|
-
const value = restOfAssignment(tokens, i, eq);
|
|
629
|
-
if (valueIsOpaque(value, assigned, safeVars))
|
|
630
|
-
assigned.delete(name);
|
|
631
|
-
else
|
|
632
|
-
assigned.add(name);
|
|
633
|
-
if (valueEscapesRoot(value, safeVars))
|
|
634
|
-
assignedEscapesRoot.add(name);
|
|
635
|
-
else
|
|
636
|
-
assignedEscapesRoot.delete(name);
|
|
642
|
+
while (i < tokens.length && ASSIGNMENT_PREFIX.test(tokens[i])) {
|
|
643
|
+
applyAssignmentWord(tokens, i);
|
|
637
644
|
i += assignmentTokenSpan(tokens, i);
|
|
638
645
|
}
|
|
639
646
|
let sawWrapper = false;
|
|
@@ -646,7 +653,7 @@ export function findUnverifiableRecursiveDelete(command, safeVars = new Set(UNVE
|
|
|
646
653
|
if (DELETE_WRAPPERS.has(t)) {
|
|
647
654
|
sawWrapper = true;
|
|
648
655
|
i++;
|
|
649
|
-
while (i < tokens.length && (/^-/.test(tokens[i]) ||
|
|
656
|
+
while (i < tokens.length && (/^-/.test(tokens[i]) || ASSIGNMENT_PREFIX.test(tokens[i])))
|
|
650
657
|
i++;
|
|
651
658
|
continue;
|
|
652
659
|
}
|
|
@@ -672,16 +679,16 @@ export function findUnverifiableRecursiveDelete(command, safeVars = new Set(UNVE
|
|
|
672
679
|
i = headIdx;
|
|
673
680
|
const head = stripTokenEdges(tokens[i]).replace(/^\\/, "");
|
|
674
681
|
const headName = head.split("/").pop() ?? head;
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
682
|
+
const declStmt = stmt.trim();
|
|
683
|
+
const declaredWords = /^(?:export|declare|typeset|local|readonly)\b/.test(declStmt) ? declStmt.split(/\s+/).filter(Boolean).slice(1) : ASSIGNMENT_PREFIX.test(declStmt) ? [declStmt] : [];
|
|
684
|
+
for (let d = 0; d < declaredWords.length;) {
|
|
685
|
+
if (/^[-+]/.test(declaredWords[d])) {
|
|
686
|
+
d += 1;
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
declaredWords[d] = stripTokenEdges(declaredWords[d]);
|
|
690
|
+
applyAssignmentWord(declaredWords, d);
|
|
691
|
+
d += assignmentTokenSpan(declaredWords, d);
|
|
685
692
|
}
|
|
686
693
|
if (headName === "read") {
|
|
687
694
|
void 0;
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -1180,7 +1180,7 @@ export interface ToolExecuteContext {
|
|
|
1180
1180
|
*/
|
|
1181
1181
|
onTaskNotification?: (n: import("./task-notification.js").TaskNotificationPayload, opts?: {
|
|
1182
1182
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
1183
|
-
}) =>
|
|
1183
|
+
}) => unknown;
|
|
1184
1184
|
/**
|
|
1185
1185
|
* design/99 (nested-subagent live observability): the host run's OPT-IN display sink — a deployment sets it (via
|
|
1186
1186
|
* `RunInternals.onForwardEvent`) to receive a SUBAGENT's live `task_progress` ticks that otherwise stay in the
|
|
@@ -432,8 +432,8 @@ export interface WiringFacts {
|
|
|
432
432
|
parkDurableApprovalOptIn: boolean;
|
|
433
433
|
/** `undefined` = unresolved at this half (per-principal runtime caps are a prepare-time fact). */
|
|
434
434
|
parkForceDurableGate?: boolean;
|
|
435
|
-
/** `undefined` = unresolved at this half (the irreversible/egress tool vocabulary
|
|
436
|
-
* prepare). */
|
|
435
|
+
/** `undefined` = unresolved at this half (the irreversible/egress tool vocabulary and the shell read station —
|
|
436
|
+
* the three sources of a mandated ask — are assembled in prepare). */
|
|
437
437
|
parkSafetyVocabularyArmed?: boolean;
|
|
438
438
|
/** Present iff `parkCapable` (the resolved checkpoint store's declaration). */
|
|
439
439
|
checkpointDurability?: StoreDurability;
|
|
@@ -1325,7 +1325,7 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
|
|
|
1325
1325
|
};
|
|
1326
1326
|
}
|
|
1327
1327
|
if (beforeResult?.block) {
|
|
1328
|
-
const blocked = createErrorToolResult(beforeResult.reason || "Tool execution was blocked");
|
|
1328
|
+
const blocked = createErrorToolResult(beforeResult.reason || "Tool execution was blocked", beforeResult.details !== undefined ? { details: beforeResult.details } : undefined);
|
|
1329
1329
|
if (beforeResult.haltRemaining !== undefined) {
|
|
1330
1330
|
return { kind: "immediate", result: blocked, isError: true, halt: beforeResult.haltRemaining };
|
|
1331
1331
|
}
|
|
@@ -83,6 +83,10 @@ export type AgentToolCall = Extract<AssistantMessage["content"][number], {
|
|
|
83
83
|
export interface BeforeToolCallResult {
|
|
84
84
|
block?: boolean;
|
|
85
85
|
reason?: string;
|
|
86
|
+
/** With `block`: the structured details the refusing layer minted, attached to the error result the loop
|
|
87
|
+
* builds from `reason` (a `{ type, code, … }` card reaches `tool_end.structured` / `errorCode` exactly as a
|
|
88
|
+
* tool's own refusal would). Ignored without `block`. */
|
|
89
|
+
details?: unknown;
|
|
86
90
|
updatedInput?: unknown;
|
|
87
91
|
haltRemaining?: HaltRemainingDirective;
|
|
88
92
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -100,7 +100,7 @@ export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core
|
|
|
100
100
|
export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
|
|
101
101
|
export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
102
102
|
export type { InvariantKind, FunctionContract, Invariant, InvariantViolation, CheckResult, } from "./core/property-harness.js";
|
|
103
|
-
export { bashReversibilityProbe,
|
|
103
|
+
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
104
104
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
|
|
105
105
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
106
106
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
|
|
@@ -132,7 +132,9 @@ export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./cor
|
|
|
132
132
|
export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE, type FsWriteGatePolicyOptions } from "./core/fs-write-gate-policy.js";
|
|
133
133
|
export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
|
|
134
134
|
export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
|
|
135
|
-
export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority,
|
|
135
|
+
export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, type NotificationInjectionOutcome, // the injector's outcome words (`parked_durably` = the session's durable box took the frame)
|
|
136
|
+
NOTIFICATION_INJECTION_OUTCOMES, // …and their value half + guard, so a host wiring its own uplink validates a reported outcome without duplicating the vocabulary
|
|
137
|
+
isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, } from "./core/task-notification.js";
|
|
136
138
|
export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
|
|
137
139
|
export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
|
|
138
140
|
export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
|
|
@@ -201,7 +203,7 @@ export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRul
|
|
|
201
203
|
* allowed and widening is not.
|
|
202
204
|
*/
|
|
203
205
|
export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, type ProgramRunReachOutcome, pathRuleReachOf, ruleBasesNeeded, PATH_RULE_BASES, PATH_RULE_BASE_LABEL, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, type PathRuleBase, type PathRuleBases, type RuleBehavior, type PersistedRuleVerdict, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, type UncoveredSegmentDetail, type EditedRuleBreadthWarning, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, type PersistedRule, type RuleTombstone, type RuleScope, type RuleDot, type RuleAdd, type RuleAddOrigin, type RuleOffer, type RuleOfferBatchMember, type SegmentRuleSuggestion, type SegmentCoverage, type RuleReject, type RuleRejectCode, type ParsedRule, type PersistedRuleTool, type PersistedRuleMatch, } from "./core/permission-rule-model.js";
|
|
204
|
-
export { removePersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, type DurableRulePartition, type DurableRulePartitionProvider, type RuleWriteOutcome, type StoredRules, type RemoveResult, type PutResult, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, type RuleSyncState, type RuleSyncFrontier, type RuleSyncDrop, type RuleSyncLandingReport, type RuleOwner, type QuarantinedRuleAdd, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, type PermissionRuleWriter, type WritableDurableRulePartition, type RuleWriteDelta, type RuleAddDelta, type RuleDeleteDelta, type RuleSyncJoinDelta, type RawRuleSyncState, type RedemptionAuthorization, } from "./core/permission-rule-store.js";
|
|
206
|
+
export { removePersistedRule, addPersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, type DurableRulePartition, type DurableRulePartitionProvider, type RuleWriteOutcome, type StoredRules, type RemoveResult, type AddResult, type PutResult, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, type RuleSyncState, type RuleSyncFrontier, type RuleSyncDrop, type RuleSyncLandingReport, type RuleOwner, type QuarantinedRuleAdd, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, type PermissionRuleWriter, type WritableDurableRulePartition, type RuleWriteDelta, type RuleAddDelta, type RuleTightenAddDelta, type RuleDeleteDelta, type RuleSyncJoinDelta, type RawRuleSyncState, type RedemptionAuthorization, } from "./core/permission-rule-store.js";
|
|
205
207
|
export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, type PermissionRuleSyncTransport, type PermissionRuleSyncResult, type RuleSyncRequestBody, type RuleSyncResponseBody, } from "./core/permission-rule-sync.js";
|
|
206
208
|
export { createPermissionRuleStoreProvider, effectivePermissionRules, effectiveOrThrow, ruleSourceOf, type PermissionRuleStore, type PermissionRuleStoreProvider, type PermissionRuleStoreConfig, type EffectivePermissionRules, type EffectivePermissionRule, type RemovedPermissionRule, type RuleSource, } from "./core/permission-rule-provider.js";
|
|
207
209
|
export { InMemorySessionRulePartition, type SessionRulePartition, type SessionRuleAdd, type SessionRuleApplyResult, } from "./core/permission-rule-session.js";
|
|
@@ -277,6 +279,7 @@ export { workflowJournalStoreContract } from "./core/store-contracts/workflow-jo
|
|
|
277
279
|
export { permissionRuleSyncContract, type PermissionRuleSyncContractHooks } from "./core/store-contracts/permission-rule-sync-contract.js";
|
|
278
280
|
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, type MailboxTombstonedRecipientContractHooks, mailboxCrossProcessContract, type MailboxCrossProcessContractHooks, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
279
281
|
export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
|
|
282
|
+
export { PEER_DIRECTORY_CONTRACT_SCOPE, peerDirectoryContract, type PeerDirectoryContractHooks } from "./core/store-contracts/peer-directory-contract.js";
|
|
280
283
|
export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, type BackgroundAgentQuery, } from "./core/background-agent-store.js";
|
|
281
284
|
export { serveDurableAgentRowLane, buildAgentPollDetails, type AgentPollDetailsInput, } from "./core/task-registry-agent.js";
|
|
282
285
|
export type { UnifiedTaskResult } from "./core/task-registry-shared.js";
|
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ export { runExecGate } from "./core/exec-gate.js";
|
|
|
78
78
|
export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core/untrusted-text.js";
|
|
79
79
|
export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
|
|
80
80
|
export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
81
|
-
export { bashReversibilityProbe,
|
|
81
|
+
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
82
82
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
|
|
83
83
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
84
84
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, } from "./tools/fs/index.js";
|
|
@@ -107,7 +107,7 @@ export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./cor
|
|
|
107
107
|
export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE } from "./core/fs-write-gate-policy.js";
|
|
108
108
|
export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
|
|
109
109
|
export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
|
|
110
|
-
export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, } from "./core/task-notification.js";
|
|
110
|
+
export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, } from "./core/task-notification.js";
|
|
111
111
|
export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
|
|
112
112
|
export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
|
|
113
113
|
export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
|
|
@@ -159,7 +159,7 @@ export { AUTO_MODE_ARMING_RECIPE_VERSION, autoModeArmingRecipeOf, sanitizeAutoMo
|
|
|
159
159
|
export { rebuildAutoModeDecider, } from "./core/auto-mode-rebuild.js";
|
|
160
160
|
export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, isNamespacedCoveringRuleName, namespacedRuleNameCovers, } from "./core/permission-rules.js";
|
|
161
161
|
export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, pathRuleReachOf, ruleBasesNeeded, PATH_RULE_BASES, PATH_RULE_BASE_LABEL, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, } from "./core/permission-rule-model.js";
|
|
162
|
-
export { removePersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, } from "./core/permission-rule-store.js";
|
|
162
|
+
export { removePersistedRule, addPersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, } from "./core/permission-rule-store.js";
|
|
163
163
|
export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, } from "./core/permission-rule-sync.js";
|
|
164
164
|
export { createPermissionRuleStoreProvider, effectivePermissionRules, effectiveOrThrow, ruleSourceOf, } from "./core/permission-rule-provider.js";
|
|
165
165
|
export { InMemorySessionRulePartition, } from "./core/permission-rule-session.js";
|
|
@@ -233,6 +233,7 @@ export { workflowJournalStoreContract } from "./core/store-contracts/workflow-jo
|
|
|
233
233
|
export { permissionRuleSyncContract } from "./core/store-contracts/permission-rule-sync-contract.js";
|
|
234
234
|
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, mailboxCrossProcessContract, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
235
235
|
export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
|
|
236
|
+
export { PEER_DIRECTORY_CONTRACT_SCOPE, peerDirectoryContract } from "./core/store-contracts/peer-directory-contract.js";
|
|
236
237
|
export { canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, } from "./core/background-agent-store.js";
|
|
237
238
|
export { serveDurableAgentRowLane, buildAgentPollDetails, } from "./core/task-registry-agent.js";
|
|
238
239
|
export { FileBackgroundAgentStore } from "./stores/file/background-agent-store.js";
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* design/147 S3b — the teammate communication addendum (CC 2.1.212
|
|
3
3
|
* `TEAMMATE_SYSTEM_PROMPT_ADDENDUM`, pretty.js:322948, sema-ized): composed for a NAMED delegated
|
|
4
4
|
* child (`core/mode.teammate` section, admit = facts.teammateEnabled — the CC injection condition
|
|
5
|
-
* `agentId && agentName && teamName` maps to sema's named-spawn internals chain
|
|
5
|
+
* `agentId && agentName && teamName` maps to sema's named-spawn internals chain; sema keeps no team
|
|
6
|
+
* name — one implicit team per session, keyed by the root session). Divergences:
|
|
6
7
|
* CC's "task system"/"team lead" wording maps to sema's `"main"` reserved lane (the spawning
|
|
7
8
|
* conversation); and the capability sentences track the shipped contract (S2a
|
|
8
9
|
* delivered mid-run delivery): a message to a RUNNING teammate is queued and reaches it at its next
|