@bastani/atomic 0.9.19-alpha.2 → 0.9.19-alpha.4
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 +42 -0
- package/dist/builtin/intercom/CHANGELOG.md +15 -0
- package/dist/builtin/intercom/broker/broker.ts +8 -0
- package/dist/builtin/intercom/broker/client.ts +18 -0
- package/dist/builtin/intercom/broker/send-handler.ts +9 -0
- package/dist/builtin/intercom/index.bundle.mjs +161 -30
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/types.ts +2 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +18 -0
- package/dist/builtin/subagents/README.md +14 -14
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +14 -14
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +142 -60
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +33 -0
- package/dist/builtin/workflows/README.md +14 -15
- package/dist/builtin/workflows/builtin/{chunk-mygmtz6e.js → chunk-9k3ywfgd.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-r9qq7xfj.js → chunk-ahbntmx2.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-zggjyg5z.js → chunk-n8zysf1t.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +5 -5
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +171 -207
- package/dist/builtin/workflows/src/index.js +33 -6
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +1 -1
- package/dist/core/agent-session-auto-compaction.js +1 -1
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.js +1 -1
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +33 -2
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +1 -1
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +22 -8
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +7 -1
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +13 -3
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.js +1 -1
- package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +83 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-queue-pause.d.ts.map +1 -1
- package/dist/core/agent-session-queue-pause.js +11 -0
- package/dist/core/agent-session-queue-pause.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts +5 -0
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +8 -1
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
- package/dist/core/agent-session-tool-hooks.js +2 -0
- package/dist/core/agent-session-tool-hooks.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +12 -0
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-transfer.d.ts.map +1 -1
- package/dist/core/agent-session-transfer.js +7 -0
- package/dist/core/agent-session-transfer.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +2 -0
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js +2 -0
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +22 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +6 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +3 -0
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/loader-host-modules.d.ts +1 -1
- package/dist/core/extensions/loader-host-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-host-modules.js +2 -1
- package/dist/core/extensions/loader-host-modules.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +4 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +9 -3
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner.js +1 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/workflow-events.d.ts +1 -1
- package/dist/core/extensions/workflow-events.d.ts.map +1 -1
- package/dist/core/extensions/workflow-events.js.map +1 -1
- package/dist/core/retry-policy.d.ts +1 -0
- package/dist/core/retry-policy.d.ts.map +1 -1
- package/dist/core/retry-policy.js +2 -1
- package/dist/core/retry-policy.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-exports.js +1 -1
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +6 -3
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +25 -8
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +6 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tasks/agent-adapter.d.ts +14 -2
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -1
- package/dist/core/tasks/agent-adapter.js +45 -4
- package/dist/core/tasks/agent-adapter.js.map +1 -1
- package/dist/core/tasks/completion.d.ts.map +1 -1
- package/dist/core/tasks/completion.js +5 -1
- package/dist/core/tasks/completion.js.map +1 -1
- package/dist/core/tasks/pause.d.ts +4 -0
- package/dist/core/tasks/pause.d.ts.map +1 -0
- package/dist/core/tasks/pause.js +49 -0
- package/dist/core/tasks/pause.js.map +1 -0
- package/dist/core/tasks/supervisor.d.ts +3 -1
- package/dist/core/tasks/supervisor.d.ts.map +1 -1
- package/dist/core/tasks/supervisor.js +48 -22
- package/dist/core/tasks/supervisor.js.map +1 -1
- package/dist/core/tools/bash-pty-native.d.ts +16 -2
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.js +82 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -1
- package/dist/core/tools/bash.d.ts +15 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +49 -4
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +12 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/kill.d.ts +17 -0
- package/dist/core/tools/kill.d.ts.map +1 -0
- package/dist/core/tools/kill.js +49 -0
- package/dist/core/tools/kill.js.map +1 -0
- package/dist/core/tools/powershell.d.ts +84 -28
- package/dist/core/tools/powershell.d.ts.map +1 -1
- package/dist/core/tools/powershell.js +11 -3
- package/dist/core/tools/powershell.js.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts +1 -1
- package/dist/core/tools/resource-selectors.d.ts.map +1 -1
- package/dist/core/tools/resource-selectors.js +7 -4
- package/dist/core/tools/resource-selectors.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +14 -0
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +63 -3
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +3 -2
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-row.js +8 -1
- package/dist/modes/interactive/components/task-row.js.map +1 -1
- package/docs/background-tasks.md +31 -2
- package/docs/compaction.md +20 -0
- package/docs/computer-use.md +390 -0
- package/docs/development.md +23 -74
- package/docs/docs.json +1 -0
- package/docs/extensions.md +15 -1
- package/docs/herdr.md +26 -77
- package/docs/index.md +1 -0
- package/docs/intercom.md +14 -2
- package/docs/models/evals.md +2 -0
- package/docs/models/model-selection.md +10 -7
- package/docs/quickstart.md +1 -1
- package/docs/sdk.md +11 -1
- package/docs/settings.md +24 -0
- package/docs/subagents.md +10 -6
- package/docs/tmux.md +2 -0
- package/docs/tools.md +11 -1
- package/docs/usage.md +1 -1
- package/docs/workflows/api-reference.md +5 -4
- package/docs/workflows/authoring.md +3 -3
- package/docs/workflows/operations.md +44 -33
- package/docs/workflows/reliable-design.md +3 -3
- package/docs/workflows/verification.md +99 -40
- package/docs/workflows.md +4 -2
- package/npm-shrinkwrap.json +59 -59
- package/package.json +3 -3
|
@@ -523,6 +523,7 @@ var init_client = __esm(() => {
|
|
|
523
523
|
_supervisorSessionId = null;
|
|
524
524
|
_messageSource;
|
|
525
525
|
pendingSends = new PendingSendRegistry;
|
|
526
|
+
pendingReplyTargets = new Map;
|
|
526
527
|
pendingGroupLists = new Map;
|
|
527
528
|
pendingLists = new Map;
|
|
528
529
|
pendingPresence = new Map;
|
|
@@ -730,6 +731,16 @@ var init_client = __esm(() => {
|
|
|
730
731
|
this.emit("_registration_failed", new Error(brokerMessage.reason));
|
|
731
732
|
break;
|
|
732
733
|
}
|
|
734
|
+
case "question_target": {
|
|
735
|
+
const { messageId, attemptId, sessionId } = brokerMessage;
|
|
736
|
+
if (typeof messageId !== "string" || typeof attemptId !== "string" || typeof sessionId !== "string") {
|
|
737
|
+
throw new Error("Invalid question_target message");
|
|
738
|
+
}
|
|
739
|
+
const pending = this.pendingReplyTargets.get(attemptId);
|
|
740
|
+
if (pending?.messageId === messageId)
|
|
741
|
+
pending.bind(sessionId);
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
733
744
|
case "sessions": {
|
|
734
745
|
const { requestId, sessions, workflowStages, workflowFutureStages } = brokerMessage;
|
|
735
746
|
if (typeof requestId !== "string" || !Array.isArray(sessions) || !sessions.every(isSessionInfo) || workflowStages !== undefined && !isWorkflowStageRosterEntries(workflowStages) || workflowFutureStages !== undefined && !isWorkflowFutureStageRosterEntries(workflowFutureStages)) {
|
|
@@ -1246,12 +1257,16 @@ var init_client = __esm(() => {
|
|
|
1246
1257
|
source: this._messageSource,
|
|
1247
1258
|
content: { text: options.text, attachments: options.attachments }
|
|
1248
1259
|
};
|
|
1260
|
+
if (options.onReplyTarget !== undefined) {
|
|
1261
|
+
this.pendingReplyTargets.set(acquired.attempt.attemptId, { messageId, bind: options.onReplyTarget });
|
|
1262
|
+
}
|
|
1249
1263
|
try {
|
|
1250
1264
|
writeMessage(socket, {
|
|
1251
1265
|
type,
|
|
1252
1266
|
to,
|
|
1253
1267
|
...options.logicalTarget === undefined ? {} : { logicalTarget: options.logicalTarget },
|
|
1254
1268
|
...options.requirePendingReply === undefined ? {} : { requirePendingReply: options.requirePendingReply },
|
|
1269
|
+
...options.onReplyTarget === undefined ? {} : { resolveReplyTarget: true },
|
|
1255
1270
|
message,
|
|
1256
1271
|
attemptId: acquired.attempt.attemptId,
|
|
1257
1272
|
...extra
|
|
@@ -1259,6 +1274,10 @@ var init_client = __esm(() => {
|
|
|
1259
1274
|
} catch (error) {
|
|
1260
1275
|
this.pendingSends.reject(acquired.attempt, toError(error));
|
|
1261
1276
|
}
|
|
1277
|
+
const clearReplyTarget = () => {
|
|
1278
|
+
this.pendingReplyTargets.delete(acquired.attempt.attemptId);
|
|
1279
|
+
};
|
|
1280
|
+
acquired.attempt.promise.then(clearReplyTarget, clearReplyTarget);
|
|
1262
1281
|
return acquired.attempt.promise;
|
|
1263
1282
|
}
|
|
1264
1283
|
updatePresence(updates) {
|
|
@@ -1799,6 +1818,10 @@ class ReplyWaiterRegistry {
|
|
|
1799
1818
|
ok: true,
|
|
1800
1819
|
wait: {
|
|
1801
1820
|
promise,
|
|
1821
|
+
bindSender: (sender) => {
|
|
1822
|
+
if (this.waiters.get(replyTo) === record)
|
|
1823
|
+
record.from = sender;
|
|
1824
|
+
},
|
|
1802
1825
|
cancel: (error) => record.reject(error)
|
|
1803
1826
|
}
|
|
1804
1827
|
};
|
|
@@ -1966,6 +1989,11 @@ class ReplyTracker {
|
|
|
1966
1989
|
endTurn() {
|
|
1967
1990
|
this.currentTurnContext = null;
|
|
1968
1991
|
}
|
|
1992
|
+
restoreTurnContext() {
|
|
1993
|
+
if (this.currentTurnContext)
|
|
1994
|
+
this.pendingTurnContexts.unshift(this.currentTurnContext);
|
|
1995
|
+
this.currentTurnContext = null;
|
|
1996
|
+
}
|
|
1969
1997
|
reset() {
|
|
1970
1998
|
this.pendingAsks.clear();
|
|
1971
1999
|
this.pendingTurnContexts.length = 0;
|
|
@@ -2414,7 +2442,8 @@ function formatSessionListRow(session, currentCwd, isSelf) {
|
|
|
2414
2442
|
const name = session.name || "Unnamed session";
|
|
2415
2443
|
const normalizedGroup = normalizeGroup(session.group);
|
|
2416
2444
|
const groupTag = normalizedGroup !== DEFAULT_GROUP ? `group: ${normalizedGroup}` : undefined;
|
|
2417
|
-
const
|
|
2445
|
+
const capabilityTag = session.replyCapability === undefined ? undefined : `replyCapability: ${session.replyCapability}`;
|
|
2446
|
+
const tags = [isSelf ? "self" : session.cwd === currentCwd ? "same cwd" : undefined, session.status, capabilityTag, groupTag].filter((tag) => Boolean(tag));
|
|
2418
2447
|
const suffix = tags.length ? ` [${tags.join(", ")}]` : "";
|
|
2419
2448
|
return `• ${name} (${session.id}) — ${session.cwd} (${session.model})${suffix}`;
|
|
2420
2449
|
}
|
|
@@ -3755,7 +3784,8 @@ ${message}${attachmentText}`);
|
|
|
3755
3784
|
text: message ?? "",
|
|
3756
3785
|
attachments,
|
|
3757
3786
|
replyTo,
|
|
3758
|
-
expectsReply: true
|
|
3787
|
+
expectsReply: true,
|
|
3788
|
+
...parseWorkflowStageTarget(to)?.kind === "path" ? { onReplyTarget: wait.bindSender } : {}
|
|
3759
3789
|
});
|
|
3760
3790
|
if (sendResult.queued === true) {
|
|
3761
3791
|
retryIdentities.release(retryIdentity);
|
|
@@ -4487,7 +4517,10 @@ var init_overlay = __esm(() => {
|
|
|
4487
4517
|
function registerIntercomLifecycle(pi, deps) {
|
|
4488
4518
|
const activeReplyTracker = () => typeof deps.replyTracker === "function" ? deps.replyTracker() : deps.replyTracker;
|
|
4489
4519
|
let hasActiveSession = false;
|
|
4520
|
+
let unbindStageClose;
|
|
4490
4521
|
async function cleanupRuntime(reason) {
|
|
4522
|
+
unbindStageClose?.();
|
|
4523
|
+
unbindStageClose = undefined;
|
|
4491
4524
|
deps.setRuntimeStarted(false);
|
|
4492
4525
|
deps.setShuttingDown(true);
|
|
4493
4526
|
deps.setDisposed(true);
|
|
@@ -4538,6 +4571,12 @@ function registerIntercomLifecycle(pi, deps) {
|
|
|
4538
4571
|
deps.setSessionStartedAt(Date.now());
|
|
4539
4572
|
deps.setAgentRunning(false);
|
|
4540
4573
|
deps.activeTools.clear();
|
|
4574
|
+
const stage = ctx.orchestrationContext;
|
|
4575
|
+
const closeSignal = stage?.kind === "workflow-stage" ? stage.messageAdmission?.boundary?.closeSignal : undefined;
|
|
4576
|
+
closeSignal?.addEventListener("abort", deps.syncPresenceStatus, { once: true });
|
|
4577
|
+
unbindStageClose = () => closeSignal?.removeEventListener("abort", deps.syncPresenceStatus);
|
|
4578
|
+
if (closeSignal?.aborted)
|
|
4579
|
+
deps.syncPresenceStatus();
|
|
4541
4580
|
});
|
|
4542
4581
|
pi.on("session_shutdown", async () => {
|
|
4543
4582
|
if (!hasActiveSession)
|
|
@@ -4545,10 +4584,15 @@ function registerIntercomLifecycle(pi, deps) {
|
|
|
4545
4584
|
hasActiveSession = false;
|
|
4546
4585
|
await cleanupRuntime("Session shutting down");
|
|
4547
4586
|
});
|
|
4548
|
-
pi.on("turn_end", () => {
|
|
4587
|
+
pi.on("turn_end", (event) => {
|
|
4549
4588
|
if (!deps.getLiveContext())
|
|
4550
4589
|
return;
|
|
4551
|
-
|
|
4590
|
+
const message = event.message;
|
|
4591
|
+
const cancelledBeforeReply = message?.role === "assistant" && message.stopReason === "aborted" && message.content?.length === 0;
|
|
4592
|
+
if (cancelledBeforeReply)
|
|
4593
|
+
activeReplyTracker().restoreTurnContext();
|
|
4594
|
+
else
|
|
4595
|
+
activeReplyTracker().endTurn();
|
|
4552
4596
|
deps.scheduleInboundFlush();
|
|
4553
4597
|
});
|
|
4554
4598
|
pi.on("agent_start", () => {
|
|
@@ -5640,7 +5684,7 @@ function createIncomingMessageSender(input) {
|
|
|
5640
5684
|
if (!input.canDeliver(generation)) {
|
|
5641
5685
|
return Promise.reject(new Error("Intercom session retired before inbound delivery"));
|
|
5642
5686
|
}
|
|
5643
|
-
if (delivery === "trigger" && trackReplyContext) {
|
|
5687
|
+
if ((delivery === "trigger" || delivery === "interrupt") && trackReplyContext) {
|
|
5644
5688
|
input.queueTurnContext(turnContext ?? { from: entry.from, message: entry.message, receivedAt: Date.now() });
|
|
5645
5689
|
}
|
|
5646
5690
|
const baseOptions = {
|
|
@@ -5648,7 +5692,7 @@ function createIncomingMessageSender(input) {
|
|
|
5648
5692
|
persistWhenStreaming: true,
|
|
5649
5693
|
...stageAdmissionBarrier ? { stageAdmissionBarrier } : {}
|
|
5650
5694
|
};
|
|
5651
|
-
const options = delivery === "trigger" ? { ...baseOptions, triggerTurn: true } : delivery === "followUp" ? { ...baseOptions, deliverAs: "followUp" } : baseOptions;
|
|
5695
|
+
const options = delivery === "interrupt" ? { ...baseOptions, triggerTurn: true, deliverAs: "interrupt" } : delivery === "trigger" ? { ...baseOptions, triggerTurn: true } : delivery === "followUp" ? { ...baseOptions, deliverAs: "followUp" } : baseOptions;
|
|
5652
5696
|
return Promise.resolve(input.pi.sendMessage(buildIncomingCustomMessage(entry), options));
|
|
5653
5697
|
};
|
|
5654
5698
|
}
|
|
@@ -6000,13 +6044,15 @@ function retryStableDelivery(options) {
|
|
|
6000
6044
|
function admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailure) {
|
|
6001
6045
|
if (ctx.orchestrationContext?.kind !== "workflow-stage")
|
|
6002
6046
|
return false;
|
|
6047
|
+
const boundary = ctx.orchestrationContext.messageAdmission?.boundary;
|
|
6048
|
+
const run = (barrier) => boundary?.runMessageDelivery(() => deliver(barrier), () => deliver(), true) ?? Promise.resolve(deliver(barrier));
|
|
6003
6049
|
try {
|
|
6004
6050
|
let busy = false;
|
|
6005
6051
|
try {
|
|
6006
6052
|
busy = ctx.isIdle?.() === false;
|
|
6007
6053
|
} catch {}
|
|
6008
6054
|
if (!busy || !firstRefusal)
|
|
6009
|
-
return
|
|
6055
|
+
return run();
|
|
6010
6056
|
let firstRefusalPromise;
|
|
6011
6057
|
const admissionBarrier = () => {
|
|
6012
6058
|
firstRefusalPromise ??= (async () => {
|
|
@@ -6019,12 +6065,29 @@ function admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailur
|
|
|
6019
6065
|
})();
|
|
6020
6066
|
return firstRefusalPromise;
|
|
6021
6067
|
};
|
|
6022
|
-
return
|
|
6068
|
+
return run(admissionBarrier);
|
|
6023
6069
|
} catch (error) {
|
|
6024
6070
|
return Promise.reject(error);
|
|
6025
6071
|
}
|
|
6026
6072
|
}
|
|
6027
6073
|
|
|
6074
|
+
// dist/builtin/intercom/active-session-admission.ts
|
|
6075
|
+
function admitActiveSessionInbound(ctx, deliver, firstRefusal, onAdmissionFailure) {
|
|
6076
|
+
const executionEnded = ctx.subagentPolicy?.executionEnded;
|
|
6077
|
+
if (executionEnded !== undefined) {
|
|
6078
|
+
if (executionEnded.aborted || ctx.subagentPolicy?.messageAdmission?.isOpen() === false) {
|
|
6079
|
+
return Promise.reject(new Error("Subagent execution is terminal and cannot accept messages"));
|
|
6080
|
+
}
|
|
6081
|
+
try {
|
|
6082
|
+
return ctx.subagentPolicy?.messageAdmission?.run(deliver) ?? Promise.resolve(deliver());
|
|
6083
|
+
} catch (error) {
|
|
6084
|
+
return Promise.reject(error);
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
return admitWorkflowStageInbound(ctx, deliver, firstRefusal, onAdmissionFailure);
|
|
6088
|
+
}
|
|
6089
|
+
var init_active_session_admission = () => {};
|
|
6090
|
+
|
|
6028
6091
|
// dist/builtin/intercom/workflow-reply-tracker.ts
|
|
6029
6092
|
function bindWorkflowReplyTracker(ctx, current) {
|
|
6030
6093
|
const state = ctx.orchestrationContext?.messageAdmission?.extensionState;
|
|
@@ -6078,7 +6141,7 @@ async function settleOpenStageDeliveryFailure(input, error) {
|
|
|
6078
6141
|
input.admission.release(input.reservation, failure);
|
|
6079
6142
|
return;
|
|
6080
6143
|
}
|
|
6081
|
-
const delivered = await sendWorkflowStageDeliveryFailure(input.entry, failure, input.tracker, input.currentClient, () => input.currentClient()?.isConnected() === true, "Running workflow stage could not admit intercom ask");
|
|
6144
|
+
const delivered = await sendWorkflowStageDeliveryFailure(input.entry, failure, input.tracker, input.currentClient, () => input.currentClient()?.isConnected() === true, input.failurePrefix ?? "Running workflow stage could not admit intercom ask");
|
|
6082
6145
|
if (delivered)
|
|
6083
6146
|
input.commit();
|
|
6084
6147
|
else
|
|
@@ -6263,7 +6326,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6263
6326
|
}
|
|
6264
6327
|
function currentStatus() {
|
|
6265
6328
|
const activeToolName = activeTools.values().next().value;
|
|
6266
|
-
const
|
|
6329
|
+
const stage = getLiveContext()?.orchestrationContext;
|
|
6330
|
+
const lifecycleStatus = stage?.kind === "workflow-stage" && stage.messageAdmission?.isOpen() === false ? `closed · reply: ${stage.lateMessageRouter === undefined ? "unavailable" : "post-mortem only"}` : activeToolName ? `tool:${activeToolName}` : agentRunning ? "thinking" : "idle";
|
|
6267
6331
|
return config.status ? `${lifecycleStatus} · ${config.status}` : lifecycleStatus;
|
|
6268
6332
|
}
|
|
6269
6333
|
function resolveSessionHomeGroup() {
|
|
@@ -6411,7 +6475,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6411
6475
|
const stageAdmission = liveContext.orchestrationContext?.kind === "workflow-stage" ? liveContext.orchestrationContext.messageAdmission : undefined;
|
|
6412
6476
|
const stageClosed = stageAdmission?.isOpen() === false;
|
|
6413
6477
|
if (stageClosed) {
|
|
6414
|
-
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () =>
|
|
6478
|
+
routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => {
|
|
6479
|
+
if (message.expectsReply === true && liveContext.orchestrationContext?.lateMessageRouter === undefined) {
|
|
6480
|
+
throw new Error("Workflow stage is closed and cannot reply because post-mortem routing is unavailable. Contact a live stage or start new work with explicit context.");
|
|
6481
|
+
}
|
|
6482
|
+
return sendIncomingMessage(entry, isDeliveryFeedback(message) ? "prelude" : "trigger", messageGeneration, false);
|
|
6483
|
+
}, () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)), (runId) => stageAdmission.boundary.ownsSubagentRun(runId));
|
|
6415
6484
|
return;
|
|
6416
6485
|
}
|
|
6417
6486
|
const admission = inboundDeliveries.admit(from, message);
|
|
@@ -6439,17 +6508,18 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6439
6508
|
tracker: replyTracker,
|
|
6440
6509
|
replyContext,
|
|
6441
6510
|
currentClient: () => client,
|
|
6442
|
-
commit
|
|
6511
|
+
commit,
|
|
6512
|
+
failurePrefix: liveContext.subagentPolicy?.executionEnded === undefined ? undefined : "Subagent could not admit intercom ask"
|
|
6443
6513
|
});
|
|
6444
|
-
const
|
|
6514
|
+
const activeDelivery = admitActiveSessionInbound(liveContext, (admissionBarrier) => {
|
|
6445
6515
|
replyTracker.queueTurnContext(replyContext);
|
|
6446
6516
|
return retryStableDelivery({
|
|
6447
|
-
deliver: () => sendIncomingMessage(entry, "
|
|
6448
|
-
isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
|
|
6517
|
+
deliver: () => sendIncomingMessage(entry, "interrupt", messageGeneration, false, undefined, admissionBarrier),
|
|
6518
|
+
isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration)) && liveContext.subagentPolicy?.executionEnded?.aborted !== true && liveContext.subagentPolicy?.messageAdmission?.isOpen() !== false
|
|
6449
6519
|
});
|
|
6450
6520
|
}, () => foregroundDetachHandoff.claim(from, message, messageGeneration, () => Boolean(getLiveContext(liveContext, messageGeneration))), release);
|
|
6451
|
-
if (
|
|
6452
|
-
|
|
6521
|
+
if (activeDelivery !== false) {
|
|
6522
|
+
activeDelivery.then(commit, release);
|
|
6453
6523
|
return;
|
|
6454
6524
|
}
|
|
6455
6525
|
return (async () => {
|
|
@@ -6459,7 +6529,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6459
6529
|
release(new Error("Intercom session retired before inbound delivery"));
|
|
6460
6530
|
return;
|
|
6461
6531
|
}
|
|
6462
|
-
if (!activeContext.isIdle()) {
|
|
6532
|
+
if (!activeContext.isIdle() && !activeContext.getAgentTaskHost?.().hasActiveTaskWaits) {
|
|
6463
6533
|
if (!activeContext.hasUI) {
|
|
6464
6534
|
const activeClient = client;
|
|
6465
6535
|
if (!message.replyTo && activeClient?.isConnected()) {
|
|
@@ -6502,6 +6572,13 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
6502
6572
|
});
|
|
6503
6573
|
return;
|
|
6504
6574
|
}
|
|
6575
|
+
if (!activeContext.isIdle()) {
|
|
6576
|
+
const disposition = await foregroundDetachHandoff.claim(from, message, messageGeneration, () => Boolean(getLiveContext(liveContext, messageGeneration)));
|
|
6577
|
+
if (disposition === "abandoned") {
|
|
6578
|
+
release(new Error("Intercom session retired during foreground-owner admission"));
|
|
6579
|
+
return;
|
|
6580
|
+
}
|
|
6581
|
+
}
|
|
6505
6582
|
replyTracker.queueTurnContext(replyContext);
|
|
6506
6583
|
await retryStableDelivery({ deliver: () => sendIncomingMessage(entry, "trigger", messageGeneration, false), isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration)) });
|
|
6507
6584
|
commit();
|
|
@@ -7078,6 +7155,7 @@ var init_index_heavy = __esm(() => {
|
|
|
7078
7155
|
init_terminal_ordering_barrier();
|
|
7079
7156
|
init_inbound_message_admission();
|
|
7080
7157
|
init_late_stage_message_router();
|
|
7158
|
+
init_active_session_admission();
|
|
7081
7159
|
init_workflow_reply_tracker();
|
|
7082
7160
|
init_closed_workflow_stage_message();
|
|
7083
7161
|
init_group();
|
|
@@ -7095,11 +7173,20 @@ var init_index_heavy = __esm(() => {
|
|
|
7095
7173
|
});
|
|
7096
7174
|
|
|
7097
7175
|
// dist/builtin/intercom/index.ts
|
|
7098
|
-
init_result_renderers();
|
|
7099
7176
|
import { APP_NAME as APP_NAME2, getEnvValue } from "@bastani/atomic";
|
|
7100
7177
|
import { Text as Text4 } from "@earendil-works/pi-tui";
|
|
7101
7178
|
import { Type as Type3 } from "typebox";
|
|
7102
7179
|
|
|
7180
|
+
// dist/builtin/intercom/context-owner.ts
|
|
7181
|
+
var CONTEXT_OWNERS_KEY = Symbol.for("atomic-coding-agent/extension-context-owners@1");
|
|
7182
|
+
function getExtensionContextOwner(context) {
|
|
7183
|
+
const owners = globalThis[CONTEXT_OWNERS_KEY];
|
|
7184
|
+
return owners?.get(context) ?? context;
|
|
7185
|
+
}
|
|
7186
|
+
|
|
7187
|
+
// dist/builtin/intercom/index.ts
|
|
7188
|
+
init_result_renderers();
|
|
7189
|
+
|
|
7103
7190
|
// dist/builtin/intercom/lazy-tool-execution.ts
|
|
7104
7191
|
init_recoverable_disconnect();
|
|
7105
7192
|
init_retry_policy();
|
|
@@ -7361,10 +7448,37 @@ function renderHeavyToolResult(loadedHeavy, name, args) {
|
|
|
7361
7448
|
return renderer(...args);
|
|
7362
7449
|
return renderIntercomToolResult(name, args);
|
|
7363
7450
|
}
|
|
7364
|
-
function
|
|
7451
|
+
function diagnosticDetail(error) {
|
|
7452
|
+
try {
|
|
7453
|
+
return String(error instanceof Error ? error.message : error);
|
|
7454
|
+
} catch {
|
|
7455
|
+
return "Unprintable error";
|
|
7456
|
+
}
|
|
7457
|
+
}
|
|
7458
|
+
function captureDiagnosticRoute(ctx) {
|
|
7459
|
+
try {
|
|
7460
|
+
return ctx?.hasUI && ctx.mode === "tui" ? ctx : "console";
|
|
7461
|
+
} catch {
|
|
7462
|
+
return "silent";
|
|
7463
|
+
}
|
|
7464
|
+
}
|
|
7465
|
+
function reportDiagnostic(route, message, error, level, consoleMessage = message) {
|
|
7466
|
+
if (route === "console") {
|
|
7467
|
+
console.error(consoleMessage, error);
|
|
7468
|
+
return;
|
|
7469
|
+
}
|
|
7470
|
+
if (route === "silent")
|
|
7471
|
+
return;
|
|
7472
|
+
try {
|
|
7473
|
+
route.ui.notify(message, level);
|
|
7474
|
+
} catch {}
|
|
7475
|
+
}
|
|
7476
|
+
function reportRelayFailure(route, eventName, error) {
|
|
7365
7477
|
if (isRecoverableIntercomDisconnect(error))
|
|
7366
7478
|
return;
|
|
7367
|
-
|
|
7479
|
+
const prefix = `Intercom event relay failed (${eventName}):`;
|
|
7480
|
+
const detail = diagnosticDetail(error);
|
|
7481
|
+
reportDiagnostic(route, `${prefix} ${detail}`, error, "error", prefix);
|
|
7368
7482
|
}
|
|
7369
7483
|
var WARM_UP_RETRY_ATTEMPTS = 5;
|
|
7370
7484
|
function intercom(pi, options = {}) {
|
|
@@ -7372,6 +7486,7 @@ function intercom(pi, options = {}) {
|
|
|
7372
7486
|
let heavyAttempt = null;
|
|
7373
7487
|
let loadedHeavy = null;
|
|
7374
7488
|
let sessionSnapshot = null;
|
|
7489
|
+
let shutdownDiagnosticRoute;
|
|
7375
7490
|
let lifecycleGeneration = 0;
|
|
7376
7491
|
let nextLeaseId = 1;
|
|
7377
7492
|
let activeLease = createLifecycleLease(nextLeaseId++);
|
|
@@ -7455,6 +7570,8 @@ function intercom(pi, options = {}) {
|
|
|
7455
7570
|
await promise;
|
|
7456
7571
|
}
|
|
7457
7572
|
async function loadHeavy(ctx) {
|
|
7573
|
+
let diagnosticRoute = captureDiagnosticRoute(ctx);
|
|
7574
|
+
let diagnosticOwner = ctx && getExtensionContextOwner(ctx);
|
|
7458
7575
|
const lease = activeLease;
|
|
7459
7576
|
if (lease.retired)
|
|
7460
7577
|
throw new Error("Intercom initialization unavailable: no active session");
|
|
@@ -7471,6 +7588,7 @@ function intercom(pi, options = {}) {
|
|
|
7471
7588
|
return handle;
|
|
7472
7589
|
}
|
|
7473
7590
|
let promise;
|
|
7591
|
+
let replayCtx = null;
|
|
7474
7592
|
promise = (async () => {
|
|
7475
7593
|
const captured = {
|
|
7476
7594
|
tools: new Map,
|
|
@@ -7479,7 +7597,6 @@ function intercom(pi, options = {}) {
|
|
|
7479
7597
|
shortcuts: new Map,
|
|
7480
7598
|
eventHandlers: new Map
|
|
7481
7599
|
};
|
|
7482
|
-
let replayCtx = null;
|
|
7483
7600
|
let cleaned = false;
|
|
7484
7601
|
const cleanupCandidate = async () => {
|
|
7485
7602
|
const shutdown = lease.shutdown;
|
|
@@ -7491,7 +7608,9 @@ function intercom(pi, options = {}) {
|
|
|
7491
7608
|
try {
|
|
7492
7609
|
await dispatchHandlers(captured, "session_shutdown", event, cleanupCtx);
|
|
7493
7610
|
} catch (cleanupError) {
|
|
7494
|
-
|
|
7611
|
+
const prefix = "Intercom failed to clean rejected lazy candidate:";
|
|
7612
|
+
const detail = diagnosticDetail(cleanupError);
|
|
7613
|
+
reportDiagnostic(shutdown?.diagnosticRoute ?? diagnosticRoute, `${prefix} ${detail}`, cleanupError, "error", prefix);
|
|
7495
7614
|
}
|
|
7496
7615
|
};
|
|
7497
7616
|
try {
|
|
@@ -7503,6 +7622,11 @@ function intercom(pi, options = {}) {
|
|
|
7503
7622
|
sessionSnapshot = { event: createSyntheticSessionStartEvent(), ctx, generation: ++lifecycleGeneration, lease };
|
|
7504
7623
|
}
|
|
7505
7624
|
await ensureSessionStartReplayed(captured, lease, (replayContext) => {
|
|
7625
|
+
const owner = getExtensionContextOwner(replayContext);
|
|
7626
|
+
if (owner !== diagnosticOwner) {
|
|
7627
|
+
diagnosticRoute = captureDiagnosticRoute(replayContext);
|
|
7628
|
+
diagnosticOwner = owner;
|
|
7629
|
+
}
|
|
7506
7630
|
replayCtx = replayContext;
|
|
7507
7631
|
});
|
|
7508
7632
|
assertLease(lease);
|
|
@@ -7521,8 +7645,8 @@ function intercom(pi, options = {}) {
|
|
|
7521
7645
|
if (heavyAttempt?.promise === promise)
|
|
7522
7646
|
heavyAttempt = null;
|
|
7523
7647
|
if (!isRecoverableIntercomDisconnect(error)) {
|
|
7524
|
-
const message =
|
|
7525
|
-
|
|
7648
|
+
const message = diagnosticDetail(error);
|
|
7649
|
+
reportDiagnostic(diagnosticRoute, `Intercom heavy initialization failed; a later call will retry: ${message}`, error, "warning");
|
|
7526
7650
|
}
|
|
7527
7651
|
});
|
|
7528
7652
|
return promise;
|
|
@@ -7633,6 +7757,7 @@ function intercom(pi, options = {}) {
|
|
|
7633
7757
|
}
|
|
7634
7758
|
const generation = ++lifecycleGeneration;
|
|
7635
7759
|
sessionSnapshot = { event, ctx, generation, lease };
|
|
7760
|
+
shutdownDiagnosticRoute = undefined;
|
|
7636
7761
|
cancelWarmUpRetry();
|
|
7637
7762
|
if (ctx.orchestrationContext?.kind === "workflow-stage" && ctx.orchestrationContext.pendingStageDelivery !== undefined) {
|
|
7638
7763
|
const pendingStageDelivery = ctx.orchestrationContext.pendingStageDelivery;
|
|
@@ -7650,7 +7775,9 @@ function intercom(pi, options = {}) {
|
|
|
7650
7775
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
7651
7776
|
const lease = activeLease;
|
|
7652
7777
|
const generation = ++lifecycleGeneration;
|
|
7653
|
-
|
|
7778
|
+
const diagnosticRoute = captureDiagnosticRoute(ctx);
|
|
7779
|
+
retireLifecycleLease(lease, { event, ctx, generation, diagnosticRoute });
|
|
7780
|
+
shutdownDiagnosticRoute = diagnosticRoute;
|
|
7654
7781
|
cancelWarmUpRetry();
|
|
7655
7782
|
const retiredHeavy = loadedHeavy?.heavy ?? null;
|
|
7656
7783
|
const retiredAttempt = heavyAttempt?.lease === lease ? heavyAttempt.promise : null;
|
|
@@ -7771,13 +7898,15 @@ function intercom(pi, options = {}) {
|
|
|
7771
7898
|
return;
|
|
7772
7899
|
payload.handled = true;
|
|
7773
7900
|
const forwarded = { ...payload, handled: false, completion: undefined };
|
|
7774
|
-
|
|
7901
|
+
const ctx = latestLifecycleContext();
|
|
7902
|
+
const diagnosticRoute = ctx ? captureDiagnosticRoute(ctx) : shutdownDiagnosticRoute ?? "console";
|
|
7903
|
+
payload.completion = loadHeavy(ctx).then(async (handle) => {
|
|
7775
7904
|
handle.assertCurrent();
|
|
7776
7905
|
await dispatchEventHandlers(handle.heavy, PENDING_STAGE_UNDELIVERABLE_EVENT2, forwarded);
|
|
7777
7906
|
handle.assertCurrent();
|
|
7778
7907
|
return forwarded.handled === true && forwarded.completion !== undefined ? await forwarded.completion : false;
|
|
7779
7908
|
}).catch((error) => {
|
|
7780
|
-
reportRelayFailure(PENDING_STAGE_UNDELIVERABLE_EVENT2, error);
|
|
7909
|
+
reportRelayFailure(diagnosticRoute, PENDING_STAGE_UNDELIVERABLE_EVENT2, error);
|
|
7781
7910
|
return false;
|
|
7782
7911
|
});
|
|
7783
7912
|
});
|
|
@@ -7787,7 +7916,9 @@ function intercom(pi, options = {}) {
|
|
|
7787
7916
|
PENDING_STAGE_ROUTE_EVENT2
|
|
7788
7917
|
]) {
|
|
7789
7918
|
pi.events.on(eventName, (payload) => {
|
|
7790
|
-
const
|
|
7919
|
+
const ctx = latestLifecycleContext();
|
|
7920
|
+
const diagnosticRoute = ctx ? captureDiagnosticRoute(ctx) : shutdownDiagnosticRoute ?? "console";
|
|
7921
|
+
const completion = loadHeavy(ctx).then(async (handle) => {
|
|
7791
7922
|
handle.assertCurrent();
|
|
7792
7923
|
await dispatchEventHandlers(handle.heavy, eventName, payload);
|
|
7793
7924
|
handle.assertCurrent();
|
|
@@ -7802,7 +7933,7 @@ function intercom(pi, options = {}) {
|
|
|
7802
7933
|
}
|
|
7803
7934
|
completion.catch((error) => {
|
|
7804
7935
|
rejectLazyResultRelay(pi, eventName, payload, error);
|
|
7805
|
-
reportRelayFailure(eventName, error);
|
|
7936
|
+
reportRelayFailure(diagnosticRoute, eventName, error);
|
|
7806
7937
|
});
|
|
7807
7938
|
});
|
|
7808
7939
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.19-alpha.
|
|
3
|
+
"version": "0.9.19-alpha.4",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -124,7 +124,7 @@ export type ClientMessage =
|
|
|
124
124
|
| { type: "join_group"; requestId: string; group: string }
|
|
125
125
|
| { type: "leave_group"; requestId: string; group?: string }
|
|
126
126
|
| { type: "authorize_supervisor"; requestId: string; childName: string; capability?: string }
|
|
127
|
-
| { type: "send" | "supervisor_send"; to: string; logicalTarget?: string; requirePendingReply?: true; message: Message; attemptId?: string }
|
|
127
|
+
| { type: "send" | "supervisor_send"; to: string; logicalTarget?: string; requirePendingReply?: true; resolveReplyTarget?: true; message: Message; attemptId?: string }
|
|
128
128
|
| {
|
|
129
129
|
type: "send_pending_stage_notification";
|
|
130
130
|
runId: string;
|
|
@@ -168,6 +168,7 @@ export type ClientMessage =
|
|
|
168
168
|
export type BrokerMessage =
|
|
169
169
|
| { type: "registered"; sessionId: string; supervisorSessionId?: string }
|
|
170
170
|
| { type: "registration_failed"; reason: string }
|
|
171
|
+
| { type: "question_target"; messageId: string; attemptId: string; sessionId: string }
|
|
171
172
|
| { type: "sessions"; requestId: string; sessions: SessionInfo[]; workflowStages?: WorkflowStageRosterEntry[]; workflowFutureStages?: WorkflowFutureStageRosterEntry[] }
|
|
172
173
|
| { type: "groups"; requestId: string; groups: GroupSummary[] }
|
|
173
174
|
| { type: "membership_ack"; requestId: string; groups: string[] }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/mcp",
|
|
3
|
-
"version": "0.9.19-alpha.
|
|
3
|
+
"version": "0.9.19-alpha.4",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
|
|
6
6
|
"contributors": [
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.19-alpha.4] - 2026-09-10
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Renamed the terminal subagent control action from `interrupt` to `kill`. Replace `subagent({ action: "interrupt", id })` with `subagent({ action: "kill", id })`, including calls using `runId`. The old action is rejected, not aliased. Killed children cannot be resumed; launch a fresh child with explicit context for follow-up work. Command results and status report killed, while parent cancellation and lower-level host/native interruption retain their existing semantics.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Preserved an explicit kill when parent cancellation arrives during execution-capacity waiting, without allowing a late kill to replace an earlier parent cancellation.
|
|
14
|
+
- Kept grouped Intercom cancellation status consistent when a killed child has parent-cancelled siblings, while retaining each child's outcome.
|
|
15
|
+
- Intercom `send` and `ask` interrupt a working foreground or background child immediately: its current model call or cancellable tool is cancelled and the message is handled in the same child execution without relaunch. Messages admitted during startup, consumed input preflight, overlapping SDK interrupt turns, or final settlement still join the original task rather than creating competing work or disappearing ahead of the result; explicit user abort and owner cancellation remain terminal.
|
|
16
|
+
|
|
17
|
+
## [0.9.19-alpha.3] - 2026-09-09
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Reduced default top-level parallel subagent concurrency from 4 to 3. Explicit configuration and per-call overrides remain honored; the separate per-parent native turn cap remains 4.
|
|
22
|
+
|
|
5
23
|
## [0.9.19-alpha.2] - 2026-09-08
|
|
6
24
|
|
|
7
25
|
### Added
|
|
@@ -181,7 +181,7 @@ subagent({ agent: "codebase-analyzer", task: "Trace authentication.", wait: { ki
|
|
|
181
181
|
subagent({ agent: "codebase-analyzer", task: "Trace authentication.", wait: { kind: "foreground", budgetMs: 30000 } })
|
|
182
182
|
subagent({ action: "wait", id: taskId, budgetMs: 1000 })
|
|
183
183
|
subagent({ action: "status", id: taskId })
|
|
184
|
-
subagent({ action: "
|
|
184
|
+
subagent({ action: "kill", id: taskId })
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
In owner-bound sessions, omitted `wait` means background. Explicit foreground waits use the owner's agent observation budget, normally 30 seconds, unless overridden. Expiry releases the caller, not the execution. Wait or inspect the returned task ID instead of launching a duplicate. Existing SDK callers without an owner retain their original execution path.
|
|
@@ -200,7 +200,7 @@ clarify → gather context → worker → fresh reviewers → worker
|
|
|
200
200
|
|
|
201
201
|
Packaged `worker` defaults to forked context when a launch omits `context`; every other builtin runs fresh. Pass `context: "fresh"` when you intentionally want a fresh `worker` run.
|
|
202
202
|
|
|
203
|
-
Child-safety boundaries are enforced at runtime by typed admission policy. In-process child sessions load bundled extensions through normal discovery. The `subagent` tool may therefore be registered when the child's active tool selection permits it, including the default no-allowlist case; an explicit allowlist may omit it. Tool presence does not grant fanout: fanout is authorized only when the resolved builtin `tools` list includes `subagent`. Typed admission policy lets a non-fanout child use only `list`, `get`, and `status`; delegation and `
|
|
203
|
+
Child-safety boundaries are enforced at runtime by typed admission policy. In-process child sessions load bundled extensions through normal discovery. The `subagent` tool may therefore be registered when the child's active tool selection permits it, including the default no-allowlist case; an explicit allowlist may omit it. Tool presence does not grant fanout: fanout is authorized only when the resolved builtin `tools` list includes `subagent`. Typed admission policy lets a non-fanout child use only `list`, `get`, and `status`; delegation and `kill` receive the fanout refusal. A management-restricted child is also refused `create`, `update`, and `delete`. The bundled `pi-subagents` skill remains parent-only and is stripped from child prompts, including fanout-authorized children. No admitted child may delegate or control another child: launches and `kill` are refused for every child regardless of its fanout authorization. Children receive boundary instructions that they are not the parent orchestrator and must complete their assigned task directly. Forked child context filtering also removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
|
|
204
204
|
|
|
205
205
|
|
|
206
206
|
|
|
@@ -230,13 +230,13 @@ The child can use one dedicated coordination tool:
|
|
|
230
230
|
|
|
231
231
|
Child-side routine completion handoffs are still not expected. In parallel runs, blocking `contact_supervisor` decisions/interviews and parent-targeted `intercom.ask` wait only in the requesting child. The supervisor replies through Intercom to the exact question; the same child continues with its original context and run identity. Sends and progress updates return without a reply.
|
|
232
232
|
|
|
233
|
-
An exact-child probe/commit handshake may release parallel foreground observations, including queued slots, so the parent can respond. It does not end any execution or spend a running concurrency slot. Active siblings keep working, queued siblings start once capacity becomes available, and worktrees remain until their owners finish. Do not relaunch children to answer an ask. Targeted
|
|
233
|
+
An exact-child probe/commit handshake may release parallel foreground observations, including queued slots, so the parent can respond. It does not end any execution or spend a running concurrency slot. Active siblings keep working, queued siblings start once capacity becomes available, and worktrees remain until their owners finish. Do not relaunch children to answer an ask. Targeted kill, explicit batch cancellation, and owner closure remain separate controls.
|
|
234
234
|
|
|
235
235
|
Single-child launches retain their existing terminal parent-ask handoff: the exact live child ends before broker send or waiter admission and the parent receives the verbatim question, ordered attachments, identity, and `[TASK_CONTEXT]` for a fresh child. The bridge still obtains each child's capability during admission; the child connects only when it uses Intercom.
|
|
236
236
|
|
|
237
237
|
Parent-side Atomic sends grouped completion results through Intercom: one grouped message per foreground parent `subagent` run and one per detached child completion while its owning session remains live. When a workflow stage completes, Atomic cancels its still-running detached children and suppresses their late findings and completion notifications instead of forwarding them to the parent/main chat. Intercom-confirmed delivery returns a compact receipt with artifact/session paths; without that confirmation, the normal full output is preserved. Grouped messages include child Intercom targets and full child summaries.
|
|
238
238
|
|
|
239
|
-
If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`,
|
|
239
|
+
If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, killing the run, or nudging the child.
|
|
240
240
|
|
|
241
241
|
If messages do not show up, check the bridge from the intercom side with `intercom({ action: "status" })`.
|
|
242
242
|
|
|
@@ -434,7 +434,7 @@ What the bundled skill covers:
|
|
|
434
434
|
- **Role-agent prompting guidance**: compact contract prompts instead of long scripts, what to include in role-specific meta prompts, and retrieval budgets for researchers
|
|
435
435
|
- **Safety boundaries**: child agents must not run subagents, must not invent intercom targets, and must escalate unapproved decisions
|
|
436
436
|
- **Intercom conventions**: when to ask vs send, and how parent-side result delivery works with `pi-intercom`
|
|
437
|
-
- **Control signals**: attention signals,
|
|
437
|
+
- **Control signals**: attention signals, terminal kills, and status
|
|
438
438
|
|
|
439
439
|
If you are writing an agent that orchestrates subagents, the bundled skill helps it behave correctly without guessing the patterns. If you are a human user, you do not need to read it directly; the README and prompt shortcuts encode the same workflows in user-facing form.
|
|
440
440
|
|
|
@@ -524,11 +524,11 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
524
524
|
|-------|------|---------|-------------|
|
|
525
525
|
| `agent` | string | - | Agent name for single mode, or target for management actions. |
|
|
526
526
|
| `task` | string | - | Task string for single mode. |
|
|
527
|
-
| `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `wait`, or `
|
|
527
|
+
| `action` | string | - | `list`, `get`, `create`, `update`, `delete`, `status`, `wait`, or `kill`. |
|
|
528
528
|
| `config` | object/string | - | Agent config for create/update. |
|
|
529
529
|
| `wait` | object | background in owner-bound sessions | `{ kind: "background" }` yields after admission; `{ kind: "foreground", budgetMs?: number }` waits before automatically yielding. |
|
|
530
530
|
| `budgetMs` | number | owner wait policy | Observation budget for `action: "wait"`; not a child execution deadline. |
|
|
531
|
-
| `id` | string | - | Task ID returned by an owner-bound launch for `wait`, `status`, or `
|
|
531
|
+
| `id` | string | - | Task ID returned by an owner-bound launch for `wait`, `status`, or `kill`. |
|
|
532
532
|
| `output` | `string \| false` | agent default | Override single-agent output file. |
|
|
533
533
|
| `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
|
|
534
534
|
| `reads` | `string[] \| false` | - | Single-agent files to read before execution, or `false` to disable. Relative paths resolve against the effective child `cwd`; absolute paths pass through. |
|
|
@@ -536,7 +536,7 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
536
536
|
| `skill` | `string \| string[] \| false` | agent default | Override skills or disable all. |
|
|
537
537
|
| `model` | string | agent default | Override model. |
|
|
538
538
|
| `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. |
|
|
539
|
-
| `concurrency` | number | config or `
|
|
539
|
+
| `concurrency` | number | config or `3` | Top-level parallel concurrency. |
|
|
540
540
|
| `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
|
|
541
541
|
| `context` | `fresh \| fork` | agent default or `fresh` | `fork` creates real branched sessions from the parent leaf. Packaged `worker` defaults to `fork`; every other builtin runs fresh. |
|
|
542
542
|
| `agentScope` | `user \| project \| both` | `both` | Agent discovery scope. Project wins on collisions. |
|
|
@@ -557,10 +557,10 @@ Status and control actions:
|
|
|
557
557
|
```ts
|
|
558
558
|
subagent({ action: "status" })
|
|
559
559
|
subagent({ action: "status", id: "<run-id>" })
|
|
560
|
-
subagent({ action: "
|
|
560
|
+
subagent({ action: "kill", id: "<run-id>" })
|
|
561
561
|
```
|
|
562
562
|
|
|
563
|
-
Completed, interrupted, and single-child terminal-handoff children cannot be revived by a prior run ID; follow-up work requires a fresh launch with explicit context. A parallel child waiting for a reply is not terminal and continues in its original execution.
|
|
563
|
+
Completed, killed, interrupted, and single-child terminal-handoff children cannot be revived by a prior run ID; follow-up work requires a fresh launch with explicit context. A parallel child waiting for a reply is not terminal and continues in its original execution. Parent cancellation of a still-running child uses the interrupted/abort state: receipts and progress present it as cancelled rather than failed, persisted metadata keeps the abort cause, and bounded partial findings remain available. Migrate old subagent calls from `action: "interrupt"` to `action: "kill"`; the old action is rejected. Kill is terminal and cannot be resumed. Workflow controls use `pause`; host interrupt APIs are unchanged.
|
|
564
564
|
|
|
565
565
|
## Worktree isolation
|
|
566
566
|
|
|
@@ -603,7 +603,7 @@ Subagent configuration controls discovery, parallel limits, session storage, con
|
|
|
603
603
|
}
|
|
604
604
|
```
|
|
605
605
|
|
|
606
|
-
`maxTasks` defaults to `50`; `concurrency` defaults to `
|
|
606
|
+
`maxTasks` defaults to `50`; `concurrency` defaults to `3`. `maxTasks` can set a lower per-call task limit but cannot exceed the hard maximum of `50`. Per-call `concurrency` takes precedence.
|
|
607
607
|
|
|
608
608
|
### `defaultSessionDir`
|
|
609
609
|
|
|
@@ -681,7 +681,7 @@ Foreground runs persist their session and user-facing artifacts beside the paren
|
|
|
681
681
|
run-history.jsonl
|
|
682
682
|
```
|
|
683
683
|
|
|
684
|
-
Task-ID status, wait, and
|
|
684
|
+
Task-ID status, wait, and kill resolve the same owner as launch. Run-ID status uses the existing Rust subagent registry. Owner-bound completion delivery uses persisted intent and acknowledgement records in session history; no second PID registry or execution is created for the UI.
|
|
685
685
|
|
|
686
686
|
## Completion and output
|
|
687
687
|
|
|
@@ -716,7 +716,7 @@ This is disabled by default. Session data may contain source code, paths, enviro
|
|
|
716
716
|
|
|
717
717
|
## Delegation boundary
|
|
718
718
|
|
|
719
|
-
Delegation is exactly one level deep, and nothing configures it. A top-level session
|
|
719
|
+
Delegation is exactly one level deep, and nothing configures it. A top-level session, main chat or a workflow stage, may call `subagent`. A session that was itself admitted as a subagent child may not: every launch and `kill` it attempts is refused with guidance to complete its assigned task directly. The observing actions `list`, `get`, and `status` stay available to a child. Child sessions retain bundled workflow definitions as resources but do not load the workflows extension or expose its `workflow` tool; orchestration stays owned by the parent session.
|
|
720
720
|
|
|
721
721
|
There is no configuration option, agent frontmatter field, or tool parameter for the delegation level. The rule is enforced twice: the subagent executor refuses a child before any run starts, and the Rust `SubagentControl` admission door refuses a child deeper than the single permitted level. Admitted depth is typed admission state and is not inherited through an environment variable.
|
|
722
722
|
|
|
@@ -773,7 +773,7 @@ The main runtime files are:
|
|
|
773
773
|
|------|---------|
|
|
774
774
|
| `src/extension/index.ts` | Extension registration, tool registration, message/render wiring. |
|
|
775
775
|
| `src/agents/agents.ts` | Agent discovery and frontmatter parsing. |
|
|
776
|
-
| `src/runs/foreground/subagent-executor.ts` | Main execution routing for single, parallel, management, status, and
|
|
776
|
+
| `src/runs/foreground/subagent-executor.ts` | Main execution routing for single, parallel, management, status, and kill actions. |
|
|
777
777
|
| `src/runs/foreground/execution.ts` | Core foreground `runSync` handling. |
|
|
778
778
|
| `src/runs/foreground/notify.ts` | Completion-notification delivery for a detached Intercom child. |
|
|
779
779
|
| `src/runs/foreground/completion-notification.ts` | Local completion acknowledgement and ordering barrier for detached children. |
|