@sema-agent/core 7.2.0 → 7.3.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 +43 -0
- package/dist/agents/cross-session-envelope.d.ts +7 -0
- package/dist/agents/cross-session-envelope.js +4 -0
- package/dist/agents/list-agents-tool.d.ts +55 -0
- package/dist/agents/list-agents-tool.js +94 -0
- package/dist/agents/peer-admission.d.ts +17 -1
- package/dist/agents/peer-admission.js +19 -2
- package/dist/agents/peer-directory.d.ts +208 -0
- package/dist/agents/peer-directory.js +272 -0
- package/dist/agents/peer-session-drain.d.ts +159 -0
- package/dist/agents/peer-session-drain.js +245 -0
- package/dist/agents/send-message-tool.d.ts +31 -0
- package/dist/agents/send-message-tool.js +145 -4
- package/dist/agents/subagent-steps.d.ts +11 -0
- package/dist/agents/subagent-steps.js +27 -4
- package/dist/brain/status-sink.d.ts +10 -0
- package/dist/brain/status-sink.js +13 -4
- package/dist/brain/stream-engine.d.ts +11 -0
- package/dist/brain/stream-engine.js +39 -3
- package/dist/core/arg-summary.d.ts +13 -3
- package/dist/core/arg-summary.js +138 -7
- package/dist/core/auto-mode-arming.d.ts +11 -0
- package/dist/core/auto-mode-arming.js +7 -1
- package/dist/core/auto-mode-prompt.d.ts +5 -0
- package/dist/core/auto-mode-prompt.js +2 -1
- package/dist/core/auto-mode-rebuild.d.ts +2 -1
- package/dist/core/auto-mode-rebuild.js +2 -0
- package/dist/core/checkpoint-store.d.ts +14 -0
- package/dist/core/checkpoint-store.js +4 -3
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/mailbox-store.d.ts +89 -2
- package/dist/core/mailbox-store.js +77 -2
- package/dist/core/permission-rule-model.d.ts +9 -0
- package/dist/core/permission-rule-model.js +4 -1
- package/dist/core/runner/prepare-task.d.ts +20 -0
- package/dist/core/runner/prepare-task.js +152 -37
- package/dist/core/runner/runtask.js +5 -2
- package/dist/core/runner/tool-output-projection.js +1 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +23 -0
- package/dist/core/store-contracts/mailbox-store-contract.js +157 -1
- package/dist/core/task-notification.d.ts +38 -9
- package/dist/core/task-notification.js +8 -2
- package/dist/core/tools.js +1 -0
- package/dist/core/types.d.ts +176 -26
- package/dist/core/wiring-manifest.d.ts +62 -5
- package/dist/core/wiring-manifest.js +9 -0
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +3 -0
- package/dist/engine/harness/types.d.ts +3 -0
- package/dist/engine/loop/agent-loop.d.ts +7 -0
- package/dist/engine/loop/agent-loop.js +79 -0
- package/dist/engine/loop/types.d.ts +42 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.js +11 -4
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/stores/cc/mailbox-store.d.ts +1 -1
- package/dist/stores/cc/mailbox-store.js +13 -0
- package/dist/stores/file/adoption/marker.d.ts +1 -1
- package/dist/stores/file/mailbox-store.d.ts +57 -0
- package/dist/stores/file/mailbox-store.js +369 -18
- package/dist/tools/fs/fs-write.js +69 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +121 -1
|
@@ -171,6 +171,9 @@ export function escapeForDisclosure(value) {
|
|
|
171
171
|
return escaped.length <= DISCLOSED_RULE_TEXT_MAX_CHARS ? escaped : `${escaped.slice(0, DISCLOSED_RULE_TEXT_MAX_CHARS)}…`;
|
|
172
172
|
}
|
|
173
173
|
const DISPLAY_STRIP_FORMAT_RE = /\p{Cf}/gu;
|
|
174
|
+
export function stripFormatCharacters(text) {
|
|
175
|
+
return text.replace(DISPLAY_STRIP_FORMAT_RE, "");
|
|
176
|
+
}
|
|
174
177
|
export function renderUntrustedCommandText(text, maxLen = DISCLOSED_RULE_TEXT_MAX_CHARS) {
|
|
175
178
|
let raw;
|
|
176
179
|
try {
|
|
@@ -179,7 +182,7 @@ export function renderUntrustedCommandText(text, maxLen = DISCLOSED_RULE_TEXT_MA
|
|
|
179
182
|
catch {
|
|
180
183
|
return "<unprintable>";
|
|
181
184
|
}
|
|
182
|
-
return inlineUntrusted(raw
|
|
185
|
+
return inlineUntrusted(stripFormatCharacters(raw), maxLen);
|
|
183
186
|
}
|
|
184
187
|
export function hasUnrenderableCharacters(text) {
|
|
185
188
|
return CONTROL_CHARS_RE.test(text);
|
|
@@ -41,6 +41,13 @@ export declare function __resetMaterializeEnvAnnouncements(): void;
|
|
|
41
41
|
* seam below (console latch only): tests here legitimately reuse ONE sink across prepares to pin
|
|
42
42
|
* the per-sink dedup itself, so the seam must be able to re-arm a still-referenced sink. */
|
|
43
43
|
export declare function __resetToolModelGateAnnouncements(): void;
|
|
44
|
+
/**
|
|
45
|
+
* The model gate's per-session READ face ({@link WiringManifest.modelGate}) — projected from the SAME
|
|
46
|
+
* gate decision {@link announceToolModelGate} reads (one source; the notice is the operator-sink
|
|
47
|
+
* dialect, this the manifest dialect). `undefined` when no default-mounted tool was trimmed on this
|
|
48
|
+
* run. The restore sentence is the notice's, verbatim.
|
|
49
|
+
*/
|
|
50
|
+
export declare const TOOL_MODEL_GATE_RESTORE_SENTENCE = "restore via TaskSpec.restoreGatedTools, SEMA_TOOL_MODEL_GATE=off, or RunnerDeps.toolModelGate: false";
|
|
44
51
|
export { __resetReadFaceClampAnnouncement } from "./prepare-hands-readface.js";
|
|
45
52
|
/**
|
|
46
53
|
* design/164 件四 — how long before an execution environment's declared `lifetimeMs` expires the engine
|
|
@@ -1177,6 +1184,19 @@ export interface InheritedGate {
|
|
|
1177
1184
|
}>;
|
|
1178
1185
|
/** The chain's effective shell-gate doctrine — the child folds it by max-rank with its own spec. */
|
|
1179
1186
|
shellGate?: "off" | "always" | "classify";
|
|
1187
|
+
/**
|
|
1188
|
+
* The chain's AUTO-MODE INTENT (`TaskSpec.autoModeRequested`, session-wide like a permission mode):
|
|
1189
|
+
* emitted when the spawning task carried the intent itself or inherited it, so an engine-spawned
|
|
1190
|
+
* child of an auto-mode task arms its OWN per-run classifier exactly as its parent did — the
|
|
1191
|
+
* intent half only; the child's deny bit (`RuntimeCaps.autoMode === false`) and deployment face
|
|
1192
|
+
* (`RunnerDeps.autoMode`) are evaluated for the child. Trusted chain data (Runner-assembled, never a
|
|
1193
|
+
* model-authored argument); absent ⇒ the child is an auto-mode task only if its own spec says so.
|
|
1194
|
+
* Persists on the checkpoint's data half (`CheckpointState.inheritedGate.autoModeRequested`) so a
|
|
1195
|
+
* redemption in another process — no seat re-passed, no waking chain — reads the same intent the
|
|
1196
|
+
* suspend leg had; the intent folds by OR across seat, live chain and seed, while the deny bit and
|
|
1197
|
+
* the deployment face stay per-leg.
|
|
1198
|
+
*/
|
|
1199
|
+
autoModeRequested?: true;
|
|
1180
1200
|
/**
|
|
1181
1201
|
* Org-memory admission freeze (ruled 2026-08-05): the spawning chain's FROZEN admitted org-scope
|
|
1182
1202
|
* set — every org memory scope the parent actually mounted (deployment-origin + admitted request).
|
|
@@ -83,6 +83,8 @@ import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.j
|
|
|
83
83
|
import { createTaskOutputTool, createTaskStopTool, defaultTaskRegistry } from "../task-registry.js";
|
|
84
84
|
import { createMonitorTool } from "../../tools/monitor.js";
|
|
85
85
|
import { createWorktreeTools } from "../../tools/worktree.js";
|
|
86
|
+
import { announcePeerLaneMount, bindPeerLaneDrain, listAgentsMountable, mountListAgents, peerLaneSendMessageSeats } from "../../agents/peer-session-drain.js";
|
|
87
|
+
import { CROSS_SESSION_CLASSIFIER_RULE } from "../../agents/cross-session-envelope.js";
|
|
86
88
|
import { applyCompactionToReadFileState, isReadDedupStubResult, FULL_SHELL_CONTRACT_ID, HAND_TOOL_EFFECTS } from "../../tools/fs/index.js";
|
|
87
89
|
import { decodeTextBytes } from "../../tools/fs/encoding.js";
|
|
88
90
|
import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, classifyQuestionOutcome, isLiveQuestionFace, validateAskQuestions, } from "../ask-question.js";
|
|
@@ -198,6 +200,20 @@ function announceToolModelGate(onNotice, modelId, gate) {
|
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
}
|
|
203
|
+
export const TOOL_MODEL_GATE_RESTORE_SENTENCE = "restore via TaskSpec.restoreGatedTools, SEMA_TOOL_MODEL_GATE=off, or RunnerDeps.toolModelGate: false";
|
|
204
|
+
function toolModelGateManifest(gate) {
|
|
205
|
+
let firstClass;
|
|
206
|
+
const removed = [];
|
|
207
|
+
for (const [gateClass, names] of gate.removedByClass) {
|
|
208
|
+
if (names.length === 0)
|
|
209
|
+
continue;
|
|
210
|
+
firstClass ??= gateClass;
|
|
211
|
+
for (const n of names)
|
|
212
|
+
if (!removed.includes(n))
|
|
213
|
+
removed.push(n);
|
|
214
|
+
}
|
|
215
|
+
return firstClass === undefined ? undefined : { class: firstClass, removed, restore: TOOL_MODEL_GATE_RESTORE_SENTENCE };
|
|
216
|
+
}
|
|
201
217
|
function announceDeclaredMcpContentClasses(args) {
|
|
202
218
|
for (const entry of args.entries ?? []) {
|
|
203
219
|
const declaredClass = entry.contentOrigin;
|
|
@@ -1161,14 +1177,113 @@ function refuseRequireExistingWithoutSession(spec) {
|
|
|
1161
1177
|
throw e;
|
|
1162
1178
|
}
|
|
1163
1179
|
}
|
|
1180
|
+
function screenAutoModeCap(caps, onError, sessionId) {
|
|
1181
|
+
if (caps === undefined)
|
|
1182
|
+
return { caps, faulted: false };
|
|
1183
|
+
if (typeof caps !== "object" || caps === null || Array.isArray(caps)) {
|
|
1184
|
+
onError?.(new Error(`runtimeCapsResolver returned a non-record value (${JSON.stringify(caps)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain). Return a RuntimeCaps object or undefined.`), { phase: "config", sessionId });
|
|
1185
|
+
return { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, faulted: true };
|
|
1186
|
+
}
|
|
1187
|
+
const record = caps;
|
|
1188
|
+
if (record.autoMode === undefined || typeof record.autoMode === "boolean")
|
|
1189
|
+
return { caps: record, faulted: false };
|
|
1190
|
+
onError?.(new Error(`runtimeCapsResolver returned a non-boolean autoMode (${JSON.stringify(record.autoMode)}) — read as a resolver fault: auto mode is DENIED for this run (the classifier is not armed; asks flow the original chain). Return true, false, or omit the key.`), { phase: "config", sessionId });
|
|
1191
|
+
return { caps: { ...record, autoMode: false }, faulted: true };
|
|
1192
|
+
}
|
|
1193
|
+
function mintPersistedArming(am, laneRule, classifierSystemPrompt, onError, sessionId) {
|
|
1194
|
+
const arming = autoModeArmingRecipeOf(laneRule ? { ...am, crossSessionMessagesRule: true } : am, {
|
|
1195
|
+
promptDigest: `apv1:${createHash("sha256").update(classifierSystemPrompt).digest("hex")}`,
|
|
1196
|
+
});
|
|
1197
|
+
if (arming === undefined) {
|
|
1198
|
+
onError?.(new Error("RunnerDeps.autoMode.persistArming is set but the auto-mode face did not canonicalize into an arming recipe " +
|
|
1199
|
+
"(a rule list carrying a non-string, or a non-finite/out-of-range timeoutMs / failureThreshold / window bound) — " +
|
|
1200
|
+
"NO arming recipe is recorded on this run's parked constraint chain, and a cross-process redemption keeps the " +
|
|
1201
|
+
"conservative behavior (the ancestor classifier answers unavailable and the inherited ask flows to a human)"), { phase: "config", sessionId });
|
|
1202
|
+
}
|
|
1203
|
+
return arming;
|
|
1204
|
+
}
|
|
1205
|
+
function autoModeLatchHealthy(d) {
|
|
1206
|
+
try {
|
|
1207
|
+
return d.breakerOpen() !== true && typeof d.consecutiveFailures === "function" && d.consecutiveFailures() === 0;
|
|
1208
|
+
}
|
|
1209
|
+
catch {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function autoModeArmReasonOf(intent, facePresent, capsAutoMode, capsFaulted) {
|
|
1214
|
+
if (!intent)
|
|
1215
|
+
return "no_intent";
|
|
1216
|
+
if (!facePresent)
|
|
1217
|
+
return "no_face";
|
|
1218
|
+
if (capsAutoMode === false)
|
|
1219
|
+
return capsFaulted ? "resolver_fault" : "denied";
|
|
1220
|
+
return "armed";
|
|
1221
|
+
}
|
|
1222
|
+
function validateInputFaultNotice(onError, sessionId) {
|
|
1223
|
+
return ({ toolName, toolCallId, error }) => onError?.(new Error(`tool input pre-validation (validateInput) threw for ${toolName} (call ${toolCallId}) — read as no verdict; the call proceeded to the gate: ${error instanceof Error ? error.message : String(error)}`), { phase: "hook", sessionId });
|
|
1224
|
+
}
|
|
1225
|
+
function refuseInvalidAutoModeSeat(spec) {
|
|
1226
|
+
if (spec.autoModeRequested !== undefined && spec.autoModeRequested !== true) {
|
|
1227
|
+
const e = new Error(`autoModeRequested must be the literal true when present (got ${JSON.stringify(spec.autoModeRequested)}) — omit it for a non-auto task; a non-boolean or false value is refused rather than read as either polarity.`);
|
|
1228
|
+
e.code = "config.auto_mode_requested_invalid";
|
|
1229
|
+
throw e;
|
|
1230
|
+
}
|
|
1231
|
+
return spec.autoModeRequested === true;
|
|
1232
|
+
}
|
|
1233
|
+
function announceDurableGateUnavailable(args) {
|
|
1234
|
+
if (!args.forceDurableGate || args.storeWired)
|
|
1235
|
+
return;
|
|
1236
|
+
const cause = args.taskStoreNull ? "task_store_null" : "no_deployment_store";
|
|
1237
|
+
const inheritedContentMandate = (args.parentConstraints ?? []).some((pc) => pc.contentMandate === true);
|
|
1238
|
+
const liveQuestionFace = args.liveQuestionFace && !inheritedContentMandate;
|
|
1239
|
+
deliverEngineNotice(args.onNotice, {
|
|
1240
|
+
code: "config.durable_gate_unavailable",
|
|
1241
|
+
message: `Durable approval gate mandated but unavailable: the runtime entitlement forceDurableGate is in force for this ` +
|
|
1242
|
+
`principal, but ${cause === "task_store_null" ? "this task disabled the checkpoint store (checkpointStore: null)" : "this deployment wired no checkpoint store"}, ` +
|
|
1243
|
+
`so no interactive ask of this task can be parked for a durable answer. Asks resolve on the live chain instead ` +
|
|
1244
|
+
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : "permission asks are denied fail-closed — no live approver is wired"}; ` +
|
|
1245
|
+
`${liveQuestionFace ? "a live question face answers AskUserQuestion in-stream" : args.liveQuestionFace ? "AskUserQuestion is withheld from the live face by an inherited durable mandate and refused" : "AskUserQuestion has no live face and is refused"}) ` +
|
|
1246
|
+
`and NO durable approval record is written. ${cause === "task_store_null" ? "Run this task with its store, or withdraw the entitlement for principals whose runs are machine-started." : "Wire a checkpoint store on this deployment, or withdraw the entitlement for principals served here."}`,
|
|
1247
|
+
detail: {
|
|
1248
|
+
sessionId: args.sessionId,
|
|
1249
|
+
runId: args.runId,
|
|
1250
|
+
...(args.principal ? { principal: args.principal } : {}),
|
|
1251
|
+
cause,
|
|
1252
|
+
liveApprover: args.liveApprover,
|
|
1253
|
+
liveQuestionFace,
|
|
1254
|
+
},
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
function buildTier3ReviveSpawn(delegationForRevive, enrichSpecToolCtx) {
|
|
1258
|
+
if (delegationForRevive === undefined)
|
|
1259
|
+
return undefined;
|
|
1260
|
+
return async (req) => {
|
|
1261
|
+
const out = await delegationForRevive.execute({
|
|
1262
|
+
description: req.row.description ?? "revived teammate",
|
|
1263
|
+
prompt: req.prompt,
|
|
1264
|
+
run_in_background: true,
|
|
1265
|
+
...(req.row.agentType !== undefined ? { subagent_type: req.row.agentType } : {}),
|
|
1266
|
+
...(req.row.name !== undefined ? { name: req.row.name } : {}),
|
|
1267
|
+
...(req.row.model !== undefined ? { model: req.row.model } : {}),
|
|
1268
|
+
}, enrichSpecToolCtx({ toolCallId: `rv-${randomBytes(8).toString("hex")}`, reviveClaim: { row: req.row, rev: req.rev, ...(req.peerSeed !== undefined ? { peerSeed: req.peerSeed } : {}) } }));
|
|
1269
|
+
const o = (typeof out === "string" ? { content: out } : out);
|
|
1270
|
+
return {
|
|
1271
|
+
content: typeof o.content === "string" ? o.content : JSON.stringify(o.content),
|
|
1272
|
+
...(o.isError === true ? { isError: true } : {}),
|
|
1273
|
+
...(o.details !== undefined ? { details: o.details } : {}),
|
|
1274
|
+
};
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1164
1277
|
export async function prepareTask(spec, deps, sessions, resume, internals, runnerSelf, runIdSink) {
|
|
1165
1278
|
const runId = uuidv7();
|
|
1166
1279
|
if (runIdSink !== undefined)
|
|
1167
1280
|
runIdSink.runId = runId;
|
|
1168
1281
|
const doors = prepareConfigDoors({ spec, deps, sessions, resume, internals });
|
|
1169
1282
|
spec = doors.spec;
|
|
1283
|
+
const autoModeSeat = refuseInvalidAutoModeSeat(spec);
|
|
1170
1284
|
const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, microCompactKnob, resolvedRole, model, thinking, compModel, fableMitigations, memoryDelegationEvidence, memoryProvenance, memoryCapturePolicy, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
|
|
1171
1285
|
announceToolModelGate(deps.onNotice, model.id, doors.modelGate);
|
|
1286
|
+
const modelGateManifest = toolModelGateManifest(doors.modelGate);
|
|
1172
1287
|
const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes, ownToolNames } = prepareSafetyScan({ spec, deps });
|
|
1173
1288
|
let shellGatedBash = false;
|
|
1174
1289
|
let shellGatedMonitor = false;
|
|
@@ -1188,6 +1303,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1188
1303
|
const taskScope = internals?.registryScope ?? spec.principal ?? "default";
|
|
1189
1304
|
internals?.peerSelfRef?.addAxis("s", sessionId);
|
|
1190
1305
|
internals?.peerSelfRef?.addAxis("t", hostTaskId);
|
|
1306
|
+
const peerLaneActive = announcePeerLaneMount(deps, { sessionId, runId });
|
|
1307
|
+
const peerLaneRefs = {};
|
|
1308
|
+
const peerSendMessageBuiltIn = runnerSelf !== undefined && !(toolFaceSnapshot.exclude ?? []).includes(SEND_MESSAGE_TOOL_NAME) && !(spec.tools ?? []).some((t) => t.name === SEND_MESSAGE_TOOL_NAME);
|
|
1191
1309
|
const { reminderMark, reminderDisclosureCounts } = await adoptReminderMark(session, sessionId, resume?.seed.reminderMark, internals?.reminderMark, deps.onError);
|
|
1192
1310
|
const offloadScope = spec.principal ?? "default";
|
|
1193
1311
|
if (internals?.registryScope !== undefined && internals.registryScope !== offloadScope) {
|
|
@@ -1575,6 +1693,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1575
1693
|
? liveShellGate
|
|
1576
1694
|
: seedShellGate;
|
|
1577
1695
|
const inheritedParentConstraints = liveInheritedGate?.parentConstraints;
|
|
1696
|
+
const autoModeIntent = autoModeSeat || liveInheritedGate?.autoModeRequested === true || seedInheritedGate?.autoModeRequested === true;
|
|
1578
1697
|
const liveAdmittedOrg = liveInheritedGate?.admittedOrgScopes;
|
|
1579
1698
|
const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
|
|
1580
1699
|
const inheritedAdmittedOrgScopes = liveAdmittedOrg === undefined ? seedAdmittedOrg : seedAdmittedOrg === undefined ? liveAdmittedOrg : liveAdmittedOrg.filter((s) => seedAdmittedOrg.includes(s));
|
|
@@ -1687,6 +1806,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1687
1806
|
return {
|
|
1688
1807
|
...(ancestorRules.length > 0 ? { ancestorRules } : {}),
|
|
1689
1808
|
...(effectiveShellGate !== "off" ? { shellGate: effectiveShellGate } : {}),
|
|
1809
|
+
...(autoModeIntent ? { autoModeRequested: true } : {}),
|
|
1690
1810
|
...(parentConstraints.length > 0 ? { parentConstraints } : {}),
|
|
1691
1811
|
admittedOrgScopes: memoryAdmittedOrgScopesRef.current,
|
|
1692
1812
|
...(orgGovernedProvenance ? { orgAdmissionGoverned: true } : {}),
|
|
@@ -1827,9 +1947,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1827
1947
|
}
|
|
1828
1948
|
catch (err) {
|
|
1829
1949
|
deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
|
|
1830
|
-
runtimeCaps = { allowWorkflows: false, allowFork: false };
|
|
1950
|
+
runtimeCaps = { allowWorkflows: false, allowFork: false, autoMode: false };
|
|
1831
1951
|
runtimeCapsFaulted = true;
|
|
1832
1952
|
}
|
|
1953
|
+
const screened = screenAutoModeCap(runtimeCaps, deps.onError, sessionId);
|
|
1954
|
+
runtimeCaps = screened.caps;
|
|
1955
|
+
runtimeCapsFaulted ||= screened.faulted;
|
|
1833
1956
|
}
|
|
1834
1957
|
let complianceDenies = new Set();
|
|
1835
1958
|
let complianceDegraded = false;
|
|
@@ -1866,7 +1989,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1866
1989
|
}
|
|
1867
1990
|
agentForkDenial = forkGovernanceDenial(spec.enableFork, runtimeCaps?.allowFork);
|
|
1868
1991
|
observersActive = runtimeCaps?.allowObservers === true;
|
|
1869
|
-
|
|
1992
|
+
const autoModeArmReason = autoModeArmReasonOf(autoModeIntent, deps.autoMode !== undefined, runtimeCaps?.autoMode, runtimeCapsFaulted);
|
|
1993
|
+
if (autoModeIntent && deps.autoMode !== undefined && runtimeCaps?.autoMode !== false) {
|
|
1870
1994
|
const am = deps.autoMode;
|
|
1871
1995
|
let classifierModel;
|
|
1872
1996
|
try {
|
|
@@ -1878,7 +2002,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1878
2002
|
if (await derivedRouteFallsBack({ seat: "auto-mode-classifier", derived: classifierModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice, sessionId, runId })) {
|
|
1879
2003
|
classifierModel = model;
|
|
1880
2004
|
}
|
|
1881
|
-
const
|
|
2005
|
+
const classifierLaneRule = peerLaneActive && peerSendMessageBuiltIn;
|
|
2006
|
+
const classifierSystemPrompt = buildAutoModePrompt(classifierLaneRule ? { ...am, crossSessionMessagesRule: CROSS_SESSION_CLASSIFIER_RULE } : am);
|
|
1882
2007
|
const classifierRuntime = brainToRuntime(deps.brain);
|
|
1883
2008
|
autoModeDecider = createAutoModeDecider({
|
|
1884
2009
|
...(am.timeoutMs !== undefined ? { timeoutMs: am.timeoutMs } : {}),
|
|
@@ -1901,17 +2026,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1901
2026
|
.join("");
|
|
1902
2027
|
},
|
|
1903
2028
|
});
|
|
1904
|
-
if (am.persistArming === true)
|
|
1905
|
-
autoModeArming =
|
|
1906
|
-
promptDigest: `apv1:${createHash("sha256").update(classifierSystemPrompt).digest("hex")}`,
|
|
1907
|
-
});
|
|
1908
|
-
if (autoModeArming === undefined) {
|
|
1909
|
-
deps.onError?.(new Error("RunnerDeps.autoMode.persistArming is set but the auto-mode face did not canonicalize into an arming recipe " +
|
|
1910
|
-
"(a rule list carrying a non-string, or a non-finite/out-of-range timeoutMs / failureThreshold / window bound) — " +
|
|
1911
|
-
"NO arming recipe is recorded on this run's parked constraint chain, and a cross-process redemption keeps the " +
|
|
1912
|
-
"conservative behavior (the ancestor classifier answers unavailable and the inherited ask flows to a human)"), { phase: "config", sessionId });
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
2029
|
+
if (am.persistArming === true)
|
|
2030
|
+
autoModeArming = mintPersistedArming(am, classifierLaneRule, classifierSystemPrompt, deps.onError, sessionId);
|
|
1915
2031
|
}
|
|
1916
2032
|
const deploymentWorkflowReady = runnerSelf !== undefined && isSelfOrchestrationActive(spec, deps);
|
|
1917
2033
|
const selfOrchestrationActive = deploymentWorkflowReady && runtimeCaps?.allowWorkflows !== false;
|
|
@@ -2207,7 +2323,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2207
2323
|
shellGatedBash = handsReadFace.shellGatedBash;
|
|
2208
2324
|
shellGatedMonitor = handsReadFace.shellGatedMonitor;
|
|
2209
2325
|
const delegationSurfaceActive = backgroundTaskToolsActive || workflowToolsActive;
|
|
2210
|
-
if (delegationSurfaceActive || internals?.parentNotify !== undefined) {
|
|
2326
|
+
if (delegationSurfaceActive || internals?.parentNotify !== undefined || peerLaneActive) {
|
|
2211
2327
|
if (delegationSurfaceActive) {
|
|
2212
2328
|
toolEffects.set("TaskOutput", "read");
|
|
2213
2329
|
toolEffects.set("TaskStop", "write");
|
|
@@ -2217,24 +2333,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2217
2333
|
toolEffects.set(SEND_MESSAGE_TOOL_NAME, "write");
|
|
2218
2334
|
axisExplicitNegatives.set(SEND_MESSAGE_TOOL_NAME, { ...axisExplicitNegatives.get(SEND_MESSAGE_TOOL_NAME), egress: false });
|
|
2219
2335
|
const delegationForRevive = (spec.tools ?? []).find((t) => t.agentListing !== undefined);
|
|
2220
|
-
const reviveSpawn =
|
|
2221
|
-
? async (req) => {
|
|
2222
|
-
const out = await delegationForRevive.execute({
|
|
2223
|
-
description: req.row.description ?? "revived teammate",
|
|
2224
|
-
prompt: req.prompt,
|
|
2225
|
-
run_in_background: true,
|
|
2226
|
-
...(req.row.agentType !== undefined ? { subagent_type: req.row.agentType } : {}),
|
|
2227
|
-
...(req.row.name !== undefined ? { name: req.row.name } : {}),
|
|
2228
|
-
...(req.row.model !== undefined ? { model: req.row.model } : {}),
|
|
2229
|
-
}, enrichSpecToolCtx({ toolCallId: `rv-${randomBytes(8).toString("hex")}`, reviveClaim: { row: req.row, rev: req.rev, ...(req.peerSeed !== undefined ? { peerSeed: req.peerSeed } : {}) } }));
|
|
2230
|
-
const o = (typeof out === "string" ? { content: out } : out);
|
|
2231
|
-
return {
|
|
2232
|
-
content: typeof o.content === "string" ? o.content : JSON.stringify(o.content),
|
|
2233
|
-
...(o.isError === true ? { isError: true } : {}),
|
|
2234
|
-
...(o.details !== undefined ? { details: o.details } : {}),
|
|
2235
|
-
};
|
|
2236
|
-
}
|
|
2237
|
-
: undefined;
|
|
2336
|
+
const reviveSpawn = deps.backgroundAgentStore !== undefined && deps.mailboxStore !== undefined ? buildTier3ReviveSpawn(delegationForRevive, enrichSpecToolCtx) : undefined;
|
|
2238
2337
|
tools.push(firstPartyOffload(createSendMessageTool({
|
|
2239
2338
|
runner: runnerSelf,
|
|
2240
2339
|
registry: defaultTaskRegistry,
|
|
@@ -2260,6 +2359,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2260
2359
|
...(deps.backgroundAgentStore !== undefined ? { agentStore: deps.backgroundAgentStore } : {}),
|
|
2261
2360
|
...(deps.mailboxStore !== undefined ? { mailbox: deps.mailboxStore } : {}),
|
|
2262
2361
|
...(reviveSpawn !== undefined ? { reviveSpawn } : {}),
|
|
2362
|
+
...(peerLaneActive ? peerLaneSendMessageSeats({ peerDirectory: deps.peerDirectory, sessionId, scope: taskScope, ...(internals?.explicitAgentName !== undefined ? { name: internals.explicitAgentName } : {}), refs: peerLaneRefs, listingMounted: listAgentsMountable({ exclude: toolFaceSnapshot.exclude, specTools: spec.tools ?? [] }) }) : {}),
|
|
2263
2363
|
onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: hostTaskId, site: f.site, message: f.error.message, ts: Date.now() })),
|
|
2264
2364
|
onTranscriptIntegrityGap: (handle, scope) => deliverEngineNotice(deps.onNotice, {
|
|
2265
2365
|
code: "delegation.transcript_integrity",
|
|
@@ -2285,6 +2385,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2285
2385
|
}
|
|
2286
2386
|
}
|
|
2287
2387
|
}
|
|
2388
|
+
const listAgents = peerLaneActive && peerSendMessageBuiltIn && listAgentsMountable({ exclude: toolFaceSnapshot.exclude, specTools: spec.tools ?? [] }) ? mountListAgents({ peerDirectory: deps.peerDirectory, sessionId, scope: taskScope, hostTaskId, ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}), ...(internals?.parentSessionId !== undefined ? { parentSessionId: internals.parentSessionId } : {}), registry: defaultTaskRegistry, ...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}), specTools: spec.tools ?? [], toolEffects }) : undefined;
|
|
2389
|
+
if (listAgents !== undefined)
|
|
2390
|
+
tools.push(firstPartyOffload(listAgents));
|
|
2288
2391
|
if (backgroundTaskToolsActive) {
|
|
2289
2392
|
toolEffects.set("Monitor", "write");
|
|
2290
2393
|
envHandToolNames.add("Monitor");
|
|
@@ -2331,10 +2434,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2331
2434
|
const liveQuestionFace = isLiveQuestionFace(onQuestion) ? onQuestion : undefined;
|
|
2332
2435
|
const contentAskBindings = new Map();
|
|
2333
2436
|
const CONTENT_ASK_BINDING_CAP = 32;
|
|
2437
|
+
const checkpointStore = resolveCheckpointStore(spec, deps);
|
|
2438
|
+
const questionParkStoreWired = checkpointStore !== undefined;
|
|
2439
|
+
const questionDurableMandateBinding = runtimeCaps?.forceDurableGate === true && questionParkStoreWired;
|
|
2334
2440
|
const contentAskRoutable = (toolCallId) => liveQuestionFace !== undefined &&
|
|
2335
2441
|
mountedQuestionTool !== undefined &&
|
|
2336
2442
|
tools.includes(mountedQuestionTool) &&
|
|
2337
|
-
|
|
2443
|
+
!questionDurableMandateBinding &&
|
|
2338
2444
|
!inheritedUnavailableAsks.has(toolCallId);
|
|
2339
2445
|
const lateStrandedAnswers = [];
|
|
2340
2446
|
const discloseStrandedAnswers = (records, why) => {
|
|
@@ -2361,8 +2467,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2361
2467
|
byDelivery.set(r.deliveryId, r);
|
|
2362
2468
|
return [...byDelivery.values()];
|
|
2363
2469
|
};
|
|
2364
|
-
const durableQuestionFace =
|
|
2365
|
-
(spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true);
|
|
2470
|
+
const durableQuestionFace = questionParkStoreWired && (spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true);
|
|
2366
2471
|
const mountedQuestionFace = liveQuestionFace !== undefined
|
|
2367
2472
|
? async (req, signal) => {
|
|
2368
2473
|
const bound = contentAskBindings.get(req.toolCallId);
|
|
@@ -3522,6 +3627,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3522
3627
|
};
|
|
3523
3628
|
const harness = new AgentHarness({
|
|
3524
3629
|
abortResultDetails: () => parkContaminationMarker({ suspendRef, reviewRef }),
|
|
3630
|
+
onToolInputValidationFault: validateInputFaultNotice(deps.onError, sessionId),
|
|
3525
3631
|
...(spec.limits?.maxOutputTokens !== undefined && spec.limits.maxOutputTokens > 0
|
|
3526
3632
|
? { maxOutputTokens: spec.limits.maxOutputTokens }
|
|
3527
3633
|
: {}),
|
|
@@ -4272,7 +4378,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4272
4378
|
}
|
|
4273
4379
|
const usageGovernance = buildUsageGovernance(usageWindows, deps, spec.principal, sessionId);
|
|
4274
4380
|
const platformSuspendArmed = durableSuspendInfraReady && (envLifetimeSuspendAt !== undefined || usageGovernance !== undefined);
|
|
4275
|
-
const checkpointStore = resolveCheckpointStore(spec, deps);
|
|
4276
4381
|
const durableApproval = spec.durableApproval ??
|
|
4277
4382
|
(runtimeCaps?.forceDurableGate ? { scope: spec.principal || DEFAULT_IRREVERSIBLE_SCOPE } : undefined);
|
|
4278
4383
|
const wiringQuestionSeam = resolveQuestionSeam(spec, deps);
|
|
@@ -4308,8 +4413,15 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4308
4413
|
complianceWired: deps.compliancePostureResolver !== undefined,
|
|
4309
4414
|
memoryAdmissionWired: deps.memoryScopeAdmission !== undefined,
|
|
4310
4415
|
retentionPolicyWired: deps.retentionPolicy !== undefined,
|
|
4416
|
+
...(modelGateManifest !== undefined ? { modelGate: modelGateManifest } : {}),
|
|
4417
|
+
autoMode: { armed: autoModeArmReason === "armed", reason: autoModeArmReason },
|
|
4311
4418
|
});
|
|
4419
|
+
peerLaneRefs.askEffective = wiringManifest.ask.effective;
|
|
4420
|
+
if (peerLaneActive && internals?.onTaskNotification !== undefined) {
|
|
4421
|
+
bindPeerLaneDrain(harness, { deps, sessionId, runId, scope: taskScope, inject: internals.onTaskNotification, ownTokens: () => internals?.peerSelfRef?.current.ownTokens ?? [], refs: peerLaneRefs });
|
|
4422
|
+
}
|
|
4312
4423
|
const parkLaneArmed = wiringManifest.parkLane.effective === true;
|
|
4424
|
+
announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreNull: spec.checkpointStore === null, liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
4313
4425
|
const hookIdentity = mintHookInvocationIdentity({
|
|
4314
4426
|
sessionId,
|
|
4315
4427
|
taskId: hostTaskId,
|
|
@@ -4449,8 +4561,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4449
4561
|
const constraintDigest = (inheritedParentConstraints?.length ?? 0) > 0
|
|
4450
4562
|
? constraintChainDigest(constraintChain)
|
|
4451
4563
|
: seedInheritedGate?.constraintDigest;
|
|
4564
|
+
const autoModeIntentCarried = autoModeIntent && (autoModeDecider === undefined || autoModeLatchHealthy(autoModeDecider));
|
|
4452
4565
|
return inheritedAncestorRules !== undefined ||
|
|
4453
4566
|
inheritedShellGate !== undefined ||
|
|
4567
|
+
autoModeIntentCarried ||
|
|
4454
4568
|
inheritedAdmittedOrgScopes !== undefined ||
|
|
4455
4569
|
ownOrgVerdictRef.current !== undefined ||
|
|
4456
4570
|
orgGovernedProvenance ||
|
|
@@ -4458,6 +4572,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4458
4572
|
? {
|
|
4459
4573
|
...(inheritedAncestorRules !== undefined ? { ancestorRules: structuredClone(inheritedAncestorRules) } : {}),
|
|
4460
4574
|
...(inheritedShellGate !== undefined ? { shellGate: inheritedShellGate } : {}),
|
|
4575
|
+
...(autoModeIntentCarried ? { autoModeRequested: true } : {}),
|
|
4461
4576
|
...(inheritedAdmittedOrgScopes !== undefined ? { admittedOrgScopes: [...inheritedAdmittedOrgScopes] } : {}),
|
|
4462
4577
|
...(ownOrgVerdictRef.current !== undefined
|
|
4463
4578
|
? { ownAdmittedOrgScopes: [...ownOrgVerdictRef.current.scopes], ownAdmittedOrgWriteScope: ownOrgVerdictRef.current.writeScope }
|
|
@@ -21,6 +21,7 @@ import { ORG_ADJUDICATION_TIMEOUT_MS, settleOrgVerdictWithin } from "../permissi
|
|
|
21
21
|
import { emitTaskOutcome } from "../task-outcome.js";
|
|
22
22
|
import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
|
|
23
23
|
import { primaryActivityArg } from "../arg-summary.js";
|
|
24
|
+
import { redactThenCut } from "../../agents/subagent-steps.js";
|
|
24
25
|
import { resolveReasoning } from "../../brain/reasoning.js";
|
|
25
26
|
import { adjudicateDerivedRoute, authCarrierFingerprint, fallbackToPrimaryNotice, normalizeBaseUrl, sameRouteIdentity } from "../../brain/route-adjudicator.js";
|
|
26
27
|
import { readDegradation } from "../../brain/degrading.js";
|
|
@@ -773,7 +774,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
773
774
|
boundaryAttachmentBytes += Buffer.byteLength(a.body, "utf8");
|
|
774
775
|
rs.attach.attachmentsInjected += due.length;
|
|
775
776
|
for (const a of due) {
|
|
776
|
-
queue.push({ type: "steering_injected", source: a.source, preview: a.body
|
|
777
|
+
queue.push({ type: "steering_injected", source: a.source, preview: redactThenCut(a.body, 220), ...ident() });
|
|
777
778
|
}
|
|
778
779
|
}
|
|
779
780
|
}
|
|
@@ -2871,6 +2872,8 @@ export class Runner {
|
|
|
2871
2872
|
...(s.retryInSec !== undefined ? { retryInSec: s.retryInSec } : {}),
|
|
2872
2873
|
...(s.retryInMs !== undefined ? { retryInMs: s.retryInMs } : {}),
|
|
2873
2874
|
...(s.retryAtMs !== undefined ? { retryAtMs: s.retryAtMs } : {}),
|
|
2875
|
+
...(s.elapsedMs !== undefined ? { elapsedMs: s.elapsedMs } : {}),
|
|
2876
|
+
...(s.timeoutMs !== undefined ? { timeoutMs: s.timeoutMs } : {}),
|
|
2874
2877
|
...(s.attempt !== undefined ? { attempt: s.attempt } : {}),
|
|
2875
2878
|
...(s.maxRetries !== undefined ? { maxRetries: s.maxRetries } : {}),
|
|
2876
2879
|
...(s.errClass !== undefined ? { errClass: s.errClass } : {}),
|
|
@@ -3821,7 +3824,7 @@ export class Runner {
|
|
|
3821
3824
|
}
|
|
3822
3825
|
for (const f of firstFrames) {
|
|
3823
3826
|
f.commit();
|
|
3824
|
-
queue.push({ type: "steering_injected", source: f.source, preview: f.body
|
|
3827
|
+
queue.push({ type: "steering_injected", source: f.source, preview: redactThenCut(f.body, 220), ...ident() });
|
|
3825
3828
|
}
|
|
3826
3829
|
rs.attach.attachmentsInjected += firstFrames.length;
|
|
3827
3830
|
if (firstFrames.length > 0)
|
|
@@ -64,6 +64,7 @@ const CC_DETAIL_TYPES = new Set([
|
|
|
64
64
|
"task-stop", "tool-search", "repo-map", "fork", "enter-plan-mode", "exit-plan-mode",
|
|
65
65
|
"monitor-start", "path_not_in_root", "read_path_denied", "readonly_out_of_root", "bash_invalid_timeout",
|
|
66
66
|
"report-findings", "schedule-wakeup", "send-message", "agent-transcript", "a2a", "document",
|
|
67
|
+
"list-agents",
|
|
67
68
|
]);
|
|
68
69
|
export const structuredFrom = (result) => {
|
|
69
70
|
const details = result !== null && typeof result === "object" ? result.details : undefined;
|
|
@@ -46,6 +46,29 @@ export declare function mailboxAckOwnershipContract(mk: () => MailboxStore, runA
|
|
|
46
46
|
* 放宽」:核心层没有一条为了任何后端而弱化。第三方后端若有租户轴,应当也挂这一层。
|
|
47
47
|
*/
|
|
48
48
|
export declare function mailboxBundledOnlyContract(mk: () => MailboxStore, runAssertion?: ContractAssertionRunner): Promise<void>;
|
|
49
|
+
export interface MailboxCrossProcessContractHooks {
|
|
50
|
+
/** Open ONE fresh, empty storage location TWICE: `local` in this process and `peer` served by ANOTHER
|
|
51
|
+
* OS process over the same storage (the peer is a real second process — an in-process second
|
|
52
|
+
* instance proves nothing here). `dispose` closes both and may remove the storage. The kit calls it
|
|
53
|
+
* once per case. */
|
|
54
|
+
openPair: () => Promise<{
|
|
55
|
+
local: MailboxStore;
|
|
56
|
+
peer: MailboxStore;
|
|
57
|
+
dispose: () => Promise<void>;
|
|
58
|
+
}>;
|
|
59
|
+
runAssertion?: ContractAssertionRunner;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* T2 可选能力层(cross-process 分册,design/385 §1.2⑥ / G11)—— 声明 `crossProcessSafe: true` 的后端必须
|
|
63
|
+
* 过的全套判据。钉的是**整套**(跨进程 seq 单铸 + lease/ack 不交叉 + 一方的 housekeeping 不丢另一方的
|
|
64
|
+
* 已落盘 append + reap/drop 的 seq 语义跨进程成立),不是「有锁」:一把锁配一份陈旧缓存照样在锁内铸
|
|
65
|
+
* 重号、照样把别人的消息压缩掉——所以每一条都从**对方进程的视角**回读。
|
|
66
|
+
*
|
|
67
|
+
* 受众:文件后端(本仓捆绑)、SQL 后端(事务天然过)。进程内 Map 的参照实现与 CC inbox 适配器不声明,
|
|
68
|
+
* 也不挂——它们不是「没做到所以放宽」,而是根本不在跨进程车道上(挂载判据 `mailboxCrossProcessMountVerdict`
|
|
69
|
+
* 对未声明的后端响亮拒)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function mailboxCrossProcessContract(hooks: MailboxCrossProcessContractHooks): Promise<void>;
|
|
49
72
|
export interface MailboxTombstonedRecipientContractHooks {
|
|
50
73
|
/** Put `(scope, handle)` into the deployment's PRE-DELETE state — whatever that is for this
|
|
51
74
|
* backend (a cascade marking the session row, a `deleting` column, a tombstone table). Core does
|