removed autoExit schema field from subagent_message

This commit is contained in:
Amos
2026-06-27 02:05:12 +03:00
parent 10fe481aba
commit eb281b63d4
3 changed files with 18 additions and 26 deletions
+1 -2
View File
@@ -189,7 +189,7 @@ The message is delivered into the child's TUI editor (newlines are flattened to
subagent_message({ sessionId: "019f05b2-f1c3", message: "Now write the tests too" }); subagent_message({ sessionId: "019f05b2-f1c3", message: "Now write the tests too" });
``` ```
Resuming is fire-and-forget async: the relaunched session's result is delivered later as a steer message, exactly like a fresh `subagent` spawn. Resuming is fire-and-forget async: the relaunched session always runs its follow-up task autonomously and its result is delivered later as a steer message, exactly like a fresh `subagent` spawn. (There is no per-call behavior knob — resume is always autonomous, matching this result-delivery model.)
> **Guard:** a `sessionId` that maps to a still-running subagent is rejected — resuming would launch a second process mutating the same session file. Steer it by `name` instead. There is no hard-abort tool; to forcibly stop a subagent, use its pane directly. > **Guard:** a `sessionId` that maps to a still-running subagent is rejected — resuming would launch a second process mutating the same session file. Steer it by `name` instead. There is no hard-abort tool; to forcibly stop a subagent, use its pane directly.
@@ -197,7 +197,6 @@ Resuming is fire-and-forget async: the relaunched session's result is delivered
- `name` — exact display name of a running subagent to steer (mutually exclusive with `sessionId`) - `name` — exact display name of a running subagent to steer (mutually exclusive with `sessionId`)
- `sessionId` — id (or id prefix) of a finished session to resume (mutually exclusive with `name`) - `sessionId` — id (or id prefix) of a finished session to resume (mutually exclusive with `name`)
- `message` (required) — the instruction or next task to deliver - `message` (required) — the instruction or next task to deliver
- `autoExit` (resume only) — whether the resumed session auto-exits after its next response. Defaults to `true`; set `false` for an interactive handoff.
--- ---
+8 -11
View File
@@ -997,9 +997,12 @@ function startStatusRefresh(pi: ExtensionAPI) {
(globalThis as any)[STATUS_INTERVAL_KEY] = statusInterval; (globalThis as any)[STATUS_INTERVAL_KEY] = statusInterval;
} }
function resolveResumeLaunchBehavior(params: { autoExit?: boolean }): { autoExit: boolean; interactive: boolean } { // Resuming a finished session is always autonomous: the relaunched agent runs
const autoExit = params.autoExit ?? true; // its follow-up task to completion and the harness delivers the result as a
return { autoExit, interactive: !autoExit }; // steer message (fire-and-forget). An interactive resume would park the pane
// waiting for the user, contradicting that result-delivery model.
function resolveResumeLaunchBehavior(): { autoExit: boolean; interactive: boolean } {
return { autoExit: true, interactive: false };
} }
export const __test__ = { export const __test__ = {
@@ -1889,12 +1892,6 @@ export default function subagentsExtension(pi: ExtensionAPI) {
description: description:
"The message to deliver: a follow-up instruction for a running subagent, or the next task for a resumed session.", "The message to deliver: a follow-up instruction for a running subagent, or the next task for a resumed session.",
}), }),
autoExit: Type.Optional(
Type.Boolean({
description:
"Resume only: whether the resumed session should automatically exit after completing its response. Defaults to true for autonomous follow-up work; set false for interactive resumed sessions.",
}),
),
}), }),
renderCall(args, theme) { renderCall(args, theme) {
@@ -1958,8 +1955,8 @@ export default function subagentsExtension(pi: ExtensionAPI) {
// ── Resume a finished session ── // ── Resume a finished session ──
const requestedId = params.sessionId!.trim(); const requestedId = params.sessionId!.trim();
const message = params.message; const message = params.message;
const name = params.name ?? "Resume"; const name = "Resume";
const { autoExit, interactive } = resolveResumeLaunchBehavior(params); const { autoExit, interactive } = resolveResumeLaunchBehavior();
const startTime = Date.now(); const startTime = Date.now();
const id = Math.random().toString(16).slice(2, 10); const id = Math.random().toString(16).slice(2, 10);
+9 -13
View File
@@ -1474,17 +1474,13 @@ describe("commands", () => {
}); });
describe("tool registration", () => { describe("tool registration", () => {
it("defaults resumed subagents to auto-exit and non-interactive tracking", () => { it("always resumes subagents as autonomous (auto-exit, non-interactive tracking)", () => {
const testApi = (subagentsModule as any).__test__; const testApi = (subagentsModule as any).__test__;
assert.deepEqual(testApi.resolveResumeLaunchBehavior({}), { assert.deepEqual(testApi.resolveResumeLaunchBehavior(), {
autoExit: true, autoExit: true,
interactive: false, interactive: false,
}); });
assert.deepEqual(testApi.resolveResumeLaunchBehavior({ autoExit: false }), {
autoExit: false,
interactive: true,
});
}); });
@@ -1561,7 +1557,7 @@ describe("tool registration", () => {
assert.match(output, /\(unnamed\)/); assert.match(output, /\(unnamed\)/);
}); });
it("registers subagent_message with name, sessionId, message, and an autoExit override", () => { it("registers subagent_message with only name, sessionId, and required message (no autoExit knob)", () => {
const { api, registeredTools } = createMockExtensionApi(); const { api, registeredTools } = createMockExtensionApi();
(subagentsModule as any).default(api); (subagentsModule as any).default(api);
@@ -1569,14 +1565,14 @@ describe("tool registration", () => {
assert.ok(messageTool, "expected subagent_message tool to be registered"); assert.ok(messageTool, "expected subagent_message tool to be registered");
const props = messageTool.parameters.properties; const props = messageTool.parameters.properties;
assert.ok(props.name, "expected name param"); assert.deepEqual(
assert.ok(props.sessionId, "expected sessionId param"); Object.keys(props).sort(),
["message", "name", "sessionId"],
"only name/sessionId/message should remain",
);
assert.equal(props.message.type, "string"); assert.equal(props.message.type, "string");
assert.equal(messageTool.parameters.required?.includes("message"), true); assert.equal(messageTool.parameters.required?.includes("message"), true);
assert.equal(props.autoExit, undefined, "autoExit knob should be removed");
const autoExitSchema = props.autoExit;
assert.equal(autoExitSchema.type, "boolean");
assert.match(autoExitSchema.description, /Defaults to true/);
}); });
it("no longer registers subagent_interrupt or subagent_resume", () => { it("no longer registers subagent_interrupt or subagent_resume", () => {