refactor(agents): trim subagent spawn exports (#106275)

This commit is contained in:
Peter Steinberger
2026-07-13 03:22:12 -07:00
committed by GitHub
parent 2aa4ff0825
commit ca0fe7f691
10 changed files with 42 additions and 89 deletions

View File

@@ -1252,9 +1252,7 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/agents/subagent-announce-dispatch.ts: mapSteerOutcomeToDeliveryResult",
"src/agents/subagent-announce-output.ts: testing",
"src/agents/subagent-attachments.ts: decodeStrictBase64",
"src/agents/subagent-attachments.ts: SubagentInlineAttachment",
"src/agents/subagent-control.ts: testing",
"src/agents/subagent-delivery-state.ts: LegacySubagentRunRecord",
"src/agents/subagent-registry-helpers.ts: resolveSubagentSessionStatus",
"src/agents/subagent-registry-maintenance.ts: listSessionMaintenanceProtectedSubagentSessionKeys",
"src/agents/subagent-registry-read.ts: getSubagentRunByChildSessionKey",
@@ -1273,22 +1271,7 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/agents/subagent-registry.ts: resolveSubagentSessionStatus",
"src/agents/subagent-registry.ts: shouldIgnorePostCompletionAnnounceForSession",
"src/agents/subagent-registry.ts: testing",
"src/agents/subagent-spawn-accepted-note.ts: SUBAGENT_SPAWN_ACCEPTED_NOTE",
"src/agents/subagent-spawn-accepted-note.ts: SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE",
"src/agents/subagent-spawn.runtime.ts: forkSessionFromParent",
"src/agents/subagent-spawn.runtime.ts: ParentForkDecision",
"src/agents/subagent-spawn.runtime.ts: resolveDisplaySessionKey",
"src/agents/subagent-spawn.runtime.ts: resolveParentForkDecision",
"src/agents/subagent-spawn.ts: SpawnSubagentContextMode",
"src/agents/subagent-spawn.ts: SpawnSubagentMode",
"src/agents/subagent-spawn.ts: SpawnSubagentResult",
"src/agents/subagent-spawn.ts: SpawnSubagentSandboxMode",
"src/agents/subagent-spawn.ts: splitModelRef",
"src/agents/subagent-spawn.ts: SUBAGENT_SPAWN_ACCEPTED_NOTE",
"src/agents/subagent-spawn.ts: SUBAGENT_SPAWN_SANDBOX_MODES",
"src/agents/subagent-spawn.ts: SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE",
"src/agents/subagent-spawn.ts: testing",
"src/agents/subagent-spawn.types.ts: SUBAGENT_SPAWN_SANDBOX_MODES",
"src/agents/system-prompt-config.ts: resolveAgentSystemPromptConfig",
"src/agents/system-prompt.ts: buildAgentBootstrapSystemContext",
"src/agents/system-prompt.ts: buildAgentBootstrapSystemPromptSections",
@@ -1418,7 +1401,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/auto-reply/reply/reply-usage-state.ts: clearReplyUsageStateForTest",
"src/auto-reply/reply/session-fork.ts: ForkSessionEntryFromParentParams",
"src/auto-reply/reply/session-fork.ts: ForkSessionEntryFromParentResult",
"src/auto-reply/reply/session-fork.ts: ParentForkDecision",
"src/auto-reply/reply/session-reset-prompt.ts: buildBareSessionResetPrompt",
"src/auto-reply/reply/stage-sandbox-media.ts: appendScpStderrTail",
"src/auto-reply/reply/stage-sandbox-media.ts: SCP_STDERR_TAIL_CHARS",

View File

@@ -1,10 +1,6 @@
// Verifies cron-isolated sessions suppress run-mode subagent acceptance notes.
import { describe, expect, it } from "vitest";
import {
resolveSubagentSpawnAcceptedNote,
SUBAGENT_SPAWN_ACCEPTED_NOTE,
SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE,
} from "./subagent-spawn-accepted-note.js";
import { resolveSubagentSpawnAcceptedNote } from "./subagent-spawn-accepted-note.js";
describe("sessions_spawn: cron isolated session note suppression", () => {
it("suppresses ACCEPTED_NOTE for cron isolated sessions (mode=run)", () => {
@@ -17,43 +13,41 @@ describe("sessions_spawn: cron isolated session note suppression", () => {
});
it("preserves ACCEPTED_NOTE for regular sessions (mode=run)", () => {
expect(
resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: "agent:main:telegram:63448508",
}),
).toBe(SUBAGENT_SPAWN_ACCEPTED_NOTE);
const note = resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: "agent:main:telegram:63448508",
});
expect(note).toContain("Auto-announce is push-based");
});
it("keeps regular run guidance push-based without recommending sessions_yield", () => {
// Run-mode children announce completion asynchronously, not through polling.
expect(SUBAGENT_SPAWN_ACCEPTED_NOTE).toContain("Auto-announce is push-based");
expect(SUBAGENT_SPAWN_ACCEPTED_NOTE).toContain("Continue any independent work");
expect(SUBAGENT_SPAWN_ACCEPTED_NOTE).toContain(
"wait for runtime completion events to arrive as user messages",
);
expect(SUBAGENT_SPAWN_ACCEPTED_NOTE).toContain(
"only answer after completion events for ALL required children arrive",
);
expect(SUBAGENT_SPAWN_ACCEPTED_NOTE).not.toContain("sessions_yield");
const note = resolveSubagentSpawnAcceptedNote({ spawnMode: "run" });
expect(note).toContain("Auto-announce is push-based");
expect(note).toContain("Continue any independent work");
expect(note).toContain("wait for runtime completion events to arrive as user messages");
expect(note).toContain("only answer after completion events for ALL required children arrive");
expect(note).not.toContain("sessions_yield");
});
it("preserves ACCEPTED_NOTE for non-canonical cron-like keys", () => {
expect(
resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: "agent:main:slack:cron:job:run:uuid",
}),
).toBe(SUBAGENT_SPAWN_ACCEPTED_NOTE);
const note = resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: "agent:main:slack:cron:job:run:uuid",
});
expect(note).toContain("Auto-announce is push-based");
});
it("preserves ACCEPTED_NOTE when agentSessionKey is undefined", () => {
expect(
resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: undefined,
}),
).toBe(SUBAGENT_SPAWN_ACCEPTED_NOTE);
const note = resolveSubagentSpawnAcceptedNote({
spawnMode: "run",
agentSessionKey: undefined,
});
expect(note).toContain("Auto-announce is push-based");
});
it("uses the session note for cron session-mode spawns", () => {
@@ -62,6 +56,6 @@ describe("sessions_spawn: cron isolated session note suppression", () => {
spawnMode: "session",
agentSessionKey: "agent:main:cron:dd871818:run:cf959c9f",
}),
).toBe(SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE);
).toBe("thread-bound session stays active after this task; continue in-thread for follow-ups.");
});
});

