@sema-agent/core 5.12.0 → 5.14.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 +320 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +4 -0
- package/dist/agents/subagent.js +137 -43
- package/dist/brain/anthropic.js +33 -10
- package/dist/brain/context-overflow.d.ts +20 -0
- package/dist/brain/context-overflow.js +58 -0
- package/dist/brain/open-responses.js +24 -10
- package/dist/brain/openai.js +29 -11
- package/dist/brain/request-params.d.ts +2 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/brain/stream-engine.d.ts +9 -1
- package/dist/brain/stream-engine.js +256 -27
- package/dist/brain/timeout.d.ts +1 -0
- package/dist/brain/timeout.js +1 -0
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.js +3 -3
- package/dist/core/ask-question.d.ts +47 -2
- package/dist/core/ask-question.js +209 -28
- package/dist/core/background-agent-store.d.ts +2 -0
- package/dist/core/checkpoint-store.d.ts +49 -18
- package/dist/core/checkpoint-store.js +117 -4
- package/dist/core/compliance.d.ts +11 -0
- package/dist/core/compliance.js +34 -0
- package/dist/core/governance-codes.d.ts +12 -0
- package/dist/core/governance-codes.js +24 -0
- package/dist/core/hooks.d.ts +24 -2
- package/dist/core/hooks.js +97 -10
- package/dist/core/human-input-projection.d.ts +12 -0
- package/dist/core/human-input-projection.js +27 -0
- package/dist/core/locked-config.d.ts +27 -0
- package/dist/core/locked-config.js +42 -0
- package/dist/core/mcp.d.ts +7 -2
- package/dist/core/mcp.js +7 -7
- package/dist/core/memory-admission.d.ts +51 -0
- package/dist/core/memory-admission.js +159 -0
- package/dist/core/memory.d.ts +2 -0
- package/dist/core/memory.js +3 -2
- package/dist/core/retention.d.ts +36 -0
- package/dist/core/retention.js +31 -0
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +2 -2
- package/dist/core/runner/prepare-memory.d.ts +9 -0
- package/dist/core/runner/prepare-memory.js +28 -2
- package/dist/core/runner/prepare-task.d.ts +18 -6
- package/dist/core/runner/prepare-task.js +428 -38
- package/dist/core/runner/runtask.d.ts +3 -6
- package/dist/core/runner/runtask.js +258 -77
- package/dist/core/runner/tool-output-projection.js +1 -0
- package/dist/core/session-store.d.ts +4 -0
- package/dist/core/session-store.js +5 -0
- package/dist/core/session.d.ts +1 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
- package/dist/core/task-notification.d.ts +2 -0
- package/dist/core/task-notification.js +5 -3
- package/dist/core/task-registry-agent.d.ts +1 -0
- package/dist/core/task-registry-agent.js +6 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/tool-policy.d.ts +5 -0
- package/dist/core/tool-policy.js +2 -1
- package/dist/core/tool-result-store.d.ts +2 -0
- package/dist/core/tool-result-store.js +1 -0
- package/dist/core/types.d.ts +38 -2
- package/dist/core/wiring-manifest.d.ts +97 -0
- package/dist/core/wiring-manifest.js +186 -0
- package/dist/engine/compaction/compaction.js +2 -2
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +19 -2
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +7 -0
- package/dist/engine/llm/types.js +8 -1
- package/dist/engine/llm/validation.js +11 -1
- package/dist/engine/session/import-validate.d.ts +6 -1
- package/dist/engine/session/import-validate.js +29 -6
- package/dist/engine/session/memory-repo.d.ts +3 -1
- package/dist/engine/session/memory-repo.js +2 -2
- package/dist/index.d.ts +12 -4
- package/dist/index.js +12 -4
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/workflow-types.d.ts +8 -0
- package/dist/orchestration/workflow-types.js +14 -0
- package/dist/orchestration/workflow.d.ts +4 -0
- package/dist/orchestration/workflow.js +134 -5
- package/dist/prompts/default.js +1 -1
- package/dist/stores/file/checkpoint-store.d.ts +3 -5
- package/dist/stores/file/checkpoint-store.js +31 -2
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/session-store.d.ts +3 -1
- package/dist/stores/file/session-store.js +2 -2
- package/dist/stores/file/shared-ledger.js +8 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
- package/dist/tools/fs/bash-readonly-classifier.js +94 -0
- package/dist/tools/fs/fs-bash.js +31 -12
- package/dist/tools/fs/safety.js +34 -10
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SessionRepo } from "../internal/harness.js";
|
|
2
2
|
import { type AcquiredSession, type SessionStore, type SessionStoreSummary } from "./session.js";
|
|
3
|
+
import type { StoreDurability } from "./checkpoint-store.js";
|
|
3
4
|
import { SESSION_DEFAULT_TTL_DAYS } from "../config/defaults.js";
|
|
4
5
|
export { SESSION_DEFAULT_TTL_DAYS };
|
|
5
6
|
export type EvictPolicy = "delete" | "forget";
|
|
@@ -8,8 +9,11 @@ export interface TtlSessionStoreOptions {
|
|
|
8
9
|
sweepIntervalMs?: number;
|
|
9
10
|
repo?: SessionRepo;
|
|
10
11
|
evict?: EvictPolicy;
|
|
12
|
+
durability?: StoreDurability;
|
|
11
13
|
}
|
|
12
14
|
export declare class TtlSessionStore implements SessionStore {
|
|
15
|
+
readonly retention: "none";
|
|
16
|
+
readonly durability?: StoreDurability;
|
|
13
17
|
private repo;
|
|
14
18
|
private entries;
|
|
15
19
|
private owners;
|
|
@@ -4,6 +4,8 @@ const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
4
4
|
import { SESSION_DEFAULT_TTL_DAYS } from "../config/defaults.js";
|
|
5
5
|
export { SESSION_DEFAULT_TTL_DAYS };
|
|
6
6
|
export class TtlSessionStore {
|
|
7
|
+
retention = "none";
|
|
8
|
+
durability;
|
|
7
9
|
repo;
|
|
8
10
|
entries = new Map();
|
|
9
11
|
owners = new Map();
|
|
@@ -14,6 +16,9 @@ export class TtlSessionStore {
|
|
|
14
16
|
sweepTimer;
|
|
15
17
|
constructor(opts = {}) {
|
|
16
18
|
this.repo = opts.repo ?? new InMemorySessionRepo();
|
|
19
|
+
const durability = opts.durability ?? (opts.repo === undefined ? "process-local" : undefined);
|
|
20
|
+
if (durability !== undefined)
|
|
21
|
+
this.durability = durability;
|
|
17
22
|
this.defaultTtlMs = (opts.defaultTtlDays ?? SESSION_DEFAULT_TTL_DAYS) * DAY_MS;
|
|
18
23
|
this.evictPolicy = opts.evict ?? (opts.repo ? "forget" : "delete");
|
|
19
24
|
if (opts.sweepIntervalMs !== undefined && opts.sweepIntervalMs > 0) {
|
package/dist/core/session.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface SessionStoreSummary {
|
|
|
20
20
|
forkedFrom?: string;
|
|
21
21
|
}
|
|
22
22
|
export interface SessionStore {
|
|
23
|
+
readonly durability?: import("./checkpoint-store.js").StoreDurability;
|
|
23
24
|
acquire(sessionId?: string, opts?: {
|
|
24
25
|
requireExisting?: boolean;
|
|
25
26
|
}): Promise<AcquiredSession>;
|
|
@@ -52,6 +52,25 @@ export async function backgroundAgentStoreContract(mk, runAssertion) {
|
|
|
52
52
|
assert.equal(await store.get("a1", "tenant-C"), null, "an unrelated scope must not see the row");
|
|
53
53
|
assert.equal(await store.get("a-missing", S), null);
|
|
54
54
|
});
|
|
55
|
+
run("the org-admission fields round-trip, and ABSENT stays absent (a backend must not invent a verdict)", async (make) => {
|
|
56
|
+
const store = make();
|
|
57
|
+
await store.put(record({ handle: "a1", admittedOrgScopes: ["org:acme", "org:beta"], admittedOrgWriteScope: "org:acme" }));
|
|
58
|
+
const withVerdict = await held(store, "a1");
|
|
59
|
+
assert.deepEqual(withVerdict.admittedOrgScopes, ["org:acme", "org:beta"]);
|
|
60
|
+
assert.equal(withVerdict.admittedOrgWriteScope, "org:acme");
|
|
61
|
+
await store.put(record({ handle: "a2", admittedOrgScopes: [], admittedOrgWriteScope: null }));
|
|
62
|
+
const readOnly = await held(store, "a2");
|
|
63
|
+
assert.deepEqual(readOnly.admittedOrgScopes, []);
|
|
64
|
+
assert.equal(readOnly.admittedOrgWriteScope, null);
|
|
65
|
+
await store.put(record({ handle: "a3" }));
|
|
66
|
+
const untouched = await held(store, "a3");
|
|
67
|
+
assert.equal(untouched.admittedOrgScopes, undefined);
|
|
68
|
+
assert.equal(untouched.admittedOrgWriteScope, undefined);
|
|
69
|
+
await store.update("a3", S, { ...untouched, admittedOrgScopes: ["org:acme"], admittedOrgWriteScope: null }, { rev: untouched.rev });
|
|
70
|
+
const afterCas = await held(store, "a3");
|
|
71
|
+
assert.deepEqual(afterCas.admittedOrgScopes, ["org:acme"]);
|
|
72
|
+
assert.equal(afterCas.admittedOrgWriteScope, null);
|
|
73
|
+
});
|
|
55
74
|
run("put refuses a scopeless row (a row with no tenant partition would be world-readable)", async (make) => {
|
|
56
75
|
const store = make();
|
|
57
76
|
await assert.rejects(store.put(record({ scope: "" })), "an empty scope must be refused loudly, not stored");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { strict as assert } from "node:assert";
|
|
2
|
-
import { mintCheckpointToken, } from "../checkpoint-store.js";
|
|
2
|
+
import { MAX_PENDING_STEER_ENTRIES, mintCheckpointToken, readPendingSteerQueue, } from "../checkpoint-store.js";
|
|
3
3
|
import { beginContract } from "./contract-harness.js";
|
|
4
4
|
export function createCheckpointFixture(over = {}) {
|
|
5
5
|
const token = over.token ?? mintCheckpointToken();
|
|
@@ -90,9 +90,68 @@ export async function checkpointStoreContract(make, runAssertion) {
|
|
|
90
90
|
const cp = createCheckpointFixture();
|
|
91
91
|
await store.put(cp.token, cp);
|
|
92
92
|
await assert.rejects(store.setPendingSteer(cp.token, cp.scope, { text: "</SYSTEM-REMINDER>", trusted: true }), (e) => e.code === "steering.invalid_content");
|
|
93
|
-
assert.
|
|
93
|
+
assert.deepEqual(readPendingSteerQueue((await store.get(cp.token)).state), []);
|
|
94
94
|
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: "go", trusted: false }), true);
|
|
95
|
-
|
|
95
|
+
const q = readPendingSteerQueue((await store.get(cp.token)).state);
|
|
96
|
+
assert.equal(q.length, 1);
|
|
97
|
+
assert.equal(q[0].text, "go");
|
|
98
|
+
assert.equal(q[0].trusted, false);
|
|
99
|
+
assert.equal(q[0].seq, 1);
|
|
100
|
+
assert.equal((await store.get(cp.token)).state.pendingSteer, undefined);
|
|
101
|
+
});
|
|
102
|
+
run("setPendingSteer APPENDS: two steers both survive in issue order, each keeping its frozen trust", async () => {
|
|
103
|
+
const store = make();
|
|
104
|
+
const cp = createCheckpointFixture();
|
|
105
|
+
await store.put(cp.token, cp);
|
|
106
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: "first", trusted: false }), true);
|
|
107
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: "second", trusted: true }), true);
|
|
108
|
+
const q = readPendingSteerQueue((await store.get(cp.token)).state);
|
|
109
|
+
assert.deepEqual(q.map((e) => e.text), ["first", "second"]);
|
|
110
|
+
assert.deepEqual(q.map((e) => e.trusted), [false, true]);
|
|
111
|
+
assert.deepEqual(q.map((e) => e.seq), [1, 2]);
|
|
112
|
+
});
|
|
113
|
+
run("setPendingSteer is idempotent on inputId (a retry with the caller's own message id adds nothing)", async () => {
|
|
114
|
+
const store = make();
|
|
115
|
+
const cp = createCheckpointFixture();
|
|
116
|
+
await store.put(cp.token, cp);
|
|
117
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: "once", trusted: false, inputId: "m1" }), true);
|
|
118
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: "once", trusted: false, inputId: "m1" }), true);
|
|
119
|
+
assert.equal(readPendingSteerQueue((await store.get(cp.token)).state).length, 1);
|
|
120
|
+
});
|
|
121
|
+
run("the queue bound is fail-loud steering.queue_full and evicts nothing", async () => {
|
|
122
|
+
const store = make();
|
|
123
|
+
const cp = createCheckpointFixture();
|
|
124
|
+
await store.put(cp.token, cp);
|
|
125
|
+
for (let i = 0; i < MAX_PENDING_STEER_ENTRIES; i++) {
|
|
126
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, { text: `s${i}`, trusted: false }), true);
|
|
127
|
+
}
|
|
128
|
+
await assert.rejects(store.setPendingSteer(cp.token, cp.scope, { text: "overflow", trusted: false }), (e) => e.code === "steering.queue_full");
|
|
129
|
+
const q = readPendingSteerQueue((await store.get(cp.token)).state);
|
|
130
|
+
assert.equal(q.length, MAX_PENDING_STEER_ENTRIES);
|
|
131
|
+
assert.deepEqual(q.map((e) => e.text), Array.from({ length: MAX_PENDING_STEER_ENTRIES }, (_, i) => `s${i}`));
|
|
132
|
+
});
|
|
133
|
+
run("a queue entry round-trips every FROZEN field (actor/inputId/priority included)", async () => {
|
|
134
|
+
const store = make();
|
|
135
|
+
const cp = createCheckpointFixture();
|
|
136
|
+
await store.put(cp.token, cp);
|
|
137
|
+
assert.equal(await store.setPendingSteer(cp.token, cp.scope, {
|
|
138
|
+
text: "attributed",
|
|
139
|
+
trusted: true,
|
|
140
|
+
actor: { id: "slack:U1", hostAsserted: true, issuer: "slack-app:A1" },
|
|
141
|
+
inputId: "m-42",
|
|
142
|
+
priority: "now",
|
|
143
|
+
}), true);
|
|
144
|
+
const q = readPendingSteerQueue((await store.get(cp.token)).state);
|
|
145
|
+
assert.deepEqual(q, [
|
|
146
|
+
{ text: "attributed", trusted: true, actor: { id: "slack:U1", hostAsserted: true, issuer: "slack-app:A1" }, inputId: "m-42", priority: "now", seq: 1 },
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
run("an unknown steering field is REFUSED (a producer must not have its new field silently dropped)", async () => {
|
|
150
|
+
const store = make();
|
|
151
|
+
const cp = createCheckpointFixture();
|
|
152
|
+
await store.put(cp.token, cp);
|
|
153
|
+
await assert.rejects(store.setPendingSteer(cp.token, cp.scope, { text: "go", trusted: false, futureField: 1 }), (e) => e.code === "steering.invalid_content");
|
|
154
|
+
assert.deepEqual(readPendingSteerQueue((await store.get(cp.token)).state), []);
|
|
96
155
|
});
|
|
97
156
|
run("expire vs resolve on the same row → exactly one wins; reap expires past-deadline pending in scope", async () => {
|
|
98
157
|
const store = make();
|
|
@@ -41,6 +41,8 @@ export interface SystemInjection<TPayload = unknown> {
|
|
|
41
41
|
}
|
|
42
42
|
export declare function taskNotificationDedupKey(n: Pick<TaskNotificationPayload, "task_id" | "task_type" | "status" | "seq">): string;
|
|
43
43
|
export declare function taskNotificationLaneKey(n: Pick<TaskNotificationPayload, "task_id" | "task_type">): string;
|
|
44
|
+
export declare function attrEscape(value: string): string;
|
|
45
|
+
export declare const EXTERNAL_SOURCE_MAX = 120;
|
|
44
46
|
export declare function renderTaskNotificationXml(n: TaskNotificationPayload): string;
|
|
45
47
|
export declare const MAX_PENDING_EVENTS_PER_TASK = 50;
|
|
46
48
|
export declare const MAX_PENDING_EVENTS_PER_SESSION = 200;
|
|
@@ -38,10 +38,10 @@ export function taskNotificationDedupKey(n) {
|
|
|
38
38
|
export function taskNotificationLaneKey(n) {
|
|
39
39
|
return n.task_type === "external" ? `external:${n.task_id}` : n.task_id;
|
|
40
40
|
}
|
|
41
|
-
function attrEscape(value) {
|
|
41
|
+
export function attrEscape(value) {
|
|
42
42
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
43
43
|
}
|
|
44
|
-
const EXTERNAL_SOURCE_MAX = 120;
|
|
44
|
+
export const EXTERNAL_SOURCE_MAX = 120;
|
|
45
45
|
export function renderTaskNotificationXml(n) {
|
|
46
46
|
const usage = n.usage === undefined
|
|
47
47
|
? undefined
|
|
@@ -54,7 +54,9 @@ export function renderTaskNotificationXml(n) {
|
|
|
54
54
|
}
|
|
55
55
|
})();
|
|
56
56
|
const open = n.task_type === "external"
|
|
57
|
-
? `<task-notification type="external"${n.source !== undefined
|
|
57
|
+
? `<task-notification type="external"${n.source !== undefined
|
|
58
|
+
? ` from="${attrEscape(inlineUntrusted(n.source, EXTERNAL_SOURCE_MAX))}" from-unverified="true"`
|
|
59
|
+
: ""}>`
|
|
58
60
|
: "<task-notification>";
|
|
59
61
|
return [
|
|
60
62
|
open,
|
|
@@ -28,6 +28,7 @@ export declare function reapDurableAgentsLane(core: DurableAgentCore, scope: str
|
|
|
28
28
|
}>;
|
|
29
29
|
export declare function releaseDurableTranscriptAnchorLane(core: DurableAgentCore, id: string): void;
|
|
30
30
|
export declare function bindBackgroundAgentSessionLane(core: DurableAgentCore, id: string, sessionId: string): void;
|
|
31
|
+
export declare function recordBackgroundAgentOrgAdmissionLane(core: DurableAgentCore, id: string, verdict: import("./memory-admission.js").OwnOrgAdmissionVerdict): void;
|
|
31
32
|
export declare function registerBackgroundAgentLane(core: DurableAgentCore, input: RegisterBackgroundAgentInput): string;
|
|
32
33
|
export declare function parkBackgroundAgentLane(core: DurableAgentCore, id: string, park: {
|
|
33
34
|
checkpointToken: string;
|
|
@@ -247,6 +247,12 @@ export function bindBackgroundAgentSessionLane(core, id, sessionId) {
|
|
|
247
247
|
handle.sessionId = sessionId;
|
|
248
248
|
durableAgentWriteLane(handle, { sessionId });
|
|
249
249
|
}
|
|
250
|
+
export function recordBackgroundAgentOrgAdmissionLane(core, id, verdict) {
|
|
251
|
+
const handle = core.handles.get(id);
|
|
252
|
+
if (!handle || handle.type !== "background_agent")
|
|
253
|
+
return;
|
|
254
|
+
durableAgentWriteLane(handle, { admittedOrgScopes: [...verdict.scopes], admittedOrgWriteScope: verdict.writeScope });
|
|
255
|
+
}
|
|
250
256
|
export function registerBackgroundAgentLane(core, input) {
|
|
251
257
|
assertOwnership(input, "registerBackgroundAgent");
|
|
252
258
|
if (input.id !== undefined && !DURABLE_AGENT_HANDLE_RE.test(input.id)) {
|
|
@@ -101,6 +101,7 @@ export declare class TaskRegistry {
|
|
|
101
101
|
releaseDurableTranscriptAnchor(id: string): void;
|
|
102
102
|
bindBackgroundAgentSession(id: string, sessionId: string): void;
|
|
103
103
|
registerBackgroundAgent(input: RegisterBackgroundAgentInput): string;
|
|
104
|
+
recordBackgroundAgentOrgAdmission(id: string, verdict: import("./memory-admission.js").OwnOrgAdmissionVerdict): void;
|
|
104
105
|
parkBackgroundAgent(id: string, park: {
|
|
105
106
|
checkpointToken: string;
|
|
106
107
|
seq?: number;
|
|
@@ -10,7 +10,7 @@ import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task
|
|
|
10
10
|
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
11
|
export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
|
|
12
12
|
import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_CONTRACT, TASK_STOP_CONTRACT, 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";
|
|
13
|
-
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
13
|
+
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
14
14
|
export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
|
|
15
15
|
const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
|
|
16
16
|
const BLOCK_MAX_TIMEOUT_MS = 600_000;
|
|
@@ -146,6 +146,9 @@ export class TaskRegistry {
|
|
|
146
146
|
registerBackgroundAgent(input) {
|
|
147
147
|
return registerBackgroundAgentLane(this.core, input);
|
|
148
148
|
}
|
|
149
|
+
recordBackgroundAgentOrgAdmission(id, verdict) {
|
|
150
|
+
return recordBackgroundAgentOrgAdmissionLane(this.core, id, verdict);
|
|
151
|
+
}
|
|
149
152
|
parkBackgroundAgent(id, park) {
|
|
150
153
|
return parkBackgroundAgentLane(this.core, id, park);
|
|
151
154
|
}
|
|
@@ -80,12 +80,17 @@ export interface AskRequest {
|
|
|
80
80
|
toolCallId: string;
|
|
81
81
|
args: unknown;
|
|
82
82
|
readonly preview?: unknown;
|
|
83
|
+
readonly boundInputHash?: string;
|
|
83
84
|
message: string;
|
|
84
85
|
readonly principal?: string;
|
|
85
86
|
readonly sourceTaskId?: string;
|
|
86
87
|
readonly fromSubagent?: true;
|
|
87
88
|
readonly sourceAgentName?: string;
|
|
88
89
|
readonly requiresRealApproval?: boolean;
|
|
90
|
+
readonly riskAxes?: {
|
|
91
|
+
readonly irreversible?: boolean;
|
|
92
|
+
readonly egress?: boolean;
|
|
93
|
+
};
|
|
89
94
|
readonly delegation?: AskDelegationProvenance;
|
|
90
95
|
}
|
|
91
96
|
export type OnAsk = "deny" | "allow" | ((req: AskRequest, signal?: AbortSignal) => AskOutcome | Promise<AskOutcome>);
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { isAbsolute, join, normalize as normalizePath, sep } from "node:path";
|
|
3
3
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
4
|
+
import { boundInputHashOf } from "./canonical-json.js";
|
|
4
5
|
import { writeTargetPath } from "../tools/fs/safety.js";
|
|
5
6
|
export function decisionText(d) {
|
|
6
7
|
return d.message;
|
|
@@ -606,7 +607,7 @@ export async function resolveAsk(req, onAsk, signal) {
|
|
|
606
607
|
decisionReason: "mode",
|
|
607
608
|
};
|
|
608
609
|
}
|
|
609
|
-
ok = await onAsk({ ...req, args: approverView.value }, signal);
|
|
610
|
+
ok = await onAsk({ ...req, boundInputHash: boundInputHashOf(presented.value), args: approverView.value }, signal);
|
|
610
611
|
}
|
|
611
612
|
catch (err) {
|
|
612
613
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
2
2
|
export interface ToolResultStore {
|
|
3
|
+
readonly retention?: import("./retention.js").RetentionDeclaration;
|
|
3
4
|
put(ref: string, content: string): Promise<void> | void;
|
|
4
5
|
get(ref: string, opts?: {
|
|
5
6
|
offset?: number;
|
|
@@ -15,6 +16,7 @@ export interface ToolResultSlice {
|
|
|
15
16
|
}
|
|
16
17
|
export declare class InMemoryToolResultStore implements ToolResultStore {
|
|
17
18
|
private readonly opts?;
|
|
19
|
+
readonly retention: "none";
|
|
18
20
|
private readonly map;
|
|
19
21
|
private totalChars;
|
|
20
22
|
constructor(opts?: {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
2
|
import type { AgentTool, ThinkingLevel } from "../internal/harness.js";
|
|
3
|
-
import type { CompleteSimpleFn, DocumentContent, ImageContent, Model, ResilienceOptions, StreamFn, TextContent } from "../internal/llm.js";
|
|
3
|
+
import type { ActorAssertion, CompleteSimpleFn, DocumentContent, ImageContent, Model, ResilienceOptions, StreamFn, TextContent } from "../internal/llm.js";
|
|
4
4
|
import type { TaskNotificationPayload } from "./task-notification.js";
|
|
5
5
|
export type ModelRef = string | Model;
|
|
6
6
|
export interface StaleToolResultOffloadOptions {
|
|
@@ -129,6 +129,7 @@ export interface ToolExecuteContext {
|
|
|
129
129
|
taskId?: string;
|
|
130
130
|
sessionId?: string;
|
|
131
131
|
backgroundScope?: "task" | "session";
|
|
132
|
+
interactionPosture?: "interactive" | "headless";
|
|
132
133
|
onBackgroundChildEvent?: (event: BackgroundChildEvent) => void;
|
|
133
134
|
onTaskNotification?: (n: import("./task-notification.js").TaskNotificationPayload, opts?: {
|
|
134
135
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
@@ -274,6 +275,9 @@ export interface TaskSpec {
|
|
|
274
275
|
taskId?: string;
|
|
275
276
|
objective: string;
|
|
276
277
|
principal?: string;
|
|
278
|
+
actor?: ActorAssertion;
|
|
279
|
+
interactionPosture?: "interactive" | "headless";
|
|
280
|
+
interactiveQuestionFallback?: boolean;
|
|
277
281
|
images?: ImageInput[];
|
|
278
282
|
sessionId?: string;
|
|
279
283
|
requireExistingSession?: boolean;
|
|
@@ -436,6 +440,10 @@ export interface TaskResult {
|
|
|
436
440
|
code: "conversation_only" | "files_env_unsupported" | "snapshot_store_unconfigured";
|
|
437
441
|
message: string;
|
|
438
442
|
}>;
|
|
443
|
+
strandedHumanAnswers?: ReadonlyArray<{
|
|
444
|
+
deliveryId: string;
|
|
445
|
+
toolCallId: string;
|
|
446
|
+
}>;
|
|
439
447
|
stats: {
|
|
440
448
|
turns: number;
|
|
441
449
|
tokens: number;
|
|
@@ -517,6 +525,9 @@ export interface ToolActivity {
|
|
|
517
525
|
arg?: string;
|
|
518
526
|
isError?: boolean;
|
|
519
527
|
}
|
|
528
|
+
export type HumanInputSource = "objective" | "steer" | "next_turn" | "wake" | "external" | "system";
|
|
529
|
+
export type HumanInputDelivery = "applied" | "queued" | "parked_for_wake";
|
|
530
|
+
export type DelegationTaskType = Extract<TaskNotificationPayload["task_type"], "background_agent" | "workflow">;
|
|
520
531
|
export type TaskEvent = ({
|
|
521
532
|
type: "text_delta";
|
|
522
533
|
delta: string;
|
|
@@ -584,7 +595,7 @@ export type TaskEvent = ({
|
|
|
584
595
|
reason?: string;
|
|
585
596
|
} & TaskEventIdentity) | ({
|
|
586
597
|
type: "steering_injected";
|
|
587
|
-
source: "limit_approach" | "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";
|
|
598
|
+
source: "limit_approach" | "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" | "final_verification";
|
|
588
599
|
preview: string;
|
|
589
600
|
} & TaskEventIdentity) | ({
|
|
590
601
|
type: "diagnostics";
|
|
@@ -613,6 +624,17 @@ export type TaskEvent = ({
|
|
|
613
624
|
entryId: string;
|
|
614
625
|
role: "user" | "assistant" | "toolResult";
|
|
615
626
|
toolCallId?: string;
|
|
627
|
+
} & TaskEventIdentity) | ({
|
|
628
|
+
type: "human_input";
|
|
629
|
+
inputId: string;
|
|
630
|
+
sessionSeq: number;
|
|
631
|
+
carrier: string;
|
|
632
|
+
source: HumanInputSource;
|
|
633
|
+
issuer?: string;
|
|
634
|
+
actor?: ActorAssertion;
|
|
635
|
+
delivery: HumanInputDelivery;
|
|
636
|
+
principal?: string;
|
|
637
|
+
entryId?: string;
|
|
616
638
|
} & TaskEventIdentity) | ({
|
|
617
639
|
type: "status";
|
|
618
640
|
} & BrainStatus & TaskEventIdentity) | ({
|
|
@@ -621,6 +643,7 @@ export type TaskEvent = ({
|
|
|
621
643
|
} & TaskEventIdentity) | ({
|
|
622
644
|
type: "task_progress";
|
|
623
645
|
taskId: string;
|
|
646
|
+
taskType?: DelegationTaskType;
|
|
624
647
|
workflowRunId?: string;
|
|
625
648
|
workflowAgentLabel?: string;
|
|
626
649
|
parentTaskId?: string;
|
|
@@ -635,16 +658,23 @@ export type TaskEvent = ({
|
|
|
635
658
|
} & TaskEventIdentity) | ({
|
|
636
659
|
type: "workspace_changed";
|
|
637
660
|
cwd: string;
|
|
661
|
+
} & TaskEventIdentity) | ({
|
|
662
|
+
type: "wiring_manifest";
|
|
663
|
+
manifest: import("./wiring-manifest.js").WiringManifest;
|
|
638
664
|
} & TaskEventIdentity) | {
|
|
639
665
|
type: "done";
|
|
640
666
|
result: TaskResult;
|
|
641
667
|
};
|
|
668
|
+
export type HumanInputEvent = Extract<TaskEvent, {
|
|
669
|
+
type: "human_input";
|
|
670
|
+
}>;
|
|
642
671
|
export type CompactOutcome = "compacted" | "failed" | "mooted" | "noop" | "blocked" | "disabled";
|
|
643
672
|
export interface TaskStream extends AsyncIterable<TaskEvent> {
|
|
644
673
|
result(): Promise<TaskResult>;
|
|
645
674
|
suggestions(): Promise<string[]>;
|
|
646
675
|
steer(text: string, options?: {
|
|
647
676
|
trusted?: boolean;
|
|
677
|
+
actor?: ActorAssertion;
|
|
648
678
|
}): Promise<void>;
|
|
649
679
|
notify(payload: import("./task-notification.js").ExternalNotificationInput, opts?: {
|
|
650
680
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
@@ -737,6 +767,11 @@ export interface RunnerDeps {
|
|
|
737
767
|
fileSnapshotStore?: import("./file-snapshot-store.js").FileSnapshotStore;
|
|
738
768
|
sessionPolicyStore?: import("./session-policy-store.js").SessionPolicyStore;
|
|
739
769
|
runtimeCapsResolver?: (principal: string | undefined) => RuntimeCaps | undefined | Promise<RuntimeCaps | undefined>;
|
|
770
|
+
lockedConfig?: import("./locked-config.js").LockedConfig;
|
|
771
|
+
compliancePostureResolver?: (principal: string | undefined) => import("./compliance.js").CompliancePosture | undefined | Promise<import("./compliance.js").CompliancePosture | undefined>;
|
|
772
|
+
memoryScopeAdmission?: import("./memory-admission.js").MemoryScopeAdmission;
|
|
773
|
+
deploymentMemoryScopes?: readonly string[];
|
|
774
|
+
retentionPolicy?: import("./retention.js").RetentionPolicy;
|
|
740
775
|
autoMode?: {
|
|
741
776
|
rules?: import("./auto-mode-prompt.js").AutoModeRules;
|
|
742
777
|
settingsDenyRules?: readonly string[];
|
|
@@ -793,6 +828,7 @@ export interface RunnerDeps {
|
|
|
793
828
|
toolPolicy?: import("./tool-policy.js").ToolPolicy;
|
|
794
829
|
onAsk?: import("./tool-policy.js").OnAsk;
|
|
795
830
|
onQuestion?: import("./ask-question.js").OnQuestion;
|
|
831
|
+
interactionPosture?: "interactive" | "headless";
|
|
796
832
|
lspManager?: import("./lsp.js").LspServerManager;
|
|
797
833
|
hooks?: import("./hooks.js").Hooks;
|
|
798
834
|
allowImageUrl?: (url: string) => boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { RunnerDeps, TaskSpec } from "./types.js";
|
|
2
|
+
import { type StoreDurability } from "./checkpoint-store.js";
|
|
3
|
+
export type { StoreDurability };
|
|
4
|
+
export type ManifestDurability = "declared_durable" | "process_local";
|
|
5
|
+
export type WiringLegKind = "root" | "child" | "resume";
|
|
6
|
+
export type AskSeamForm = "callback" | "allow" | "deny" | "absent";
|
|
7
|
+
export type AskEffective = "human_reachable" | "auto_allow" | "auto_deny" | "park_only" | "unresolved";
|
|
8
|
+
export type QuestionChannelState = "wired" | "absent" | "stripped_bg_lane";
|
|
9
|
+
export type SeamProvenance = "spec" | "deps";
|
|
10
|
+
export type ParkLaneReason = "no_checkpoint_store" | "no_durable_approval_opt_in" | "no_force_durable_gate" | "no_armed_safety_vocabulary" | "await_runtime_caps" | "await_tool_vocabulary";
|
|
11
|
+
export interface WiringManifest {
|
|
12
|
+
schemaVersion: 1;
|
|
13
|
+
leg?: {
|
|
14
|
+
kind: WiringLegKind;
|
|
15
|
+
};
|
|
16
|
+
ask: {
|
|
17
|
+
form: AskSeamForm;
|
|
18
|
+
provenance?: SeamProvenance;
|
|
19
|
+
effective?: AskEffective;
|
|
20
|
+
};
|
|
21
|
+
question: {
|
|
22
|
+
wired: QuestionChannelState;
|
|
23
|
+
provenance?: SeamProvenance;
|
|
24
|
+
interactiveToolsWithoutDeliveryFace?: true;
|
|
25
|
+
};
|
|
26
|
+
interaction: {
|
|
27
|
+
posture: "interactive" | "headless" | "absent";
|
|
28
|
+
};
|
|
29
|
+
elicit: {
|
|
30
|
+
seamWired: boolean;
|
|
31
|
+
serversOptedIn: number;
|
|
32
|
+
};
|
|
33
|
+
parkLane: {
|
|
34
|
+
capable: boolean;
|
|
35
|
+
effective: boolean | "unresolved";
|
|
36
|
+
reasons: readonly ParkLaneReason[];
|
|
37
|
+
checkpointDurability?: ManifestDurability;
|
|
38
|
+
};
|
|
39
|
+
session: {
|
|
40
|
+
store: ManifestDurability;
|
|
41
|
+
};
|
|
42
|
+
fleet: {
|
|
43
|
+
backgroundAgentStore: boolean;
|
|
44
|
+
hostChildEventSink: boolean;
|
|
45
|
+
};
|
|
46
|
+
governance: {
|
|
47
|
+
audience: "operator";
|
|
48
|
+
lockedConfig: boolean;
|
|
49
|
+
compliance: boolean;
|
|
50
|
+
memoryAdmission: boolean;
|
|
51
|
+
retention: boolean;
|
|
52
|
+
};
|
|
53
|
+
configFingerprint?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface WiringFacts {
|
|
56
|
+
half: "static" | "effective";
|
|
57
|
+
leg?: WiringLegKind;
|
|
58
|
+
askForm: AskSeamForm;
|
|
59
|
+
askProvenance?: SeamProvenance;
|
|
60
|
+
questionWired: boolean;
|
|
61
|
+
questionProvenance?: SeamProvenance;
|
|
62
|
+
questionStrippedByEngine?: boolean;
|
|
63
|
+
interactiveToolsWithoutDeliveryFace?: boolean;
|
|
64
|
+
interactionPosture?: "interactive" | "headless";
|
|
65
|
+
elicitSeamWired: boolean;
|
|
66
|
+
elicitServersOptedIn: number;
|
|
67
|
+
parkCapable: boolean;
|
|
68
|
+
parkDurableApprovalOptIn: boolean;
|
|
69
|
+
parkForceDurableGate?: boolean;
|
|
70
|
+
parkSafetyVocabularyArmed?: boolean;
|
|
71
|
+
checkpointDurability?: StoreDurability;
|
|
72
|
+
sessionDurability: StoreDurability;
|
|
73
|
+
backgroundAgentStoreWired: boolean;
|
|
74
|
+
hostChildEventSinkWired: boolean;
|
|
75
|
+
lockedConfigWired: boolean;
|
|
76
|
+
complianceWired: boolean;
|
|
77
|
+
memoryAdmissionWired: boolean;
|
|
78
|
+
retentionPolicyWired: boolean;
|
|
79
|
+
}
|
|
80
|
+
export type StaticWiringDeps = Pick<RunnerDeps, "onAsk" | "onQuestion" | "interactionPosture" | "onElicit" | "checkpointStore" | "sessionStore" | "backgroundAgentStore" | "onBackgroundChildEvent" | "lockedConfig" | "compliancePostureResolver" | "memoryScopeAdmission" | "retentionPolicy">;
|
|
81
|
+
export type StaticWiringSpec = Pick<TaskSpec, "onAsk" | "onQuestion" | "checkpointStore" | "durableApproval" | "mcp" | "interactiveTools" | "interactionPosture">;
|
|
82
|
+
export declare function resolveDeclaredDurability(store: {
|
|
83
|
+
readonly durability?: StoreDurability;
|
|
84
|
+
} | undefined, storeName: string): StoreDurability;
|
|
85
|
+
export declare function deriveAskEffective(form: AskSeamForm, parkEffective: boolean | "unresolved"): AskEffective;
|
|
86
|
+
export declare function deriveWiringManifest(facts: WiringFacts): WiringManifest;
|
|
87
|
+
export declare function resolveAskSeamForm(spec: Pick<TaskSpec, "onAsk">, deps: Pick<RunnerDeps, "onAsk">): {
|
|
88
|
+
form: AskSeamForm;
|
|
89
|
+
provenance?: SeamProvenance;
|
|
90
|
+
};
|
|
91
|
+
export declare function resolveQuestionSeam(spec: Pick<TaskSpec, "onQuestion">, deps: Pick<RunnerDeps, "onQuestion">): {
|
|
92
|
+
wired: boolean;
|
|
93
|
+
provenance?: SeamProvenance;
|
|
94
|
+
};
|
|
95
|
+
export declare function countElicitOptIns(spec: Pick<TaskSpec, "mcp">): number;
|
|
96
|
+
export declare function resolveElicitSeam(deps: Pick<RunnerDeps, "onElicit">): boolean;
|
|
97
|
+
export declare function describeStaticWiring(deps: StaticWiringDeps, spec?: StaticWiringSpec): WiringManifest;
|