feat: refine subagents + add chat.inject

Co-authored-by: Tyler Yust <tyler6204@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-01-15 23:06:58 +00:00
parent 688a0ce439
commit a4b347b454
22 changed files with 632 additions and 533 deletions

View File

@@ -22,8 +22,12 @@ export type SubagentRunRecord = {
endedAt?: number;
outcome?: SubagentRunOutcome;
archiveAtMs?: number;
/** @deprecated Use cleanupCompletedAt instead */
announceCompletedAt?: number;
announceHandled: boolean;
/** @deprecated Use cleanupHandled instead */
announceHandled?: boolean;
cleanupCompletedAt?: number;
cleanupHandled?: boolean;
};
const subagentRuns = new Map<string, SubagentRunRecord>();
@@ -46,11 +50,11 @@ function resumeSubagentRun(runId: string) {
if (!runId || resumedRuns.has(runId)) return;
const entry = subagentRuns.get(runId);
if (!entry) return;
if (entry.announceCompletedAt) return;
if (entry.cleanupCompletedAt) return;
if (typeof entry.endedAt === "number" && entry.endedAt > 0) {
if (!beginSubagentAnnounce(runId)) return;
const announce = runSubagentAnnounceFlow({
if (!beginSubagentCleanup(runId)) return;
void runSubagentAnnounceFlow({
childSessionKey: entry.childSessionKey,
childRunId: entry.runId,
requesterSessionKey: entry.requesterSessionKey,
@@ -64,9 +68,8 @@ function resumeSubagentRun(runId: string) {
endedAt: entry.endedAt,
label: entry.label,
outcome: entry.outcome,
});
void announce.then((didAnnounce) => {
finalizeSubagentAnnounce(runId, entry.cleanup, didAnnounce);
}).then((didAnnounce) => {
finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
});
resumedRuns.add(runId);
return;
@@ -156,7 +159,9 @@ async function sweepSubagentRuns() {
}
function ensureListener() {
if (listenerStarted) return;
if (listenerStarted) {
return;
}
listenerStarted = true;
listenerStop = onAgentEvent((evt) => {
if (!evt || evt.stream !== "lifecycle") return;
@@ -186,10 +191,10 @@ function ensureListener() {
}
persistSubagentRuns();
if (!beginSubagentAnnounce(evt.runId)) {
if (!beginSubagentCleanup(evt.runId)) {
return;
}
const announce = runSubagentAnnounceFlow({
void runSubagentAnnounceFlow({
childSessionKey: entry.childSessionKey,
childRunId: entry.runId,
requesterSessionKey: entry.requesterSessionKey,
@@ -203,14 +208,17 @@ function ensureListener() {
endedAt: entry.endedAt,
label: entry.label,
outcome: entry.outcome,
});
void announce.then((didAnnounce) => {
finalizeSubagentAnnounce(evt.runId, entry.cleanup, didAnnounce);
}).then((didAnnounce) => {
finalizeSubagentCleanup(evt.runId, entry.cleanup, didAnnounce);
});
});
}
function finalizeSubagentAnnounce(runId: string, cleanup: "delete" | "keep", didAnnounce: boolean) {
function finalizeSubagentCleanup(
runId: string,
cleanup: "delete" | "keep",
didAnnounce: boolean,
) {
const entry = subagentRuns.get(runId);
if (!entry) return;
if (cleanup === "delete") {
@@ -218,17 +226,23 @@ function finalizeSubagentAnnounce(runId: string, cleanup: "delete" | "keep", did
persistSubagentRuns();
return;
}
if (!didAnnounce) return;
entry.announceCompletedAt = Date.now();
if (!didAnnounce) {
// Allow retry on the next wake if the announce failed.
entry.cleanupHandled = false;
persistSubagentRuns();
return;
}
entry.cleanupCompletedAt = Date.now();
persistSubagentRuns();
}
export function beginSubagentAnnounce(runId: string) {
function beginSubagentCleanup(runId: string) {
const entry = subagentRuns.get(runId);
if (!entry) return false;
if (entry.announceCompletedAt) return false;
if (entry.announceHandled) return false;
entry.announceHandled = true;
// Support legacy field names for backward compatibility
if (entry.cleanupCompletedAt || entry.announceCompletedAt) return false;
if (entry.cleanupHandled || entry.announceHandled) return false;
entry.cleanupHandled = true;
persistSubagentRuns();
return true;
}
@@ -261,7 +275,7 @@ export function registerSubagentRun(params: {
createdAt: now,
startedAt: now,
archiveAtMs,
announceHandled: false,
cleanupHandled: false,
});
ensureListener();
persistSubagentRuns();
@@ -302,8 +316,8 @@ async function waitForSubagentCompletion(runId: string, waitTimeoutMs: number) {
wait.status === "error" ? { status: "error", error: wait.error } : { status: "ok" };
mutated = true;
if (mutated) persistSubagentRuns();
if (!beginSubagentAnnounce(runId)) return;
const announce = runSubagentAnnounceFlow({
if (!beginSubagentCleanup(runId)) return;
void runSubagentAnnounceFlow({
childSessionKey: entry.childSessionKey,
childRunId: entry.runId,
requesterSessionKey: entry.requesterSessionKey,
@@ -317,9 +331,8 @@ async function waitForSubagentCompletion(runId: string, waitTimeoutMs: number) {
endedAt: entry.endedAt,
label: entry.label,
outcome: entry.outcome,
});
void announce.then((didAnnounce) => {
finalizeSubagentAnnounce(runId, entry.cleanup, didAnnounce);
}).then((didAnnounce) => {
finalizeSubagentCleanup(runId, entry.cleanup, didAnnounce);
});
} catch {
// ignore