View File

@@ -33,7 +33,7 @@ export function decodeStrictBase64(value: string, maxDecodedBytes: number): Buff
return decoded;
}
export type SubagentInlineAttachment = {
type SubagentInlineAttachment = {
name: string;
content: string;
encoding?: "utf8" | "base64";

View File

@@ -2,9 +2,10 @@
// nested completion/delivery shape used by current registry records.
import { describe, expect, it } from "vitest";
import { normalizeSubagentRunState } from "./subagent-delivery-state.js";
import type { LegacySubagentRunRecord } from "./subagent-delivery-state.js";
import type { SubagentRunRecord } from "./subagent-registry.types.js";
type LegacySubagentRunRecord = SubagentRunRecord & Record<string, unknown>;
function baseRun(overrides: Partial<LegacySubagentRunRecord> = {}): LegacySubagentRunRecord {
return {
runId: "run-1",

View File

@@ -12,7 +12,7 @@ import type {
} from "./subagent-registry.types.js";
/** Legacy flat fields accepted while restoring older subagent registry rows. */
export type LegacySubagentRunRecord = SubagentRunRecord & {
type LegacySubagentRunRecord = SubagentRunRecord & {
announceRetryCount?: number;
lastAnnounceRetryAt?: number;
lastAnnounceDeliveryError?: string;

View File

@@ -5,9 +5,9 @@
*/
import { isCronSessionKey } from "../routing/session-key.js";
export const SUBAGENT_SPAWN_ACCEPTED_NOTE =
const SUBAGENT_SPAWN_ACCEPTED_NOTE =
"Auto-announce is push-based. After spawning children, do NOT call sessions_list, sessions_history, exec sleep, or any polling tool. Track expected child session keys. Continue any independent work. If your final answer depends on child output, wait for runtime completion events to arrive as user messages and only answer after completion events for ALL required children arrive. If a child completion event arrives AFTER your final answer, reply ONLY with NO_REPLY.";
export const SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE =
const SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE =
"thread-bound session stays active after this task; continue in-thread for follow-ups.";
/** Resolve the post-spawn note, suppressing polling guidance for cron sessions. */

View File

@@ -9,12 +9,7 @@ export {
} from "../config/agent-limits.js";
export { getRuntimeConfig } from "../config/config.js";
export { loadSessionEntry, upsertSessionEntry } from "../config/sessions/session-accessor.js";
export {
forkSessionEntryFromParent,
forkSessionFromParent,
resolveParentForkDecision,
type ParentForkDecision,
} from "../auto-reply/reply/session-fork.js";
export { forkSessionEntryFromParent } from "../auto-reply/reply/session-fork.js";
export { ensureContextEnginesInitialized } from "../context-engine/init.js";
export { resolveContextEngine } from "../context-engine/registry.js";
export { callGateway } from "../gateway/call.js";
@@ -38,8 +33,4 @@ export { resolveAgentConfig } from "./agent-scope.js";
export { AGENT_LANE_SUBAGENT } from "./lanes.js";
export { resolveSandboxRuntimeStatus } from "./sandbox/runtime-status.js";
export { buildSubagentSystemPrompt } from "./subagent-system-prompt.js";
export {
resolveDisplaySessionKey,
resolveInternalSessionKey,
resolveMainSessionAlias,
} from "./tools/sessions-helpers.js";
export { resolveInternalSessionKey, resolveMainSessionAlias } from "./tools/sessions-helpers.js";

View File

@@ -51,6 +51,7 @@ import {
resolvePersistedSelectedModelRef,
} from "./model-selection.js";
import { resolveThinkingDefault } from "./model-thinking-default.js";
import { resolveRequesterOriginForChild } from "./spawn-requester-origin.js";
import {
mapToolContextToSpawnedRunMetadata,
normalizeSpawnedRunMetadata,
@@ -67,13 +68,6 @@ import { countActiveRunsForSession, registerSubagentRun } from "./subagent-regis
import { resolveSubagentRunTimerDelayMs } from "./subagent-run-timeout.js";
import { resolveSubagentSpawnAcceptedNote } from "./subagent-spawn-accepted-note.js";
import { resolveSubagentSpawnOwnership } from "./subagent-spawn-ownership.js";
import { resolveSubagentTargetPolicy } from "./subagent-target-policy.js";
import { normalizeSubagentTaskName } from "./subagent-task-name.js";
export {
SUBAGENT_SPAWN_ACCEPTED_NOTE,
SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE,
} from "./subagent-spawn-accepted-note.js";
import { resolveRequesterOriginForChild } from "./spawn-requester-origin.js";
import {
resolveConfiguredSubagentRunTimeoutSeconds,
resolveSubagentModelAndThinkingPlan,
@@ -111,17 +105,10 @@ import type {
SpawnSubagentMode,
SpawnSubagentSandboxMode,
} from "./subagent-spawn.types.js";
import { resolveSubagentTargetPolicy } from "./subagent-target-policy.js";
import { normalizeSubagentTaskName } from "./subagent-task-name.js";
export {
SUBAGENT_SPAWN_CONTEXT_MODES,
SUBAGENT_SPAWN_MODES,
SUBAGENT_SPAWN_SANDBOX_MODES,
} from "./subagent-spawn.types.js";
export type {
SpawnSubagentContextMode,
SpawnSubagentMode,
SpawnSubagentSandboxMode,
} from "./subagent-spawn.types.js";
export { SUBAGENT_SPAWN_CONTEXT_MODES, SUBAGENT_SPAWN_MODES } from "./subagent-spawn.types.js";
function resolveConfiguredAgentIds(cfg: OpenClawConfig): string[] {
return listAgentIds(cfg);
@@ -198,7 +185,7 @@ type SpawnSubagentContext = {
inheritedToolDenylist?: string[];
};
export type SpawnSubagentResult = {
type SpawnSubagentResult = {
status: "accepted" | "forbidden" | "error";
childSessionKey?: string;
runId?: string;
@@ -219,8 +206,6 @@ export type SpawnSubagentResult = {
};
};
export { splitModelRef } from "./subagent-spawn-plan.js";
async function callSubagentGateway(
params: Parameters<typeof callGateway>[0],
): Promise<Awaited<ReturnType<typeof callGateway>>> {

View File

@@ -5,7 +5,7 @@ export const SUBAGENT_SPAWN_MODES = ["run", "session"] as const;
export type SpawnSubagentMode = (typeof SUBAGENT_SPAWN_MODES)[number];
/** Sandbox escalation policy requested for a spawned subagent. */
export const SUBAGENT_SPAWN_SANDBOX_MODES = ["inherit", "require"] as const;
const SUBAGENT_SPAWN_SANDBOX_MODES = ["inherit", "require"] as const;
export type SpawnSubagentSandboxMode = (typeof SUBAGENT_SPAWN_SANDBOX_MODES)[number];
/** Prompt context relationship between the parent session and spawned subagent. */

View File

@@ -24,7 +24,7 @@ function assertParentSessionForkAllowed(parentEntry: SessionEntry): void {
}
}
export type ParentForkDecision = SessionParentForkDecision;
type ParentForkDecision = SessionParentForkDecision;
type ParentForkDecisionParams = {
parentEntry: SessionEntry;