diff --git a/config/knip.config.ts b/config/knip.config.ts index 147304a2b8c8..6fb9fa628efe 100644 --- a/config/knip.config.ts +++ b/config/knip.config.ts @@ -156,9 +156,9 @@ const rootEntries = [ // Loaded by URL from setup-inference-detection.ts; no static import edge exists. "src/system-agent/setup-inference-detection.worker.ts!", // Split runtime loaded through a path assembled in subagent-registry.ts. - "src/agents/subagent-registry.runtime.ts!", + "src/agents/subagents/registry/subagent-registry.runtime.ts!", // Loaded lazily by the sweeper only when a receipt-bearing or interrupted row is found. - "src/agents/subagent-registry-restart-recovery.ts!", + "src/agents/subagents/registry/subagent-registry-restart-recovery.ts!", // Task cancellation loads this control facade by string path to avoid a registry cycle. "src/tasks/task-registry-control.runtime.ts!", // Human plugin listing lazily loads its formatter to keep JSON startup lean. diff --git a/config/max-lines-baseline.txt b/config/max-lines-baseline.txt index 1c06f769a353..5374fdc5afbc 100644 --- a/config/max-lines-baseline.txt +++ b/config/max-lines-baseline.txt @@ -409,7 +409,7 @@ src/agents/failover-error.ts src/agents/harness/native-hook-relay.test.ts src/agents/harness/selection.test.ts src/agents/harness/selection.ts -src/agents/main-session-restart-recovery.test.ts +src/agents/main-session-recovery/main-session-restart-recovery.test.ts src/agents/model-auth-availability.ts src/agents/model-auth.profiles.test.ts src/agents/model-auth.test.ts @@ -441,15 +441,15 @@ src/agents/sessions/model-registry.ts src/agents/sessions/package-manager.ts src/agents/sessions/resource-loader.ts src/agents/sessions/settings-manager.ts -src/agents/subagent-announce-delivery.test.ts -src/agents/subagent-announce-delivery.ts -src/agents/subagent-announce.format.e2e.test.ts -src/agents/subagent-control.test.ts -src/agents/subagent-control.ts -src/agents/subagent-registry-lifecycle.test.ts -src/agents/subagent-registry-run-manager.ts -src/agents/subagent-registry.steer-restart.test.ts -src/agents/subagent-registry.test.ts +src/agents/subagents/announce/subagent-announce-delivery.test.ts +src/agents/subagents/announce/subagent-announce-delivery.ts +src/agents/subagents/announce/subagent-announce.format.e2e.test.ts +src/agents/subagents/registry/subagent-control.test.ts +src/agents/subagents/registry/subagent-control.ts +src/agents/subagents/registry/subagent-registry-lifecycle.test.ts +src/agents/subagents/registry/subagent-registry-run-manager.ts +src/agents/subagents/registry/subagent-registry.steer-restart.test.ts +src/agents/subagents/registry/subagent-registry.test.ts src/agents/subagents/spawn/subagent-spawn.test.ts src/agents/system-prompt.test.ts src/agents/system-prompt.ts diff --git a/docs/refactor/operator-approvals.md b/docs/refactor/operator-approvals.md index 1bd7f6a56ac1..506855198c21 100644 --- a/docs/refactor/operator-approvals.md +++ b/docs/refactor/operator-approvals.md @@ -50,7 +50,7 @@ This table records the implementation state when #103505 was opened. The rollout | Portable actions | `src/interactive/payload.ts`, `src/plugin-sdk/interactive-runtime.ts`, `src/plugin-sdk/approval-reply-runtime.ts` | Approval buttons are command actions containing `/approve ...`; URL and Web App targets are untyped button fields. | | Telegram | `extensions/telegram/src/approval-handler.runtime.ts`, `extensions/telegram/src/button-types.ts` | The renderer parses command text to recognize approval semantics before producing private callback data. | | Control UI | `ui/src/app/exec-approval.ts`, `ui/src/app/overlays.ts`, `ui/src/components/exec-approval.ts` | Approval UI is a global modal. `ui/src/app-route-paths.ts` and `ui/src/app-routes.ts` use exact routes and rewrite unknown paths to Chat. | -| Session ownership | `src/agents/subagent-registry.types.ts`, `src/agents/subagent-registry-read.ts`, `src/config/sessions/types.ts` | Controller, requester, explicit parent, and legacy spawn ownership exist, but approval events are not projected to those session streams. | +| Session ownership | `src/agents/subagents/registry/subagent-registry.types.ts`, `src/agents/subagents/registry/subagent-registry-read.ts`, `src/config/sessions/types.ts` | Controller, requester, explicit parent, and legacy spawn ownership exist, but approval events are not projected to those session streams. | | Shared state | `src/state/openclaw-state-schema.sql`, `src/state/openclaw-state-db.ts` | Existing immediate transactions and Kysely conditional updates support durable compare-and-set in `state/openclaw.sqlite`. | Representative current tests include `src/gateway/exec-approval-manager.test.ts`, `src/gateway/server-methods/approval-shared.test.ts`, `src/agents/bash-tools.exec-gateway-approval.e2e.test.ts`, `extensions/telegram/src/approval-handler.runtime.test.ts`, and `ui/src/e2e/approval-flow.e2e.test.ts`. @@ -294,7 +294,7 @@ Use a deterministic breadth-first walk: 4. Normalize and de-duplicate on enqueue so the first, shortest path wins. 5. Stop at 64 unique keys; this audience-size cap also bounds traversal depth. -The registry source is `src/agents/subagent-registry-read.ts`; ownership fields are defined in `src/agents/subagent-registry.types.ts`. Session fallback fields are defined in `src/config/sessions/types.ts`. +The registry source is `src/agents/subagents/registry/subagent-registry-read.ts`; ownership fields are defined in `src/agents/subagents/registry/subagent-registry.types.ts`. Session fallback fields are defined in `src/config/sessions/types.ts`. Requested and terminal projections use the same persisted audience even if focus/controller ownership changes while the approval is pending. This guarantees terminal cleanup for every audience session stream that received the request projection. Resolution always targets the source approval ID; audience sessions never receive cloned approval state. Forwarded channel-message cleanup remains the separate delivery-locator follow-up below. diff --git a/qa/scenarios/agents/issue-109025-completion-policy-live.yaml b/qa/scenarios/agents/issue-109025-completion-policy-live.yaml index b3ecd60b222b..37235dcfa2ea 100644 --- a/qa/scenarios/agents/issue-109025-completion-policy-live.yaml +++ b/qa/scenarios/agents/issue-109025-completion-policy-live.yaml @@ -37,8 +37,8 @@ scenario: - docs/help/testing.md codeRefs: - src/agents/requester-tool-policy.ts - - src/agents/subagent-announce-delivery.ts - - src/agents/subagent-capabilities.ts + - src/agents/subagents/announce/subagent-announce-delivery.ts + - src/agents/subagents/spawn/subagent-capabilities.ts - src/agents/tools/sessions-yield-tool.ts execution: kind: flow diff --git a/qa/scenarios/agents/issue-109025-sender-policy-live.yaml b/qa/scenarios/agents/issue-109025-sender-policy-live.yaml index 5e657d10bb27..3df374e0c7bd 100644 --- a/qa/scenarios/agents/issue-109025-sender-policy-live.yaml +++ b/qa/scenarios/agents/issue-109025-sender-policy-live.yaml @@ -30,7 +30,7 @@ scenario: - src/agents/conversation-capability-profile.ts - src/agents/requester-tool-policy.ts - src/agents/sender-tool-policy.ts - - src/agents/subagent-capabilities.ts + - src/agents/subagents/spawn/subagent-capabilities.ts execution: kind: flow suiteIsolation: isolated diff --git a/qa/scenarios/agents/subagent-completion-direct-fallback.yaml b/qa/scenarios/agents/subagent-completion-direct-fallback.yaml index 052f625049f1..84c56ff84fcb 100644 --- a/qa/scenarios/agents/subagent-completion-direct-fallback.yaml +++ b/qa/scenarios/agents/subagent-completion-direct-fallback.yaml @@ -32,8 +32,8 @@ scenario: - docs/channels/qa-channel.md codeRefs: - src/agents/agent-run-terminal-reply.ts - - src/agents/subagent-announce-delivery.ts - - src/agents/subagent-registry-lifecycle.ts + - src/agents/subagents/announce/subagent-announce-delivery.ts + - src/agents/subagents/registry/subagent-registry-lifecycle.ts - extensions/qa-lab/src/providers/mock-openai/server.ts execution: kind: flow diff --git a/qa/scenarios/agents/subagent-stale-child-links.yaml b/qa/scenarios/agents/subagent-stale-child-links.yaml index c15ab43076f5..23aad172eb57 100644 --- a/qa/scenarios/agents/subagent-stale-child-links.yaml +++ b/qa/scenarios/agents/subagent-stale-child-links.yaml @@ -20,7 +20,7 @@ scenario: - docs/help/testing.md codeRefs: - src/gateway/session-utils.ts - - src/agents/subagent-run-liveness.ts + - src/agents/subagents/registry/subagent-run-liveness.ts - extensions/qa-lab/src/gateway-child.ts execution: kind: flow diff --git a/qa/scenarios/runtime/gateway-restart-multi-live.yaml b/qa/scenarios/runtime/gateway-restart-multi-live.yaml index d1015e1bcf33..736b771a6298 100644 --- a/qa/scenarios/runtime/gateway-restart-multi-live.yaml +++ b/qa/scenarios/runtime/gateway-restart-multi-live.yaml @@ -31,7 +31,7 @@ scenario: codeRefs: - extensions/qa-lab/src/suite-runtime-agent-session.ts - extensions/qa-lab/src/suite-runtime-gateway.ts - - src/agents/main-session-restart-recovery.ts + - src/agents/main-session-recovery/main-session-restart-recovery.ts execution: kind: flow summary: Run a fixture-backed audit with GPT-5.4 while replacing the Gateway child three times at durable wait checkpoints. diff --git a/scripts/audit-seams.mts b/scripts/audit-seams.mts index 484e724d22d7..316df1edc9b0 100644 --- a/scripts/audit-seams.mts +++ b/scripts/audit-seams.mts @@ -686,8 +686,8 @@ function describeSubagentSeamKinds(relativePath: string, source: string) { const seamKinds = []; const isAnnounceDispatchPath = - relativePath === "src/agents/subagent-announce.ts" || - relativePath === "src/agents/subagent-announce-dispatch.ts"; + relativePath === "src/agents/subagents/announce/subagent-announce.ts" || + relativePath === "src/agents/subagents/announce/subagent-announce-dispatch.ts"; const importsSpawnRuntime = hasAnyImportSource(source, [ "./subagent-spawn.js", "./acp-spawn.js", @@ -718,6 +718,8 @@ function describeSubagentSeamKinds(relativePath: string, source: string) { const importsAnnounceDelivery = hasAnyImportSource(source, [ "./subagent-announce.js", "./subagent-announce-dispatch.js", + "../announce/subagent-announce.js", + "../announce/subagent-announce-dispatch.js", "./subagent-announce-queue.js", "../infra/outbound/bound-delivery-router.js", "../utils/delivery-context.shared.js", diff --git a/scripts/bench-agent-concurrency-worker.ts b/scripts/bench-agent-concurrency-worker.ts index b9f879d755d3..533349fbb4ff 100644 --- a/scripts/bench-agent-concurrency-worker.ts +++ b/scripts/bench-agent-concurrency-worker.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import { performance } from "node:perf_hooks"; import { pathToFileURL } from "node:url"; -import type { SubagentRunRecord } from "../src/agents/subagent-registry.types.js"; +import type { SubagentRunRecord } from "../src/agents/subagents/registry/subagent-registry.types.js"; import type { DB as OpenClawStateKyselyDatabase } from "../src/state/openclaw-state-db.generated.js"; import { WORKER_RESULT_SENTINEL, @@ -102,7 +102,7 @@ async function drainSpawnSampleRootWork( async function resetRuntime(persist: boolean): Promise { const [subagents, tasks, stateDb, agentDb] = await Promise.all([ - import("../src/agents/subagent-registry.test-helpers.js"), + import("../src/agents/subagents/registry/subagent-registry.test-helpers.js"), import("../src/tasks/task-runtime.test-helpers.js"), import("../src/state/openclaw-state-db.js"), import("../src/state/openclaw-agent-db.js"), @@ -184,8 +184,8 @@ async function configureSpawnRuntime( callGateway: typeof import("../src/gateway/call.js").callGateway, ): Promise { const [subagents, registry, taskStore, flowStore] = await Promise.all([ - import("../src/agents/subagent-registry.test-helpers.js"), - import("../src/agents/subagent-registry-memory.js"), + import("../src/agents/subagents/registry/subagent-registry.test-helpers.js"), + import("../src/agents/subagents/registry/subagent-registry-memory.js"), import("../src/tasks/task-registry.store.js"), import("../src/tasks/task-flow-registry.store.test-support.js"), ]); @@ -315,7 +315,7 @@ async function runSpawnSample( ): Promise { const [pipeline, registry] = await Promise.all([ import("../src/agents/spawn-pipeline.js"), - import("../src/agents/subagent-registry-memory.js"), + import("../src/agents/subagents/registry/subagent-registry-memory.js"), ]); await resetRuntime(mode === "durable"); const barrier = createTerminalWaitBarrier(); @@ -595,8 +595,8 @@ async function runSweepSample(childCount: number): Promise { { getSubagentRunsForChildSession, subagentRuns: runs }, { createSubagentRegistrySweeper }, ] = await Promise.all([ - import("../src/agents/subagent-registry-memory.js"), - import("../src/agents/subagent-registry-sweeper.js"), + import("../src/agents/subagents/registry/subagent-registry-memory.js"), + import("../src/agents/subagents/registry/subagent-registry-sweeper.js"), ]); const now = Date.now(); runs.clear(); @@ -694,7 +694,7 @@ async function runSweepSample(childCount: number): Promise { async function runDedupeSample(childCount: number): Promise { const { dedupeLatestChildCompletionRows } = - await import("../src/agents/subagent-announce-output.js"); + await import("../src/agents/subagents/announce/subagent-announce-output.js"); const rowsForOrder = (generations: number[]) => Array.from({ length: childCount }, (_, child) => generations.map((generation) => ({ diff --git a/scripts/check-session-accessor-boundary.mts b/scripts/check-session-accessor-boundary.mts index 764da11df9bb..326f26d8de18 100644 --- a/scripts/check-session-accessor-boundary.mts +++ b/scripts/check-session-accessor-boundary.mts @@ -109,8 +109,8 @@ export const migratedSessionAccessorFiles = new Set([ "src/agents/embedded-agent-runner/transcript-rewrite.ts", "src/agents/embedded-agent-runner/transcript-runtime-state.ts", "src/agents/live-model-switch.ts", - "src/agents/subagent-control.ts", - "src/agents/subagent-registry-helpers.ts", + "src/agents/subagents/registry/subagent-control.ts", + "src/agents/subagents/registry/subagent-registry-helpers.ts", "src/auto-reply/reply/abort.ts", "src/auto-reply/reply/agent-runner-helpers.ts", "src/auto-reply/reply/agent-runner.ts", @@ -187,13 +187,13 @@ export const migratedSessionAccessorWriteFiles = new Set([ "src/agents/embedded-agent-subscribe.handlers.compaction.runtime.ts", "src/agents/embedded-agent-runner/run/attempt.ts", "src/agents/live-model-switch.ts", - "src/agents/main-session-restart-recovery-checkpoint.ts", - "src/agents/main-session-restart-recovery-marking.ts", - "src/agents/main-session-restart-recovery-store.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-checkpoint.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-marking.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-store.ts", "src/agents/session-suspension.ts", "src/auto-reply/reply/abort.ts", - "src/agents/subagent-control.ts", - "src/agents/subagent-registry-helpers.ts", + "src/agents/subagents/registry/subagent-control.ts", + "src/agents/subagents/registry/subagent-registry-helpers.ts", "src/agents/tools/session-status-tool.ts", "src/auto-reply/reply/abort-cutoff.runtime.ts", "src/auto-reply/reply/agent-runner-cli-dispatch.ts", diff --git a/scripts/check-session-transcript-reader-boundary.mts b/scripts/check-session-transcript-reader-boundary.mts index 0639dc22db82..57d4d4dcf07b 100644 --- a/scripts/check-session-transcript-reader-boundary.mts +++ b/scripts/check-session-transcript-reader-boundary.mts @@ -69,12 +69,12 @@ const gatewaySessionServerMethodFiles = [ ]; export const migratedSessionTranscriptReaderFiles = new Set([ - "src/agents/main-session-restart-recovery-store.ts", - "src/agents/subagent-announce-output.test.ts", - "src/agents/subagent-announce-output.ts", - "src/agents/subagent-announce.runtime.ts", - "src/agents/subagent-registry-restart-recovery.test.ts", - "src/agents/subagent-registry-restart-recovery.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-store.ts", + "src/agents/subagents/announce/subagent-announce-output.test.ts", + "src/agents/subagents/announce/subagent-announce-output.ts", + "src/agents/subagents/announce/subagent-announce.runtime.ts", + "src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts", + "src/agents/subagents/registry/subagent-registry-restart-recovery.ts", "src/agents/tools/embedded-gateway-stub.runtime.ts", "src/agents/tools/embedded-gateway-stub.test.ts", "src/agents/tools/embedded-gateway-stub.ts", diff --git a/scripts/lib/export-name-collision-baseline.json b/scripts/lib/export-name-collision-baseline.json index e65932e0947d..1e434d2f12cd 100644 --- a/scripts/lib/export-name-collision-baseline.json +++ b/scripts/lib/export-name-collision-baseline.json @@ -200,15 +200,15 @@ { "name": "countActiveDescendantRuns", "files": [ - "src/agents/subagent-registry-read.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-read.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { "name": "countPendingDescendantRuns", "files": [ - "src/agents/subagent-registry-announce-read.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-announce-read.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { @@ -524,8 +524,8 @@ { "name": "getLatestSubagentRunByChildSessionKey", "files": [ - "src/agents/subagent-registry-read.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-read.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { @@ -672,8 +672,8 @@ { "name": "listDescendantRunsForRequester", "files": [ - "src/agents/subagent-registry-read.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-read.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { @@ -702,8 +702,8 @@ { "name": "listSubagentRunsForController", "files": [ - "src/agents/subagent-registry-read.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-read.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { @@ -806,7 +806,7 @@ "files": [ "src/agents/auth-profiles/constants.ts", "src/agents/embedded-agent-runner/logger.ts", - "src/agents/main-session-restart-recovery-shared.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-shared.ts", "src/system-agent/setup-inference-core.ts", "src/tasks/task-registry-state.ts" ] @@ -1081,7 +1081,7 @@ { "name": "readSessionEntry", "files": [ - "src/agents/subagent-announce.runtime.ts", + "src/agents/subagents/announce/subagent-announce.runtime.ts", "src/cron/isolated-agent.turn-test-helpers.ts" ] }, @@ -1184,8 +1184,8 @@ { "name": "replaceSubagentRunAfterSteer", "files": [ - "src/agents/subagent-registry-runtime.ts", - "src/agents/subagent-registry.ts" + "src/agents/subagents/registry/subagent-registry-runtime.ts", + "src/agents/subagents/registry/subagent-registry.ts" ] }, { diff --git a/scripts/lib/session-accessor-debt-baseline.json b/scripts/lib/session-accessor-debt-baseline.json index 3b7c632e1c9f..7cb71a72b998 100644 --- a/scripts/lib/session-accessor-debt-baseline.json +++ b/scripts/lib/session-accessor-debt-baseline.json @@ -2,8 +2,8 @@ "embeddedAgentSessionTarget": {}, "memoryHostSessionCorpus": {}, "sessionAccessorRead": { - "src/agents/subagent-announce-output.ts": 3, - "src/agents/subagent-announce.test-support.ts": 2, + "src/agents/subagents/announce/subagent-announce-output.ts": 3, + "src/agents/subagents/announce/subagent-announce.test-support.ts": 2, "src/agents/tools/transcripts-tool.ts": 2, "src/auto-reply/reply/commands-session-store.ts": 2, "src/config/sessions/session-accessor.entry.ts": 2 diff --git a/scripts/test-live-shard.mts b/scripts/test-live-shard.mts index 7f05ff605520..f7399f950d70 100644 --- a/scripts/test-live-shard.mts +++ b/scripts/test-live-shard.mts @@ -26,7 +26,7 @@ const OPTIONAL_LIVE_SHARD_FILE_ENVS = new Map([ ["src/agents/embedded-agent-runner.cache.live.test.ts", ["OPENCLAW_LIVE_CACHE_TEST"]], ["src/agents/live-cache-regression.live.test.ts", ["OPENCLAW_LIVE_CACHE_TEST"]], ["src/agents/provider-headers.live.test.ts", ["OPENCLAW_LIVE_CACHE_TEST"]], - ["src/agents/subagent-announce.live.test.ts", ["OPENCLAW_LIVE_SUBAGENT_E2E"]], + ["src/agents/subagents/announce/subagent-announce.live.test.ts", ["OPENCLAW_LIVE_SUBAGENT_E2E"]], ["src/agents/tools/image-tool.ollama.live.test.ts", ["OPENCLAW_LIVE_OLLAMA_IMAGE"]], ["src/agents/tools/image-tool.providers.live.test.ts", ["OPENCLAW_LIVE_IMAGE_TOOL_TEST"]], [ diff --git a/scripts/test-live-subagent-announce-docker.sh b/scripts/test-live-subagent-announce-docker.sh index 3dd2404f0eb6..4c36013ce54b 100644 --- a/scripts/test-live-subagent-announce-docker.sh +++ b/scripts/test-live-subagent-announce-docker.sh @@ -85,7 +85,7 @@ cd "$tmp_dir" OPENCLAW_LIVE_TEST=1 \ OPENCLAW_LIVE_SUBAGENT_E2E=1 \ OPENCLAW_VITEST_MAX_WORKERS="${OPENCLAW_VITEST_MAX_WORKERS:-1}" \ -node --import tsx scripts/test-live.mts -- src/agents/subagent-announce.live.test.ts -- --reporter=verbose +node --import tsx scripts/test-live.mts -- src/agents/subagents/announce/subagent-announce.live.test.ts -- --reporter=verbose EOF OPENCLAW_LIVE_DOCKER_REPO_ROOT="$ROOT_DIR" "$TRUSTED_HARNESS_DIR/scripts/test-live-build-docker.sh" @@ -98,7 +98,7 @@ if openclaw_live_uses_managed_bind_dirs; then fi echo "==> Run subagent announce live test in Docker" -echo "==> Target: src/agents/subagent-announce.live.test.ts" +echo "==> Target: src/agents/subagents/announce/subagent-announce.live.test.ts" echo "==> Model: ${OPENCLAW_LIVE_SUBAGENT_E2E_MODEL:-openai/gpt-5.6-luna}" echo "==> Profile file: $PROFILE_STATUS" DOCKER_RUN_ARGS=() diff --git a/src/agents/agent-command-recovery-owner.test.ts b/src/agents/agent-command-recovery-owner.test.ts index 8ada58ca902f..3adb46d0d521 100644 --- a/src/agents/agent-command-recovery-owner.test.ts +++ b/src/agents/agent-command-recovery-owner.test.ts @@ -6,13 +6,13 @@ import { loadSessionEntry, replaceSessionEntry } from "../config/sessions/sessio import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; import { runWithAgentCommandRecoveryOwner } from "./agent-command-recovery-owner.js"; import type { AgentCommandOpts } from "./command/types.js"; -import { claimMainSessionRecoveryOwner } from "./main-session-recovery-store.js"; +import { claimMainSessionRecoveryOwner } from "./main-session-recovery/main-session-recovery-store.js"; const recoveryOwnerMocks = vi.hoisted(() => ({ scheduleMainSessionRecoveryPendingTarget: vi.fn(), })); -vi.mock("./main-session-recovery-owner-release.js", () => ({ +vi.mock("./main-session-recovery/main-session-recovery-owner-release.js", () => ({ scheduleMainSessionRecoveryPendingTarget: recoveryOwnerMocks.scheduleMainSessionRecoveryPendingTarget, })); diff --git a/src/agents/agent-command-recovery-owner.ts b/src/agents/agent-command-recovery-owner.ts index 26f27e140c0d..5935bde695b7 100644 --- a/src/agents/agent-command-recovery-owner.ts +++ b/src/agents/agent-command-recovery-owner.ts @@ -3,8 +3,8 @@ import type { InternalSessionEntry } from "../config/sessions.js"; import { formatErrorMessage } from "../infra/errors.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import type { AgentCommandOpts } from "./command/types.js"; -import { repairMainSessionRecoveryMutation } from "./main-session-recovery-lifecycle.js"; -import { scheduleMainSessionRecoveryPendingTarget } from "./main-session-recovery-owner-release.js"; +import { repairMainSessionRecoveryMutation } from "./main-session-recovery/main-session-recovery-lifecycle.js"; +import { scheduleMainSessionRecoveryPendingTarget } from "./main-session-recovery/main-session-recovery-owner-release.js"; import { claimMainSessionRecoveryOwner, inspectMainSessionRecoveryRequired, @@ -12,7 +12,7 @@ import { releaseMainSessionRecoveryOwner, type MainSessionRecoveryOwnerLease, type MainSessionRecoveryPendingTarget, -} from "./main-session-recovery-store.js"; +} from "./main-session-recovery/main-session-recovery-store.js"; const log = createSubsystemLogger("agents/agent-command"); diff --git a/src/agents/agent-command.live-model-switch.test.ts b/src/agents/agent-command.live-model-switch.test.ts index c297232cb6a4..08fa94707065 100644 --- a/src/agents/agent-command.live-model-switch.test.ts +++ b/src/agents/agent-command.live-model-switch.test.ts @@ -240,7 +240,7 @@ vi.mock("./command/types.js", () => ({})); // Recovery ownership has dedicated store-backed coverage. This command suite // uses an intentionally synthetic session resolver with no durable store path. -vi.mock("./main-session-recovery-store.js", () => ({ +vi.mock("./main-session-recovery/main-session-recovery-store.js", () => ({ claimMainSessionRecoveryOwner: vi.fn(async () => ({ kind: "not_required" })), inspectMainSessionRecoveryRequired: vi.fn(async () => ({ kind: "not_required" })), releaseMainSessionRecoveryOwner: vi.fn(async () => undefined), diff --git a/src/agents/agent-command.ts b/src/agents/agent-command.ts index 32ab0af45821..cd29ca32ba3e 100644 --- a/src/agents/agent-command.ts +++ b/src/agents/agent-command.ts @@ -59,7 +59,7 @@ import { resolveInternalSessionEffectsTarget, } from "./internal-session-effects.js"; import { AGENT_LANE_SUBAGENT } from "./lanes.js"; -import type { MainSessionRecoveryPendingTarget } from "./main-session-recovery-store.js"; +import type { MainSessionRecoveryPendingTarget } from "./main-session-recovery/main-session-recovery-store.js"; import type { AgentRunSessionTarget } from "./run-session-target.js"; import { createAgentRunRestartAbortError } from "./run-termination.js"; import { measureAgentStartup } from "./startup-timing.js"; diff --git a/src/agents/agent-steering-queue.test.ts b/src/agents/agent-steering-queue.test.ts index 996441d2a5c3..491ca811505d 100644 --- a/src/agents/agent-steering-queue.test.ts +++ b/src/agents/agent-steering-queue.test.ts @@ -6,7 +6,10 @@ import { prependAgentSteeringPrompt, releaseLeasedAgentSteeringItemsFromSubagentRuns, } from "./agent-steering-queue.js"; -import type { PendingFinalDeliveryPayload, SubagentRunRecord } from "./subagent-registry.types.js"; +import type { + PendingFinalDeliveryPayload, + SubagentRunRecord, +} from "./subagents/registry/subagent-registry.types.js"; const requesterSessionKey = "agent:main:main"; diff --git a/src/agents/agent-steering-queue.ts b/src/agents/agent-steering-queue.ts index 84684874da5b..1f7a115850bb 100644 --- a/src/agents/agent-steering-queue.ts +++ b/src/agents/agent-steering-queue.ts @@ -5,7 +5,7 @@ import type { PendingFinalDeliveryPayload, SubagentCompletionDeliveryState, SubagentRunRecord, -} from "./subagent-registry.types.js"; +} from "./subagents/registry/subagent-registry.types.js"; import { selectDeliverableSessionsReply } from "./tools/sessions-send-tokens.js"; // Steering queue utilities for delivering completed subagent results back into diff --git a/src/agents/agent-tools.policy.ts b/src/agents/agent-tools.policy.ts index 169a34e5b409..c0316aa79441 100644 --- a/src/agents/agent-tools.policy.ts +++ b/src/agents/agent-tools.policy.ts @@ -34,7 +34,7 @@ import { resolveStoredSubagentCapabilities, type SessionCapabilityStore, type SubagentSessionRole, -} from "./subagent-capabilities.js"; +} from "./subagents/spawn/subagent-capabilities.js"; import { isToolAllowedByPolicyName } from "./tool-policy-match.js"; import { mergeAlsoAllowPolicy, resolveToolProfilePolicy } from "./tool-policy.js"; import { AUTOMATIONS_TOOL_NAME } from "./tools/automations-tool-name.js"; diff --git a/src/agents/agent-tools.ts b/src/agents/agent-tools.ts index 836f0c75fe3e..800acb55edd0 100644 --- a/src/agents/agent-tools.ts +++ b/src/agents/agent-tools.ts @@ -77,7 +77,7 @@ import { createReadTool, createWriteTool, } from "./sessions/index.js"; -import type { TrustedSubagentCompletionHandoff } from "./subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "./subagents/announce/subagent-announce-handoff.js"; import { createToolFsPolicy, resolveToolFsConfig } from "./tool-fs-policy.js"; import { resolveToolLoopDetectionConfig } from "./tool-loop-detection-config.js"; import { buildDeclaredToolAllowlistContext } from "./tool-policy-declared-context.js"; diff --git a/src/agents/code-mode-bridge.ts b/src/agents/code-mode-bridge.ts index bf0061f9c688..bcd193837e15 100644 --- a/src/agents/code-mode-bridge.ts +++ b/src/agents/code-mode-bridge.ts @@ -11,8 +11,11 @@ import type { CodeModeNamespaceRuntime } from "./code-mode-namespaces.js"; import type { PendingBridgeRequest, SettledBridgeRequest } from "./code-mode-runtime.js"; import { readCodeModeSkill } from "./code-mode-skills.js"; import type { AgentToolUpdateCallback } from "./runtime/index.js"; -import { getSwarmRunByLaunchReplayKey, initSubagentRegistry } from "./subagent-registry.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; +import { + getSwarmRunByLaunchReplayKey, + initSubagentRegistry, +} from "./subagents/registry/subagent-registry.js"; +import type { SubagentRunRecord } from "./subagents/registry/subagent-registry.types.js"; import { SWARM_CODE_MODE_IDEMPOTENCY_KEY, SWARM_CODE_MODE_REQUEST_FINGERPRINT, diff --git a/src/agents/command/attempt-execution.ts b/src/agents/command/attempt-execution.ts index bd56994dfdc1..2eae2830b7b2 100644 --- a/src/agents/command/attempt-execution.ts +++ b/src/agents/command/attempt-execution.ts @@ -92,7 +92,7 @@ import { buildUsageWithNoCost } from "../stream-message-shared.js"; import { isSubagentAnnounceCompletionHandoff, isTrustedSubagentCompletionHandoffForRun, -} from "../subagent-announce-handoff.js"; +} from "../subagents/announce/subagent-announce-handoff.js"; import { isRuntimeToolAllowed, isToolAllowedByPolicies } from "../tool-policy-match.js"; import { DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS } from "../tool-result-limits.js"; import type { ContextUsage } from "../usage.js"; diff --git a/src/agents/command/session-store.ts b/src/agents/command/session-store.ts index 3f6ce6cadb5b..d858b402f80a 100644 --- a/src/agents/command/session-store.ts +++ b/src/agents/command/session-store.ts @@ -20,7 +20,7 @@ import { setCliSessionId, } from "../cli-session.js"; import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js"; -import { clearMainSessionRecoveryAfterAgentRun } from "../main-session-recovery-clear.js"; +import { clearMainSessionRecoveryAfterAgentRun } from "../main-session-recovery/main-session-recovery-clear.js"; import { isCliProvider } from "../model-selection.js"; import { deriveSessionTotalTokens, hasNonzeroUsage } from "../usage.js"; diff --git a/src/agents/command/session.ts b/src/agents/command/session.ts index a0bcc6100c73..7b2fc3f12c9d 100644 --- a/src/agents/command/session.ts +++ b/src/agents/command/session.ts @@ -41,7 +41,7 @@ import { sessionDeliveryChannel } from "../../utils/delivery-context.shared.js"; import { listAgentIds, resolveDefaultAgentId } from "../agent-scope.js"; import { clearBootstrapSnapshotOnSessionRollover } from "../bootstrap-cache.js"; import { clearAllCliSessions } from "../cli-session.js"; -import { transitionMainSessionRecovery } from "../main-session-recovery-state.js"; +import { transitionMainSessionRecovery } from "../main-session-recovery/main-session-recovery-state.js"; /** Resolved command session identity plus backing store metadata. */ type SessionResolution = { diff --git a/src/agents/command/types.ts b/src/agents/command/types.ts index 5eccb85f4dc4..9f00bd6847d1 100644 --- a/src/agents/command/types.ts +++ b/src/agents/command/types.ts @@ -21,9 +21,9 @@ import type { ExecApprovalContinuationPromptRange } from "../bash-tools.exec-app import type { ExecElevatedDefaults } from "../bash-tools.exec-types.js"; import type { BootstrapContextRunKind } from "../bootstrap-mode.js"; import type { CliSessionBindingFacts } from "../cli-runner/types.js"; -import type { MainSessionRecoveryOwnerLease } from "../main-session-recovery-store.js"; +import type { MainSessionRecoveryOwnerLease } from "../main-session-recovery/main-session-recovery-store.js"; import type { ScheduledToolPolicyContext } from "../scheduled-tool-policy.js"; -import type { TrustedSubagentCompletionHandoff } from "../subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "../subagents/announce/subagent-announce-handoff.js"; import type { AgentStreamParams, ClientToolDefinition } from "./shared-types.js"; /** Image content block for Claude API multimodal messages. */ diff --git a/src/agents/conversation-capability-profile.ts b/src/agents/conversation-capability-profile.ts index f36e32f4efe8..bb202aee9a39 100644 --- a/src/agents/conversation-capability-profile.ts +++ b/src/agents/conversation-capability-profile.ts @@ -25,7 +25,7 @@ import { import { pickSandboxToolPolicy } from "./sandbox-tool-policy.js"; import type { SandboxToolPolicy } from "./sandbox/types.js"; import type { ScheduledToolPolicyContext } from "./scheduled-tool-policy.js"; -import type { TrustedSubagentCompletionHandoff } from "./subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "./subagents/announce/subagent-announce-handoff.js"; import type { PromptMode } from "./system-prompt.types.js"; import { collectExplicitAllowlist, diff --git a/src/agents/embedded-agent-runner/compact.types.ts b/src/agents/embedded-agent-runner/compact.types.ts index b969b59428d8..6fd17fbc1132 100644 --- a/src/agents/embedded-agent-runner/compact.types.ts +++ b/src/agents/embedded-agent-runner/compact.types.ts @@ -15,7 +15,7 @@ import type { SkillSnapshot } from "../../skills/types.js"; import type { ExecElevatedDefaults, ExecToolDefaults } from "../bash-tools.exec-types.js"; import type { AgentRunSessionTarget } from "../run-session-target.js"; import type { AgentRuntimeAuthPlan, AgentRuntimePlan } from "../runtime-plan/types.js"; -import type { TrustedSubagentCompletionHandoff } from "../subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "../subagents/announce/subagent-announce-handoff.js"; export type CompactEmbeddedAgentSessionParams = { sessionId: string; diff --git a/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts b/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts index 6e5d16f8951f..07b7cbeff4df 100644 --- a/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts +++ b/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts @@ -36,7 +36,7 @@ vi.mock("../harness/selection.js", () => ({ runAgentHarnessSettledTurnFinalization: vi.fn(), })); -vi.mock("../subagent-registry.js", () => ({ +vi.mock("../subagents/registry/subagent-registry.js", () => ({ settleRequesterAfterSessionSpawns: mocks.settleRequesterAfterSessionSpawns, })); diff --git a/src/agents/embedded-agent-runner/run/attempt-execution-settle.test.ts b/src/agents/embedded-agent-runner/run/attempt-execution-settle.test.ts index ca92debb5c33..05b0468f9e98 100644 --- a/src/agents/embedded-agent-runner/run/attempt-execution-settle.test.ts +++ b/src/agents/embedded-agent-runner/run/attempt-execution-settle.test.ts @@ -13,7 +13,7 @@ const mocks = vi.hoisted(() => ({ vi.mock("../logger.js", () => ({ log: { debug: mocks.logDebug, error: mocks.logError }, })); -vi.mock("../../subagent-registry.js", () => ({ +vi.mock("../../subagents/registry/subagent-registry.js", () => ({ settleRequesterAfterSessionSpawns: mocks.settleRequesterAfterSessionSpawns, })); vi.mock("../runs.js", () => ({ clearActiveEmbeddedRun: mocks.clearActiveEmbeddedRun })); diff --git a/src/agents/embedded-agent-runner/run/attempt-history.ts b/src/agents/embedded-agent-runner/run/attempt-history.ts index 82f65e1a415e..ccfe88f43bb9 100644 --- a/src/agents/embedded-agent-runner/run/attempt-history.ts +++ b/src/agents/embedded-agent-runner/run/attempt-history.ts @@ -27,7 +27,7 @@ import { DEFAULT_CONTEXT_TOKENS } from "../../defaults.js"; import type { AgentRuntimePlan } from "../../runtime-plan/types.js"; import type { AgentMessage } from "../../runtime/index.js"; import type { AgentSession, SessionManager } from "../../sessions/index.js"; -import { buildActiveSubagentSystemPromptAddition } from "../../subagent-active-context.js"; +import { buildActiveSubagentSystemPromptAddition } from "../../subagents/registry/subagent-active-context.js"; import { resolveTranscriptPolicy, type TranscriptPolicy } from "../../transcript-policy.js"; import { getHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js"; import { log } from "../logger.js"; diff --git a/src/agents/embedded-agent-runner/run/attempt-prompt-build.ts b/src/agents/embedded-agent-runner/run/attempt-prompt-build.ts index a19138cce326..000c0c299f1e 100644 --- a/src/agents/embedded-agent-runner/run/attempt-prompt-build.ts +++ b/src/agents/embedded-agent-runner/run/attempt-prompt-build.ts @@ -29,7 +29,7 @@ import type { AgentSession, SessionManager } from "../../sessions/index.js"; import { leasePendingAgentSteeringItems, prependAgentSteeringPrompt, -} from "../../subagent-registry.js"; +} from "../../subagents/registry/subagent-registry.js"; import { appendModelIdentitySystemPrompt, buildModelIdentityPromptLine, diff --git a/src/agents/embedded-agent-runner/run/attempt-prompt-phase.test.ts b/src/agents/embedded-agent-runner/run/attempt-prompt-phase.test.ts index b85de1b418d2..20b98f175a5c 100644 --- a/src/agents/embedded-agent-runner/run/attempt-prompt-phase.test.ts +++ b/src/agents/embedded-agent-runner/run/attempt-prompt-phase.test.ts @@ -15,7 +15,7 @@ const mocks = vi.hoisted(() => ({ warn: vi.fn(), })); -vi.mock("../../subagent-registry.js", () => ({ +vi.mock("../../subagents/registry/subagent-registry.js", () => ({ releasePendingAgentSteeringItems: mocks.releasePendingSteering, })); vi.mock("../google-prompt-cache.js", () => ({ diff --git a/src/agents/embedded-agent-runner/run/attempt-prompt-phase.ts b/src/agents/embedded-agent-runner/run/attempt-prompt-phase.ts index c00ca9669eb1..246fec1ed22f 100644 --- a/src/agents/embedded-agent-runner/run/attempt-prompt-phase.ts +++ b/src/agents/embedded-agent-runner/run/attempt-prompt-phase.ts @@ -4,7 +4,7 @@ import { buildHeartbeatOutcomeContext, claimHeartbeatOutcomeForRun, } from "../../../infra/heartbeat-outcome-store.js"; -import { releasePendingAgentSteeringItems } from "../../subagent-registry.js"; +import { releasePendingAgentSteeringItems } from "../../subagents/registry/subagent-registry.js"; import { prepareGooglePromptCacheStreamFn } from "../google-prompt-cache.js"; import { log } from "../logger.js"; import { resolveEmbeddedAgentApiKey } from "../stream-resolution.js"; diff --git a/src/agents/embedded-agent-runner/run/attempt-prompt-submit.ts b/src/agents/embedded-agent-runner/run/attempt-prompt-submit.ts index 3ad885f19729..1c7b98b1b905 100644 --- a/src/agents/embedded-agent-runner/run/attempt-prompt-submit.ts +++ b/src/agents/embedded-agent-runner/run/attempt-prompt-submit.ts @@ -11,7 +11,7 @@ import { resolveImageSanitizationLimits } from "../../image-sanitization.js"; import type { AgentMessage } from "../../runtime/index.js"; import type { SandboxContext } from "../../sandbox/types.js"; import type { AgentSession } from "../../sessions/index.js"; -import { ackPendingAgentSteeringItems } from "../../subagent-registry.js"; +import { ackPendingAgentSteeringItems } from "../../subagents/registry/subagent-registry.js"; import { normalizeAssistantReplayContent } from "../replay-history.js"; import { updateActiveEmbeddedRunSnapshot } from "../runs.js"; import { diff --git a/src/agents/embedded-agent-runner/run/attempt-settle.ts b/src/agents/embedded-agent-runner/run/attempt-settle.ts index 375966641d73..e49fa9c58949 100644 --- a/src/agents/embedded-agent-runner/run/attempt-settle.ts +++ b/src/agents/embedded-agent-runner/run/attempt-settle.ts @@ -10,7 +10,7 @@ import { type AgentRunAttemptFailureSource, } from "../../agent-run-terminal-outcome.js"; import type { AgentMessage } from "../../runtime/index.js"; -import { settleRequesterAfterSessionSpawns } from "../../subagent-registry.js"; +import { settleRequesterAfterSessionSpawns } from "../../subagents/registry/subagent-registry.js"; import type { NormalizedUsage } from "../../usage.js"; import { log } from "../logger.js"; import type { PromptCacheBreak, PromptCacheChange } from "../prompt-cache-observability.js"; diff --git a/src/agents/embedded-agent-runner/run/backend.ts b/src/agents/embedded-agent-runner/run/backend.ts index 5351cc66188e..3ad1f48ddb0b 100644 --- a/src/agents/embedded-agent-runner/run/backend.ts +++ b/src/agents/embedded-agent-runner/run/backend.ts @@ -6,7 +6,7 @@ import { runAgentHarnessSettledTurnFinalization, } from "../../harness/selection.js"; import type { AgentHarness } from "../../harness/types.js"; -import { settleRequesterAfterSessionSpawns } from "../../subagent-registry.js"; +import { settleRequesterAfterSessionSpawns } from "../../subagents/registry/subagent-registry.js"; import type { EmbeddedRunAttemptParams, EmbeddedRunAttemptResult } from "./types.js"; /** diff --git a/src/agents/embedded-agent-runner/run/params.ts b/src/agents/embedded-agent-runner/run/params.ts index 6067c00b5458..c5024c7b6e0c 100644 --- a/src/agents/embedded-agent-runner/run/params.ts +++ b/src/agents/embedded-agent-runner/run/params.ts @@ -50,7 +50,7 @@ import type { AgentRunSessionTarget } from "../../run-session-target.js"; import type { AgentMessage } from "../../runtime/index.js"; import type { ScheduledToolPolicyContext } from "../../scheduled-tool-policy.js"; import type { SessionManager } from "../../sessions/index.js"; -import type { TrustedSubagentCompletionHandoff } from "../../subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "../../subagents/announce/subagent-announce-handoff.js"; import type { SilentReplyPromptMode } from "../../system-prompt.types.js"; import type { PromptMode } from "../../system-prompt.types.js"; import type { EmbeddedAgentExecutionPhase } from "../execution-phase.js"; diff --git a/src/agents/main-session-recovery-clear.ts b/src/agents/main-session-recovery/main-session-recovery-clear.ts similarity index 93% rename from src/agents/main-session-recovery-clear.ts rename to src/agents/main-session-recovery/main-session-recovery-clear.ts index 79f916d86a3c..d2d94e5225d5 100644 --- a/src/agents/main-session-recovery-clear.ts +++ b/src/agents/main-session-recovery/main-session-recovery-clear.ts @@ -1,4 +1,4 @@ -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; type MainRecoveryStateFields = Pick< SessionEntry, diff --git a/src/agents/main-session-recovery-lifecycle.ts b/src/agents/main-session-recovery/main-session-recovery-lifecycle.ts similarity index 97% rename from src/agents/main-session-recovery-lifecycle.ts rename to src/agents/main-session-recovery/main-session-recovery-lifecycle.ts index cd52668708d5..f0335f29e5dc 100644 --- a/src/agents/main-session-recovery-lifecycle.ts +++ b/src/agents/main-session-recovery/main-session-recovery-lifecycle.ts @@ -1,6 +1,6 @@ -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import { mergeRestartRecoveryTerminalRunIds } from "../config/sessions/restart-recovery-state.js"; -import { retryAsync } from "../infra/retry.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import { mergeRestartRecoveryTerminalRunIds } from "../../config/sessions/restart-recovery-state.js"; +import { retryAsync } from "../../infra/retry.js"; import { buildMainSessionRecoveryClearPatch, type MainRecoveryStateFields, diff --git a/src/agents/main-session-recovery-owner-release.ts b/src/agents/main-session-recovery/main-session-recovery-owner-release.ts similarity index 84% rename from src/agents/main-session-recovery-owner-release.ts rename to src/agents/main-session-recovery/main-session-recovery-owner-release.ts index d301936225a4..0a8a616cf252 100644 --- a/src/agents/main-session-recovery-owner-release.ts +++ b/src/agents/main-session-recovery/main-session-recovery-owner-release.ts @@ -19,5 +19,5 @@ export function scheduleMainSessionRecoveryPendingTarget( () => {}, // Startup recovery remains the fallback if this optional module cannot load. ); } -import { getRuntimeConfig } from "../config/io.js"; -import { getGatewayRecoveryRuntime } from "../gateway/server-recovery-runtime-context.js"; +import { getRuntimeConfig } from "../../config/io.js"; +import { getGatewayRecoveryRuntime } from "../../gateway/server-recovery-runtime-context.js"; diff --git a/src/agents/main-session-recovery-run-ownership.test.ts b/src/agents/main-session-recovery/main-session-recovery-run-ownership.test.ts similarity index 97% rename from src/agents/main-session-recovery-run-ownership.test.ts rename to src/agents/main-session-recovery/main-session-recovery-run-ownership.test.ts index b4a2f947f2a5..5843aa76f0d6 100644 --- a/src/agents/main-session-recovery-run-ownership.test.ts +++ b/src/agents/main-session-recovery/main-session-recovery-run-ownership.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; import { projectMainSessionRecoveryLifecycle } from "./main-session-recovery-lifecycle.js"; function recoveryEntry(params?: { diff --git a/src/agents/main-session-recovery-state.execution-identity.test.ts b/src/agents/main-session-recovery/main-session-recovery-state.execution-identity.test.ts similarity index 99% rename from src/agents/main-session-recovery-state.execution-identity.test.ts rename to src/agents/main-session-recovery/main-session-recovery-state.execution-identity.test.ts index c93df634bb14..897b6efe13d0 100644 --- a/src/agents/main-session-recovery-state.execution-identity.test.ts +++ b/src/agents/main-session-recovery/main-session-recovery-state.execution-identity.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import type { InternalSessionEntry as SessionEntry, MainRestartRecoveryState, -} from "../config/sessions.js"; +} from "../../config/sessions.js"; import { transitionMainSessionRecovery } from "./main-session-recovery-state.js"; const executionIdentity = (runId: string) => ({ diff --git a/src/agents/main-session-recovery-state.test.ts b/src/agents/main-session-recovery/main-session-recovery-state.test.ts similarity index 99% rename from src/agents/main-session-recovery-state.test.ts rename to src/agents/main-session-recovery/main-session-recovery-state.test.ts index 8e420b3e440d..ef5721ccd9c4 100644 --- a/src/agents/main-session-recovery-state.test.ts +++ b/src/agents/main-session-recovery/main-session-recovery-state.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import type { InternalSessionEntry as SessionEntry, MainRestartRecoveryState, -} from "../config/sessions.js"; +} from "../../config/sessions.js"; import { buildMainSessionRecoveryClearPatch } from "./main-session-recovery-clear.js"; import { projectMainSessionRecoveryLifecycle } from "./main-session-recovery-lifecycle.js"; import { transitionMainSessionRecovery } from "./main-session-recovery-state.js"; diff --git a/src/agents/main-session-recovery-state.ts b/src/agents/main-session-recovery/main-session-recovery-state.ts similarity index 98% rename from src/agents/main-session-recovery-state.ts rename to src/agents/main-session-recovery/main-session-recovery-state.ts index 67a1efb26633..2a28a1c89e04 100644 --- a/src/agents/main-session-recovery-state.ts +++ b/src/agents/main-session-recovery/main-session-recovery-state.ts @@ -1,14 +1,18 @@ import { PENDING_FINAL_DELIVERY_CLEAR_PATCH, sanitizePendingFinalDeliveryText, -} from "../auto-reply/reply/pending-final-delivery.js"; +} from "../../auto-reply/reply/pending-final-delivery.js"; import type { InternalSessionEntry as SessionEntry, MainRestartRecoveryState, RestartRecoveryRun, -} from "../config/sessions.js"; -import { buildRestartRecoveryClaimCleanupPatch } from "../config/sessions/restart-recovery-state.js"; -import { isAcpSessionKey, isCronSessionKey, isSubagentSessionKey } from "../routing/session-key.js"; +} from "../../config/sessions.js"; +import { buildRestartRecoveryClaimCleanupPatch } from "../../config/sessions/restart-recovery-state.js"; +import { + isAcpSessionKey, + isCronSessionKey, + isSubagentSessionKey, +} from "../../routing/session-key.js"; import { buildMainSessionRecoveryClearPatch } from "./main-session-recovery-clear.js"; import type { MainSessionRecoveryCommand, diff --git a/src/agents/main-session-recovery-store.test.ts b/src/agents/main-session-recovery/main-session-recovery-store.test.ts similarity index 98% rename from src/agents/main-session-recovery-store.test.ts rename to src/agents/main-session-recovery/main-session-recovery-store.test.ts index 0f93ff5d1588..91ea5e15c35b 100644 --- a/src/agents/main-session-recovery-store.test.ts +++ b/src/agents/main-session-recovery/main-session-recovery-store.test.ts @@ -1,16 +1,16 @@ import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import * as sessionAccessor from "../config/sessions/session-accessor.js"; +import { useAutoCleanupTempDirTracker } from "../../../test/helpers/temp-dir.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import * as sessionAccessor from "../../config/sessions/session-accessor.js"; import { applySessionEntryLifecycleMutation, listSessionEntries, -} from "../config/sessions/session-accessor.js"; +} from "../../config/sessions/session-accessor.js"; import { getAgentEventLifecycleGeneration, rotateAgentEventLifecycleGeneration, -} from "../infra/agent-events.js"; +} from "../../infra/agent-events.js"; import { claimMainSessionRecoveryOwner, commitMainSessionRecovery, diff --git a/src/agents/main-session-recovery-store.ts b/src/agents/main-session-recovery/main-session-recovery-store.ts similarity index 98% rename from src/agents/main-session-recovery-store.ts rename to src/agents/main-session-recovery/main-session-recovery-store.ts index 2124eb4252ce..f3766e44985e 100644 --- a/src/agents/main-session-recovery-store.ts +++ b/src/agents/main-session-recovery/main-session-recovery-store.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import { applySessionEntryReplacements } from "../config/sessions/session-accessor.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import { applySessionEntryReplacements } from "../../config/sessions/session-accessor.js"; +import { getAgentEventLifecycleGeneration } from "../../infra/agent-events.js"; import { retryMainSessionRecoveryMutation, scheduleMainSessionRecoveryMutation, diff --git a/src/agents/main-session-recovery-types.ts b/src/agents/main-session-recovery/main-session-recovery-types.ts similarity index 99% rename from src/agents/main-session-recovery-types.ts rename to src/agents/main-session-recovery/main-session-recovery-types.ts index b2d091f4afd1..c751b857c0ac 100644 --- a/src/agents/main-session-recovery-types.ts +++ b/src/agents/main-session-recovery/main-session-recovery-types.ts @@ -2,7 +2,7 @@ import type { InternalSessionEntry as SessionEntry, MainRestartRecoveryState, RestartRecoveryRun, -} from "../config/sessions.js"; +} from "../../config/sessions.js"; type MainSessionRecoveryExecutionIdentity = NonNullable< MainRestartRecoveryState["executionIdentity"] diff --git a/src/agents/main-session-restart-claim.ts b/src/agents/main-session-recovery/main-session-restart-claim.ts similarity index 91% rename from src/agents/main-session-restart-claim.ts rename to src/agents/main-session-recovery/main-session-restart-claim.ts index 81d1aeaef893..b597ed69cd73 100644 --- a/src/agents/main-session-restart-claim.ts +++ b/src/agents/main-session-recovery/main-session-restart-claim.ts @@ -1,6 +1,6 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import type { SessionEntry } from "../config/sessions.js"; -import { loadExactSessionEntry } from "../config/sessions/session-accessor.js"; +import type { SessionEntry } from "../../config/sessions.js"; +import { loadExactSessionEntry } from "../../config/sessions/session-accessor.js"; export type ExpectedRestartRecoveryClaim = { canonicalSessionKey?: string; diff --git a/src/agents/main-session-restart-dispatch.ts b/src/agents/main-session-recovery/main-session-restart-dispatch.ts similarity index 93% rename from src/agents/main-session-restart-dispatch.ts rename to src/agents/main-session-recovery/main-session-restart-dispatch.ts index d729a2ea67d7..94ec0f8b1e85 100644 --- a/src/agents/main-session-restart-dispatch.ts +++ b/src/agents/main-session-recovery/main-session-restart-dispatch.ts @@ -1,35 +1,36 @@ import { randomUUID } from "node:crypto"; import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { GatewayClientRequestError } from "../../packages/gateway-client/src/index.js"; -import { isExecutionIdentityCollectionEnabled } from "../audit/audit-config.js"; -import { createExecutionIdentityAdmissionToken } from "../audit/execution-identity-admission.js"; -import { sanitizePendingFinalDeliveryText } from "../auto-reply/reply/pending-final-delivery.js"; -import type { SessionEntry } from "../config/sessions.js"; +import { GatewayClientRequestError } from "../../../packages/gateway-client/src/index.js"; +import { isExecutionIdentityCollectionEnabled } from "../../audit/audit-config.js"; +import { createExecutionIdentityAdmissionToken } from "../../audit/execution-identity-admission.js"; +import { sanitizePendingFinalDeliveryText } from "../../auto-reply/reply/pending-final-delivery.js"; +import type { SessionEntry } from "../../config/sessions.js"; import { buildRestartRecoveryClaimCleanupPatch, hasRestartRecoveryTerminalRun, resolveRestartRecoveryChannelAuthority, -} from "../config/sessions/restart-recovery-state.js"; -import { applySessionEntryReplacements } from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { isTrustedMessageActionTurnIngress } from "../gateway/message-action-turn-capability.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import type { AgentRunRequest } from "../gateway/server-methods/agent-request-types.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import { findRestartRecoveryUnsafeReplyHook } from "../plugins/restart-recovery-hook-safety.js"; -import { withPluginRuntimeRegistryScope } from "../plugins/runtime/gateway-request-scope.js"; -import { CommandLane } from "../process/lanes.js"; -import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; -import { MAIN_SESSION_RESTART_RECOVERY_SOURCE_TOOL } from "../sessions/input-provenance.js"; -import { resolveSendPolicy } from "../sessions/send-policy.js"; +} from "../../config/sessions/restart-recovery-state.js"; +import { applySessionEntryReplacements } from "../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import { isTrustedMessageActionTurnIngress } from "../../gateway/message-action-turn-capability.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; +import type { AgentRunRequest } from "../../gateway/server-methods/agent-request-types.js"; +import { getAgentEventLifecycleGeneration } from "../../infra/agent-events.js"; +import { createSubsystemLogger } from "../../logging/subsystem.js"; +import { findRestartRecoveryUnsafeReplyHook } from "../../plugins/restart-recovery-hook-safety.js"; +import { withPluginRuntimeRegistryScope } from "../../plugins/runtime/gateway-request-scope.js"; +import { CommandLane } from "../../process/lanes.js"; +import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; +import { MAIN_SESSION_RESTART_RECOVERY_SOURCE_TOOL } from "../../sessions/input-provenance.js"; +import { resolveSendPolicy } from "../../sessions/send-policy.js"; import { deliveryContextFromSession, normalizeDeliveryContext, type DeliveryContext, -} from "../utils/delivery-context.shared.js"; -import { isDeliverableMessageChannel } from "../utils/message-channel.js"; -import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "./agent-scope.js"; +} from "../../utils/delivery-context.shared.js"; +import { isDeliverableMessageChannel } from "../../utils/message-channel.js"; +import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent-scope.js"; +import { loadAgentRuntimePluginRegistryHandle } from "../runtime-plugins.js"; import { buildMainSessionRecoveryClearPatch } from "./main-session-recovery-clear.js"; import { repairMainSessionRecoveryMutation, @@ -44,7 +45,6 @@ import { } from "./main-session-recovery-state.js"; import { commitMainSessionRecovery } from "./main-session-recovery-store.js"; import { normalizeFiniteTimestamp } from "./main-session-restart-recovery-shared.js"; -import { loadAgentRuntimePluginRegistryHandle } from "./runtime-plugins.js"; const log = createSubsystemLogger("main-session-restart-recovery"); const RESTART_RECOVERY_RESUME_MESSAGE = diff --git a/src/agents/main-session-restart-recovery-checkpoint.ts b/src/agents/main-session-recovery/main-session-restart-recovery-checkpoint.ts similarity index 97% rename from src/agents/main-session-restart-recovery-checkpoint.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-checkpoint.ts index 458a6dba8f51..aabdb2df058e 100644 --- a/src/agents/main-session-restart-recovery-checkpoint.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-checkpoint.ts @@ -1,23 +1,23 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import { buildRestartRecoveryClaimCleanupPatch } from "../config/sessions/restart-recovery-state.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import { buildRestartRecoveryClaimCleanupPatch } from "../../config/sessions/restart-recovery-state.js"; import { applySessionEntryReplacements, persistSessionTranscriptTurn, type SessionTranscriptTurnLifecyclePatch, updateSessionEntry, -} from "../config/sessions/session-accessor.js"; +} from "../../config/sessions/session-accessor.js"; import { hasInterSessionUserProvenance, isCompletionReportInputProvenance, -} from "../sessions/input-provenance.js"; -import { buildRunUserTurnIdempotencyKey } from "../sessions/user-turn-transcript.js"; -import { isAnnounceRunId } from "./announce-idempotency.js"; +} from "../../sessions/input-provenance.js"; +import { buildRunUserTurnIdempotencyKey } from "../../sessions/user-turn-transcript.js"; +import { isAnnounceRunId } from "../announce-idempotency.js"; import { getTranscriptMessageRole as getMessageRole, isTerminalSilentAssistantMessage, readTerminalSourceReplyDeliveryMirror, -} from "./embedded-agent-runner/message-visibility.js"; +} from "../embedded-agent-runner/message-visibility.js"; import { buildMainSessionRecoveryClearPatch } from "./main-session-recovery-clear.js"; import { isRestartAbortTailArtifact } from "./main-session-restart-recovery-resume-policy.js"; import { buildRestartRecoveryExpectedState, log } from "./main-session-restart-recovery-shared.js"; diff --git a/src/agents/main-session-restart-recovery-failure.ts b/src/agents/main-session-recovery/main-session-restart-recovery-failure.ts similarity index 91% rename from src/agents/main-session-restart-recovery-failure.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-failure.ts index 589d18eb1213..bc74793a560d 100644 --- a/src/agents/main-session-restart-recovery-failure.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-failure.ts @@ -1,8 +1,8 @@ -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import { loadSessionEntry } from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import { loadSessionEntry } from "../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; +import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; import type { MainSessionRecoveryObservation } from "./main-session-recovery-state.js"; import { commitMainSessionRecovery } from "./main-session-recovery-store.js"; import { resolveRestartRecoveryDeliveryContext } from "./main-session-restart-dispatch.js"; diff --git a/src/agents/main-session-restart-recovery-marking.ts b/src/agents/main-session-recovery/main-session-restart-recovery-marking.ts similarity index 93% rename from src/agents/main-session-restart-recovery-marking.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-marking.ts index 0a0df0612efb..5c80f4e98545 100644 --- a/src/agents/main-session-restart-recovery-marking.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-marking.ts @@ -1,20 +1,21 @@ import { randomUUID } from "node:crypto"; import path from "node:path"; -import { resolveStateDir } from "../config/paths.js"; +import { resolveStateDir } from "../../config/paths.js"; import { type InternalSessionEntry as SessionEntry, type RestartRecoveryRun, resolveAllAgentSessionStoreTargetsSync, -} from "../config/sessions.js"; -import { applySessionEntryReplacements } from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { resolveGatewaySessionStoreTarget } from "../gateway/session-utils.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; -import { listAgentRunsForSession } from "../infra/agent-run-registry.js"; +} from "../../config/sessions.js"; +import { applySessionEntryReplacements } from "../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import { resolveGatewaySessionStoreTarget } from "../../gateway/session-utils.js"; +import { getAgentEventLifecycleGeneration } from "../../infra/agent-events.js"; +import { listAgentRunsForSession } from "../../infra/agent-run-registry.js"; import { listActiveEmbeddedRunSessionIds, listActiveEmbeddedRunSessionKeys, -} from "./embedded-agent-runner/run-state.js"; +} from "../embedded-agent-runner/run-state.js"; +import { resolveAgentSessionDirs } from "../session-dirs.js"; import { isMainRestartRecoveryCandidate, normalizeMainSessionRecoveryRunFences, @@ -27,7 +28,6 @@ import { normalizeStringSet, resolveRestartRecoveryStorePaths, } from "./main-session-restart-recovery-shared.js"; -import { resolveAgentSessionDirs } from "./session-dirs.js"; async function markRecoveryStore(params: { storePath: string; diff --git a/src/agents/main-session-restart-recovery-notice.ts b/src/agents/main-session-recovery/main-session-restart-recovery-notice.ts similarity index 87% rename from src/agents/main-session-restart-recovery-notice.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-notice.ts index 63215cce3080..3f65de35c216 100644 --- a/src/agents/main-session-restart-recovery-notice.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-notice.ts @@ -1,14 +1,14 @@ -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; import type { SessionTranscriptTurnExpectedState, SessionTranscriptTurnLifecyclePatch, -} from "../config/sessions/session-accessor.js"; -import { appendAssistantMessageToSessionTranscript } from "../config/sessions/transcript.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; -import type { DeliveryContext } from "../utils/delivery-context.shared.js"; -import { resolveDefaultAgentId } from "./agent-scope-config.js"; +} from "../../config/sessions/session-accessor.js"; +import { appendAssistantMessageToSessionTranscript } from "../../config/sessions/transcript.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; +import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; +import type { DeliveryContext } from "../../utils/delivery-context.shared.js"; +import { resolveDefaultAgentId } from "../agent-scope-config.js"; import type { MainSessionRecoveryObservation } from "./main-session-recovery-state.js"; import { commitMainSessionRecovery } from "./main-session-recovery-store.js"; import { buildUnresumableSessionNoticeIdempotencyKey } from "./main-session-restart-claim.js"; diff --git a/src/agents/main-session-restart-recovery-resume-policy.test.ts b/src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.test.ts similarity index 97% rename from src/agents/main-session-restart-recovery-resume-policy.test.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.test.ts index de0282b0853d..2c7af2a5546e 100644 --- a/src/agents/main-session-restart-recovery-resume-policy.test.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.test.ts @@ -1,16 +1,16 @@ import { describe, expect, it, vi } from "vitest"; import { resolveMainSessionResumePolicy } from "./main-session-restart-recovery-resume-policy.js"; -vi.mock("./code-mode-control-tools.js", () => ({ +vi.mock("../code-mode-control-tools.js", () => ({ CODE_MODE_EXEC_TOOL_NAME: "exec", CODE_MODE_WAIT_TOOL_NAME: "wait", })); -vi.mock("./tool-replay-safety.js", () => ({ +vi.mock("../tool-replay-safety.js", () => ({ isAgentToolReplaySafe: ({ name }: { name?: string }) => name === "read", })); -vi.mock("./run-termination.js", () => ({ +vi.mock("../run-termination.js", () => ({ AGENT_RUN_RESTART_ABORT_ERROR: "agent run aborted for restart", AGENT_RUN_RESTART_ABORT_ERROR_CODE: "OPENCLAW_RESTART_ABORT", })); diff --git a/src/agents/main-session-restart-recovery-resume-policy.ts b/src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.ts similarity index 98% rename from src/agents/main-session-restart-recovery-resume-policy.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.ts index 1cbc1063ab77..bd3c0bfe0f02 100644 --- a/src/agents/main-session-restart-recovery-resume-policy.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.ts @@ -1,17 +1,17 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import { CODE_MODE_EXEC_TOOL_NAME, CODE_MODE_WAIT_TOOL_NAME } from "./code-mode-control-tools.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import { CODE_MODE_EXEC_TOOL_NAME, CODE_MODE_WAIT_TOOL_NAME } from "../code-mode-control-tools.js"; import { getTranscriptMessageRole as getMessageRole, isIntermediateAssistantTranscriptMessage, isMeaningfulTranscriptMessage, readTerminalSourceReplyDeliveryMirror, -} from "./embedded-agent-runner/message-visibility.js"; +} from "../embedded-agent-runner/message-visibility.js"; import { AGENT_RUN_RESTART_ABORT_ERROR, AGENT_RUN_RESTART_ABORT_ERROR_CODE, -} from "./run-termination.js"; -import { isAgentToolReplaySafe } from "./tool-replay-safety.js"; +} from "../run-termination.js"; +import { isAgentToolReplaySafe } from "../tool-replay-safety.js"; function readDeliveredTerminalSourceReplyToolCallId( messages: readonly unknown[], diff --git a/src/agents/main-session-restart-recovery-runtime.ts b/src/agents/main-session-recovery/main-session-restart-recovery-runtime.ts similarity index 96% rename from src/agents/main-session-restart-recovery-runtime.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-runtime.ts index 92d5a03be64f..949b22880bfb 100644 --- a/src/agents/main-session-restart-recovery-runtime.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-runtime.ts @@ -1,15 +1,15 @@ -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; import { getAgentEventLifecycleGeneration, isAgentEventLifecycleGenerationCurrent, -} from "../infra/agent-events.js"; -import { sleepWithAbort } from "../infra/backoff.js"; -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; +} from "../../infra/agent-events.js"; +import { sleepWithAbort } from "../../infra/backoff.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../process/gateway-work-admission.js"; import { beginSessionWorkAdmission, cancelSessionWorkAdmissionHandoff, -} from "../sessions/session-lifecycle-admission.js"; +} from "../../sessions/session-lifecycle-admission.js"; import { loadExpectedRestartRecoveryClaim, type ExpectedRestartRecoveryClaim, diff --git a/src/agents/main-session-restart-recovery-shared.ts b/src/agents/main-session-recovery/main-session-restart-recovery-shared.ts similarity index 93% rename from src/agents/main-session-restart-recovery-shared.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-shared.ts index f29348b27d32..cc50f8f7e277 100644 --- a/src/agents/main-session-restart-recovery-shared.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-shared.ts @@ -1,18 +1,18 @@ import path from "node:path"; -import { resolveStateDir } from "../config/paths.js"; +import { resolveStateDir } from "../../config/paths.js"; import { listConfiguredSessionStoreAgentIds, resolveStorePath, type InternalSessionEntry as SessionEntry, resolveAllAgentSessionStoreTargetsSync, -} from "../config/sessions.js"; +} from "../../config/sessions.js"; import { hasSessionEntriesByStatusReadOnly, type SessionTranscriptTurnExpectedState, -} from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import { resolveAgentSessionDirs } from "./session-dirs.js"; +} from "../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import { createSubsystemLogger } from "../../logging/subsystem.js"; +import { resolveAgentSessionDirs } from "../session-dirs.js"; export const log = createSubsystemLogger("main-session-restart-recovery"); export const DEFAULT_RECOVERY_DELAY_MS = 5_000; diff --git a/src/agents/main-session-restart-recovery-store.ts b/src/agents/main-session-recovery/main-session-restart-recovery-store.ts similarity index 95% rename from src/agents/main-session-restart-recovery-store.ts rename to src/agents/main-session-recovery/main-session-restart-recovery-store.ts index c524591c5c6b..25080badf9a1 100644 --- a/src/agents/main-session-restart-recovery-store.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery-store.ts @@ -4,22 +4,22 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe import { type InternalSessionEntry as SessionEntry, resolveSessionWorkStartError, -} from "../config/sessions.js"; +} from "../../config/sessions.js"; import { listSessionEntriesByStatus, loadExactSessionEntry, -} from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { readSessionMessagesAsync } from "../gateway/session-transcript-readers.js"; -import { resolveGatewaySessionStoreTarget } from "../gateway/session-utils.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; -import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; -import { resolveDefaultAgentId } from "./agent-scope-config.js"; +} from "../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; +import { readSessionMessagesAsync } from "../../gateway/session-transcript-readers.js"; +import { resolveGatewaySessionStoreTarget } from "../../gateway/session-utils.js"; +import { getAgentEventLifecycleGeneration } from "../../infra/agent-events.js"; +import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; +import { resolveDefaultAgentId } from "../agent-scope-config.js"; import { listActiveEmbeddedRunSessionIds, listActiveEmbeddedRunSessionKeys, -} from "./embedded-agent-runner/run-state.js"; +} from "../embedded-agent-runner/run-state.js"; import { isMainRestartRecoveryCandidate } from "./main-session-recovery-state.js"; import { commitMainSessionRecovery } from "./main-session-recovery-store.js"; import { diff --git a/src/agents/main-session-restart-recovery.test.ts b/src/agents/main-session-recovery/main-session-restart-recovery.test.ts similarity index 98% rename from src/agents/main-session-restart-recovery.test.ts rename to src/agents/main-session-recovery/main-session-restart-recovery.test.ts index 5b3cbda28087..71286980cae7 100644 --- a/src/agents/main-session-restart-recovery.test.ts +++ b/src/agents/main-session-recovery/main-session-restart-recovery.test.ts @@ -3,66 +3,76 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { GatewayClientRequestError } from "../../packages/gateway-client/src/index.js"; -import { createDeferred } from "../../test/helpers/promise.js"; -import { markInboundContextLabel } from "../auto-reply/reply/inbound-context-marker.js"; -import type { ChannelOutboundAdapter } from "../channels/plugins/types.public.js"; -import type { CliDeps } from "../cli/outbound-send-deps.js"; -import type { OpenClawConfig } from "../config/config.js"; -import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; -import * as sessionAccessor from "../config/sessions/session-accessor.js"; +import { GatewayClientRequestError } from "../../../packages/gateway-client/src/index.js"; +import { createDeferred } from "../../../test/helpers/promise.js"; +import { markInboundContextLabel } from "../../auto-reply/reply/inbound-context-marker.js"; +import type { ChannelOutboundAdapter } from "../../channels/plugins/types.public.js"; +import type { CliDeps } from "../../cli/outbound-send-deps.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; +import * as sessionAccessor from "../../config/sessions/session-accessor.js"; import { appendTranscriptMessage, listSessionEntries, loadSessionEntry as loadSessionEntryRaw, loadTranscriptEvents, replaceSessionEntry, -} from "../config/sessions/session-accessor.js"; -import { callGateway } from "../gateway/call.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; +} from "../../config/sessions/session-accessor.js"; +import { callGateway } from "../../gateway/call.js"; +import type { GatewayRecoveryRuntime } from "../../gateway/server-instance-runtime.types.js"; import { getAgentEventLifecycleGeneration, resetAgentEventsForTest, rotateAgentEventLifecycleGeneration, -} from "../infra/agent-events.js"; -import { registerAgentRunContext } from "../infra/agent-run-registry.js"; +} from "../../infra/agent-events.js"; +import { registerAgentRunContext } from "../../infra/agent-run-registry.js"; import { initializeGlobalHookRunner, resetGlobalHookRunner, -} from "../plugins/hook-runner-global.js"; -import { addTestHook } from "../plugins/hooks.test-fixtures.js"; -import { createEmptyPluginRegistry } from "../plugins/registry-empty.js"; -import { setActivePluginRegistry } from "../plugins/runtime.js"; -import { getPluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js"; +} from "../../plugins/hook-runner-global.js"; +import { addTestHook } from "../../plugins/hooks.test-fixtures.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry-empty.js"; +import { setActivePluginRegistry } from "../../plugins/runtime.js"; +import { getPluginRuntimeGatewayRequestScope } from "../../plugins/runtime/gateway-request-scope.js"; import { getActiveGatewayRootWorkCount, resetGatewayWorkAdmission, tryBeginGatewaySuspendAdmission, -} from "../process/gateway-work-admission.js"; +} from "../../process/gateway-work-admission.js"; import { interruptSessionWorkAdmissions, isSessionLifecycleMutationActive, isSessionWorkAdmissionActive, runExclusiveSessionLifecycleMutation, -} from "../sessions/session-lifecycle-admission.js"; +} from "../../sessions/session-lifecycle-admission.js"; import { closeOpenClawAgentDatabasesForTest, openOpenClawAgentDatabase, -} from "../state/openclaw-agent-db.js"; -import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js"; -import { createOutboundTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js"; -import { normalizeSessionDeliveryState } from "../utils/delivery-context.shared.js"; -import { deliverAgentCommandResult } from "./command/delivery.js"; -import { setActiveEmbeddedRunLifecycleGeneration } from "./embedded-agent-runner/run-state.js"; +} from "../../state/openclaw-agent-db.js"; +import { closeOpenClawStateDatabaseForTest } from "../../state/openclaw-state-db.js"; +import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js"; +import { normalizeSessionDeliveryState } from "../../utils/delivery-context.shared.js"; +import { deliverAgentCommandResult } from "../command/delivery.js"; +import { setActiveEmbeddedRunLifecycleGeneration } from "../embedded-agent-runner/run-state.js"; import { clearActiveEmbeddedRun, setActiveEmbeddedRun, type EmbeddedAgentQueueHandle, -} from "./embedded-agent-runner/runs.js"; +} from "../embedded-agent-runner/runs.js"; import { INTERNAL_RUNTIME_CONTEXT_BEGIN, INTERNAL_RUNTIME_CONTEXT_END, -} from "./internal-runtime-context.js"; +} from "../internal-runtime-context.js"; +import { AGENT_RUN_RESTART_ABORT_ERROR_CODE } from "../run-termination.js"; +import { + createAssistantToolCallMessage, + createSessionEntry, + createSessionStore, + type SessionEntryFixture, + expectRecord, + mockCallArg, + waitForFast, +} from "../subagent-test-fixtures.test-helpers.js"; import * as recoveryOwnerRelease from "./main-session-recovery-owner-release.js"; import { claimMainSessionRecoveryOwner } from "./main-session-recovery-store.js"; import { resolveRestartRecoveryStorePaths } from "./main-session-restart-recovery-shared.js"; @@ -74,16 +84,6 @@ import { scheduleRestartAbortedMainSessionRecoveryAfterOwnerRelease, scheduleRestartAbortedMainSessionRecovery as scheduleRestartAbortedMainSessionRecoveryBase, } from "./main-session-restart-recovery.js"; -import { AGENT_RUN_RESTART_ABORT_ERROR_CODE } from "./run-termination.js"; -import { - createAssistantToolCallMessage, - createSessionEntry, - createSessionStore, - type SessionEntryFixture, - expectRecord, - mockCallArg, - waitForFast, -} from "./subagent-test-fixtures.test-helpers.js"; const transcriptMocks = vi.hoisted(() => ({ appendAssistantMessageToSessionTranscript: vi.fn(), @@ -101,7 +101,7 @@ const executionIdentityEnabledConfig = { logging: { audit: { executionIdentity: true } }, } satisfies OpenClawConfig; -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../gateway/call.js", () => ({ callGateway: vi.fn(async () => ({ runId: "run-resumed" })), })); @@ -144,8 +144,8 @@ function gatewayParams(): Record { return expectRecord(mockCallArg(callGateway).params, "gateway params"); } -vi.mock("../config/sessions/transcript.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../../config/sessions/transcript.js", async (importOriginal) => { + const actual = await importOriginal(); transcriptMocks.appendAssistantMessageToSessionTranscript.mockImplementation( actual.appendAssistantMessageToSessionTranscript, ); @@ -156,11 +156,11 @@ vi.mock("../config/sessions/transcript.js", async (importOriginal) => { }; }); -vi.mock("../plugins/restart-recovery-hook-safety.js", () => ({ +vi.mock("../../plugins/restart-recovery-hook-safety.js", () => ({ findRestartRecoveryUnsafeReplyHook: runtimePluginMocks.findRestartRecoveryUnsafeReplyHook, })); -vi.mock("./runtime-plugins.js", () => ({ +vi.mock("../runtime-plugins.js", () => ({ loadAgentRuntimePluginRegistryHandle: runtimePluginMocks.loadAgentRuntimePluginRegistryHandle, })); diff --git a/src/agents/main-session-restart-recovery.ts b/src/agents/main-session-recovery/main-session-restart-recovery.ts similarity index 100% rename from src/agents/main-session-restart-recovery.ts rename to src/agents/main-session-recovery/main-session-restart-recovery.ts diff --git a/src/agents/openclaw-tools.registration.test.ts b/src/agents/openclaw-tools.registration.test.ts index 7e931672c6bd..f799a0f62eb1 100644 --- a/src/agents/openclaw-tools.registration.test.ts +++ b/src/agents/openclaw-tools.registration.test.ts @@ -529,7 +529,7 @@ describe("sessions_yield completion ownership", () => { ["the controller when the run owner is blank", " ", controllerSessionKey], ["the controller when the run owner is absent", undefined, controllerSessionKey], ] as const)("records yield intent against %s", async (_, runSessionKey, expectedSessionKey) => { - const registry = await import("./subagent-registry.js"); + const registry = await import("./subagents/registry/subagent-registry.js"); const markRequesterTurnYielded = vi .spyOn(registry, "markRequesterTurnYielded") .mockReturnValue(1); diff --git a/src/agents/openclaw-tools.sessions.test.ts b/src/agents/openclaw-tools.sessions.test.ts index edc1f7c82007..d3cba6bdf000 100644 --- a/src/agents/openclaw-tools.sessions.test.ts +++ b/src/agents/openclaw-tools.sessions.test.ts @@ -25,7 +25,7 @@ vi.mock("../gateway/call.js", () => ({ callGateway: (opts: unknown) => callGatewayMock(opts), })); const loadSessionEntryByKeyMock = vi.fn(); -vi.mock("./subagent-announce-delivery.js", () => ({ +vi.mock("./subagents/announce/subagent-announce-delivery.js", () => ({ loadSessionEntryByKey: (sessionKey: string) => loadSessionEntryByKeyMock(sessionKey), })); diff --git a/src/agents/openclaw-tools.subagents.scope.test.ts b/src/agents/openclaw-tools.subagents.scope.test.ts index e37a18c97555..307cc8195487 100644 --- a/src/agents/openclaw-tools.subagents.scope.test.ts +++ b/src/agents/openclaw-tools.subagents.scope.test.ts @@ -11,7 +11,7 @@ import { import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "./subagent-registry.test-helpers.js"; +} from "./subagents/registry/subagent-registry.test-helpers.js"; import { createPerSenderSessionConfig } from "./test-helpers/session-config.js"; import { createSubagentsTool } from "./tools/subagents-tool.js"; diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.allowlist.test.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.allowlist.test.ts index 8711465f76dc..8d82508c7f0b 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.allowlist.test.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.allowlist.test.ts @@ -11,7 +11,7 @@ const hoisted = vi.hoisted(() => ({ configOverride: {} as Record, })); -let resetSubagentRegistryForTests: typeof import("./subagent-registry.test-helpers.js").resetSubagentRegistryForTests; +let resetSubagentRegistryForTests: typeof import("./subagents/registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; let spawnSubagentDirect: typeof import("./subagents/spawn/subagent-spawn.js").spawnSubagentDirect; function resolveAgentConfigFromList(cfg: Record, agentId: string) { diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts index 3a4cbdebeec2..8cedc9c3e16c 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts @@ -19,7 +19,7 @@ import { import { getLatestSubagentRunByChildSessionKey, resetSubagentRegistryForTests, -} from "./subagent-registry.test-helpers.js"; +} from "./subagents/registry/subagent-registry.test-helpers.js"; const fastModeEnv = vi.hoisted(() => { const previous = process.env.OPENCLAW_TEST_FAST; diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts index 3271c39539f0..e0db8709b561 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts @@ -2,18 +2,20 @@ import { vi, type Mock } from "vitest"; import type { SessionRunStatus } from "../../packages/gateway-protocol/src/schema/sessions-row.js"; import type { SubagentLifecycleHookRunner } from "../plugins/hooks.js"; -import { resolveRequesterStoreKey } from "./subagent-requester-store-key.js"; +import { resolveRequesterStoreKey } from "./subagents/announce/subagent-requester-store-key.js"; type SessionsSpawnTestConfig = ReturnType< (typeof import("../config/config.js"))["getRuntimeConfig"] >; type SessionsSpawnHookRunner = SubagentLifecycleHookRunner | null; type CaptureSubagentCompletionReply = - (typeof import("./subagent-announce.js"))["captureSubagentCompletionReply"]; -type RunSubagentAnnounceFlow = (typeof import("./subagent-announce.js"))["runSubagentAnnounceFlow"]; + (typeof import("./subagents/announce/subagent-announce.js"))["captureSubagentCompletionReply"]; +type RunSubagentAnnounceFlow = + (typeof import("./subagents/announce/subagent-announce.js"))["runSubagentAnnounceFlow"]; type CreateSessionsSpawnTool = (typeof import("./tools/sessions-spawn-tool.js"))["createSessionsSpawnTool"]; -type SubagentRegistryTesting = (typeof import("./subagent-registry.test-helpers.js"))["testing"]; +type SubagentRegistryTesting = + (typeof import("./subagents/registry/subagent-registry.test-helpers.js"))["testing"]; type SubagentSpawnTesting = (typeof import("./subagents/spawn/subagent-spawn.test-support.js"))["testing"]; type CreateOpenClawToolsOpts = Parameters[0]; @@ -196,7 +198,7 @@ export async function getSessionsSpawnTool(opts: CreateOpenClawToolsOpts) { const [{ testing: subagentSpawnTesting }, { testing: subagentRegistryTesting }] = await Promise.all([ import("./subagents/spawn/subagent-spawn.test-support.js"), - import("./subagent-registry.test-helpers.js"), + import("./subagents/registry/subagent-registry.test-helpers.js"), ]); cachedSubagentSpawnTesting = subagentSpawnTesting; cachedSubagentRegistryTesting = subagentRegistryTesting; diff --git a/src/agents/openclaw-tools.subagents.test-harness.ts b/src/agents/openclaw-tools.subagents.test-harness.ts index 87db18f2c221..7d7aab75439c 100644 --- a/src/agents/openclaw-tools.subagents.test-harness.ts +++ b/src/agents/openclaw-tools.subagents.test-harness.ts @@ -3,8 +3,8 @@ import { vi } from "vitest"; import { testing as queueCleanupTesting } from "../auto-reply/reply/queue/cleanup.test-support.js"; import type { CallGatewayOptions } from "../gateway/call.js"; import type { MockFn } from "../test-utils/vitest-mock-fn.js"; -import { testing as subagentAnnounceTesting } from "./subagent-announce.js"; -import { testing as subagentControlTesting } from "./subagent-control.test-support.js"; +import { testing as subagentAnnounceTesting } from "./subagents/announce/subagent-announce.js"; +import { testing as subagentControlTesting } from "./subagents/registry/subagent-control.test-support.js"; type LoadedConfig = ReturnType<(typeof import("../config/config.js"))["getRuntimeConfig"]>; diff --git a/src/agents/openclaw-tools.swarm.ts b/src/agents/openclaw-tools.swarm.ts index 658e357efb34..73df4686eeb2 100644 --- a/src/agents/openclaw-tools.swarm.ts +++ b/src/agents/openclaw-tools.swarm.ts @@ -3,7 +3,7 @@ import { getLatestSubagentRunByChildSessionKey, getSubagentRunByRunId, recordSwarmStructuredOutput, -} from "./subagent-registry.js"; +} from "./subagents/registry/subagent-registry.js"; import { resolveSwarmConfig } from "./subagents/swarm/swarm-config.js"; import { createAgentsWaitTool } from "./tools/agents-wait-tool.js"; import type { AnyAgentTool } from "./tools/common.js"; diff --git a/src/agents/openclaw-tools.ts b/src/agents/openclaw-tools.ts index 9b1cd9382662..567d808c585a 100644 --- a/src/agents/openclaw-tools.ts +++ b/src/agents/openclaw-tools.ts @@ -691,7 +691,8 @@ export function createOpenClawTools( onBeforeYield: requesterSessionKey && requesterTurnRunId ? async () => { - const { markRequesterTurnYielded } = await import("./subagent-registry.js"); + const { markRequesterTurnYielded } = + await import("./subagents/registry/subagent-registry.js"); markRequesterTurnYielded({ requesterSessionKey, requesterTurnRunId }); } : undefined, diff --git a/src/agents/requester-tool-policy.ts b/src/agents/requester-tool-policy.ts index b35a9bee81a7..d8c7b4c78381 100644 --- a/src/agents/requester-tool-policy.ts +++ b/src/agents/requester-tool-policy.ts @@ -16,14 +16,14 @@ import { resolveSenderToolPolicy } from "./sender-tool-policy.js"; import { isTrustedSubagentCompletionHandoffForRun, type TrustedSubagentCompletionHandoff, -} from "./subagent-announce-handoff.js"; +} from "./subagents/announce/subagent-announce-handoff.js"; +import { resolveRequesterStoreKey } from "./subagents/announce/subagent-requester-store-key.js"; import { isSubagentEnvelopeSession, resolvePersistedSubagentToolPolicyEnvelope, resolveSubagentCapabilityStore, type SessionCapabilityStore, -} from "./subagent-capabilities.js"; -import { resolveRequesterStoreKey } from "./subagent-requester-store-key.js"; +} from "./subagents/spawn/subagent-capabilities.js"; const MAX_DELEGATION_LINEAGE_DEPTH = 32; diff --git a/src/agents/restart-abort-code-propagation.test.ts b/src/agents/restart-abort-code-propagation.test.ts index 4ee548170c43..252175250a3f 100644 --- a/src/agents/restart-abort-code-propagation.test.ts +++ b/src/agents/restart-abort-code-propagation.test.ts @@ -1,6 +1,6 @@ import { failTransportStream, finalizeTransportStream } from "@openclaw/ai/transports"; import { describe, expect, it, vi } from "vitest"; -import { resolveMainSessionResumePolicy } from "./main-session-restart-recovery-resume-policy.js"; +import { resolveMainSessionResumePolicy } from "./main-session-recovery/main-session-restart-recovery-resume-policy.js"; import { createAssistantOutput, makeCompletionsModel, diff --git a/src/agents/sessions-spawn-hooks.test.ts b/src/agents/sessions-spawn-hooks.test.ts index e746f4fc8370..67f85d6a00a2 100644 --- a/src/agents/sessions-spawn-hooks.test.ts +++ b/src/agents/sessions-spawn-hooks.test.ts @@ -56,7 +56,7 @@ const bindingMocks = vi.hoisted(() => ({ listBySession: vi.fn(() => []), })); -let resetSubagentRegistryForTests: typeof import("./subagent-registry.test-helpers.js").resetSubagentRegistryForTests; +let resetSubagentRegistryForTests: typeof import("./subagents/registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; let spawnSubagentDirect: typeof import("./subagents/spawn/subagent-spawn.js").spawnSubagentDirect; function getGatewayRequests(): GatewayRequest[] { diff --git a/src/agents/spawn-pipeline.ts b/src/agents/spawn-pipeline.ts index 25febdf822e5..a8c481810b05 100644 --- a/src/agents/spawn-pipeline.ts +++ b/src/agents/spawn-pipeline.ts @@ -1,5 +1,5 @@ import type { SubagentLifecycleHookRunner } from "../plugins/hooks.js"; -import { registerSubagentRun } from "./subagent-registry.js"; +import { registerSubagentRun } from "./subagents/registry/subagent-registry.js"; type SpawnPipelinePhase = "initialize" | "dispatch" | "register"; diff --git a/src/agents/spawn-plan.ts b/src/agents/spawn-plan.ts index 50cc44fff55c..6a5afc931544 100644 --- a/src/agents/spawn-plan.ts +++ b/src/agents/spawn-plan.ts @@ -20,10 +20,10 @@ import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { getSessionBindingService } from "../infra/outbound/session-binding-service.js"; import { resolveAgentConfig } from "./agent-scope.js"; import { resolveChildAdmission, type ChildAdmissionCap } from "./child-admission.js"; -import { resolveSubagentCapabilities } from "./subagent-capabilities.js"; -import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; -import { countActiveRunsForSession } from "./subagent-registry.js"; -import { resolveSubagentTargetPolicy } from "./subagent-target-policy.js"; +import { countActiveRunsForSession } from "./subagents/registry/subagent-registry.js"; +import { resolveSubagentCapabilities } from "./subagents/spawn/subagent-capabilities.js"; +import { getSubagentDepthFromSessionStore } from "./subagents/spawn/subagent-depth.js"; +import { resolveSubagentTargetPolicy } from "./subagents/spawn/subagent-target-policy.js"; type SpawnMode = "run" | "session"; type SpawnBackendKind = "subagent" | "acp"; diff --git a/src/agents/subagent-announce-delivery.runtime.ts b/src/agents/subagent-announce-delivery.runtime.ts deleted file mode 100644 index a487c43d657a..000000000000 --- a/src/agents/subagent-announce-delivery.runtime.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Runtime dependency barrel for subagent announcement delivery. - * - * Tests mock this module to isolate delivery logic from gateway, outbound - * message routing, queue settings, hooks, and embedded-run state. - */ -export { getRuntimeConfig } from "../config/config.js"; -export { resolveAgentIdFromSessionKey, resolveStorePath } from "../config/sessions.js"; -export { loadSessionEntryReadOnly as loadSessionEntry } from "../config/sessions/session-accessor.js"; -export { callGateway } from "../gateway/call.js"; -export { dispatchGatewayMethodInProcess } from "../gateway/server-plugins.js"; -export { resolveQueueSettings } from "../auto-reply/reply/queue.js"; -export { resolveExternalBestEffortDeliveryTarget } from "../infra/outbound/best-effort-delivery.js"; -export { sendMessage } from "../infra/outbound/message.js"; -export { createBoundDeliveryRouter } from "../infra/outbound/bound-delivery-router.js"; -export { resolveConversationIdFromTargets } from "../infra/outbound/conversation-id.js"; -export { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; -export { - formatEmbeddedAgentQueueFailureSummary, - isEmbeddedAgentRunActive, - isEmbeddedRunAbandoned, - queueEmbeddedAgentMessageWithOutcomeAsync, - resolveActiveEmbeddedRunSessionId, -} from "./embedded-agent-runner/runs.js"; diff --git a/src/agents/subagent-control.runtime.ts b/src/agents/subagent-control.runtime.ts deleted file mode 100644 index 696d94496dc9..000000000000 --- a/src/agents/subagent-control.runtime.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Runtime seams used by subagent control for queue and embedded-run cancellation. - */ -export { clearSessionQueues } from "../auto-reply/reply/queue.js"; -export { abortEmbeddedAgentRun, isEmbeddedAgentRunActive } from "./embedded-agent-runner/runs.js"; diff --git a/src/agents/subagent-orphan-recovery.restart-integration.test.ts b/src/agents/subagent-orphan-recovery.restart-integration.test.ts index d634c813e95f..a5d9d230e4cc 100644 --- a/src/agents/subagent-orphan-recovery.restart-integration.test.ts +++ b/src/agents/subagent-orphan-recovery.restart-integration.test.ts @@ -23,15 +23,19 @@ import { } from "../tasks/task-runtime.test-helpers.js"; import { captureEnv } from "../test-utils/env.js"; import { cleanupSessionStateForTest } from "../test-utils/session-state-cleanup.js"; -import { subagentRuns } from "./subagent-registry-memory.js"; -import { persistSubagentRunsToDiskOrThrow } from "./subagent-registry-state.js"; +import { + createSubagentRunRecord, + type SubagentRunRecordOverrides, +} from "./subagent-test-fixtures.test-helpers.js"; +import { subagentRuns } from "./subagents/registry/subagent-registry-memory.js"; +import { persistSubagentRunsToDiskOrThrow } from "./subagents/registry/subagent-registry-state.js"; import { createCanonicalSubagentRunFixture, createSubagentRegistryTestDeps, readSubagentSessionStore, writeSubagentSessionEntry, -} from "./subagent-registry.persistence.test-support.js"; -import { loadSubagentRegistryFromSqlite } from "./subagent-registry.store.sqlite.js"; +} from "./subagents/registry/subagent-registry.persistence.test-support.js"; +import { loadSubagentRegistryFromSqlite } from "./subagents/registry/subagent-registry.store.sqlite.js"; import { addSubagentRunForTests, getSubagentRunByChildSessionKey, @@ -39,12 +43,8 @@ import { listSubagentRunsForRequester, resetSubagentRegistryForTests, testing, -} from "./subagent-registry.test-helpers.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { - createSubagentRunRecord, - type SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; +} from "./subagents/registry/subagent-registry.test-helpers.js"; +import type { SubagentRunRecord } from "./subagents/registry/subagent-registry.types.js"; function consumeRecoveryAdmission(payload: Record): SessionWorkAdmissionLease { const sessionKey = String(payload.sessionKey); diff --git a/src/agents/subagent-registry.runtime.ts b/src/agents/subagent-registry.runtime.ts deleted file mode 100644 index 1c376ed93145..000000000000 --- a/src/agents/subagent-registry.runtime.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Runtime seams used by subagent registry code for plugin/context-engine initialization. - */ -export { ensureContextEnginesInitialized } from "../context-engine/init.js"; -export { resolveContextEngine } from "../context-engine/registry.js"; diff --git a/src/agents/subagent-test-fixtures.test-helpers.ts b/src/agents/subagent-test-fixtures.test-helpers.ts index d9a8f41ee05d..0a430d361824 100644 --- a/src/agents/subagent-test-fixtures.test-helpers.ts +++ b/src/agents/subagent-test-fixtures.test-helpers.ts @@ -4,8 +4,8 @@ import type { SessionOrigin } from "../config/sessions/types.js"; import { normalizeLegacySessionEntryDelivery } from "../infra/state-migrations.legacy-session-store.js"; import type { DeliveryContext } from "../utils/delivery-context.types.js"; import type { AgentInternalEvent } from "./internal-events.js"; -import type { RegisterSubagentRunParams } from "./subagent-registry-run-manager.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; +import type { RegisterSubagentRunParams } from "./subagents/registry/subagent-registry-run-manager.js"; +import type { SubagentRunRecord } from "./subagents/registry/subagent-registry.types.js"; type GatewayRequest = { method?: string }; type GatewayResponse = diff --git a/src/agents/subagent-announce-capture.ts b/src/agents/subagents/announce/subagent-announce-capture.ts similarity index 100% rename from src/agents/subagent-announce-capture.ts rename to src/agents/subagents/announce/subagent-announce-capture.ts diff --git a/src/agents/subagents/announce/subagent-announce-delivery.runtime.ts b/src/agents/subagents/announce/subagent-announce-delivery.runtime.ts new file mode 100644 index 000000000000..2af44f08de6c --- /dev/null +++ b/src/agents/subagents/announce/subagent-announce-delivery.runtime.ts @@ -0,0 +1,24 @@ +/** + * Runtime dependency barrel for subagent announcement delivery. + * + * Tests mock this module to isolate delivery logic from gateway, outbound + * message routing, queue settings, hooks, and embedded-run state. + */ +export { getRuntimeConfig } from "../../../config/config.js"; +export { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js"; +export { loadSessionEntryReadOnly as loadSessionEntry } from "../../../config/sessions/session-accessor.js"; +export { callGateway } from "../../../gateway/call.js"; +export { dispatchGatewayMethodInProcess } from "../../../gateway/server-plugins.js"; +export { resolveQueueSettings } from "../../../auto-reply/reply/queue.js"; +export { resolveExternalBestEffortDeliveryTarget } from "../../../infra/outbound/best-effort-delivery.js"; +export { sendMessage } from "../../../infra/outbound/message.js"; +export { createBoundDeliveryRouter } from "../../../infra/outbound/bound-delivery-router.js"; +export { resolveConversationIdFromTargets } from "../../../infra/outbound/conversation-id.js"; +export { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js"; +export { + formatEmbeddedAgentQueueFailureSummary, + isEmbeddedAgentRunActive, + isEmbeddedRunAbandoned, + queueEmbeddedAgentMessageWithOutcomeAsync, + resolveActiveEmbeddedRunSessionId, +} from "../../embedded-agent-runner/runs.js"; diff --git a/src/agents/subagent-announce-delivery.test-support.ts b/src/agents/subagents/announce/subagent-announce-delivery.test-support.ts similarity index 92% rename from src/agents/subagent-announce-delivery.test-support.ts rename to src/agents/subagents/announce/subagent-announce-delivery.test-support.ts index 76c7ddbb505c..cba2b8a0b2c8 100644 --- a/src/agents/subagent-announce-delivery.test-support.ts +++ b/src/agents/subagents/announce/subagent-announce-delivery.test-support.ts @@ -1,9 +1,9 @@ export * from "./subagent-announce-delivery.js"; type QueueMessageOptions = - import("./embedded-agent-runner/runs.js").EmbeddedAgentQueueMessageOptions; + import("../../embedded-agent-runner/runs.js").EmbeddedAgentQueueMessageOptions; type QueueMessageOutcome = - import("./embedded-agent-runner/runs.js").EmbeddedAgentQueueMessageOutcome; + import("../../embedded-agent-runner/runs.js").EmbeddedAgentQueueMessageOutcome; type DeliveryDeps = { callGateway: typeof import("./subagent-announce-delivery.runtime.js").callGateway; dispatchGatewayMethodInProcess: typeof import("./subagent-announce-delivery.runtime.js").dispatchGatewayMethodInProcess; diff --git a/src/agents/subagent-announce-delivery.test.ts b/src/agents/subagents/announce/subagent-announce-delivery.test.ts similarity index 99% rename from src/agents/subagent-announce-delivery.test.ts rename to src/agents/subagents/announce/subagent-announce-delivery.test.ts index db3afd895007..5204d462d9ea 100644 --- a/src/agents/subagent-announce-delivery.test.ts +++ b/src/agents/subagents/announce/subagent-announce-delivery.test.ts @@ -1,24 +1,36 @@ // Subagent announce delivery tests cover the last-mile routing used when child // runs report progress or completion back to the requester session. import { afterEach, describe, expect, it, vi } from "vitest"; -import type { SessionEntry } from "../config/sessions.js"; -import { OutboundDeliveryError } from "../infra/outbound/deliver-types.js"; +import type { SessionEntry } from "../../../config/sessions.js"; +import { OutboundDeliveryError } from "../../../infra/outbound/deliver-types.js"; import { testing as sessionBindingServiceTesting, registerSessionBindingAdapter, -} from "../infra/outbound/session-binding-service.js"; -import { normalizeLegacySessionEntryDelivery } from "../infra/state-migrations.legacy-session-store.js"; -import { setActivePluginRegistry } from "../plugins/runtime.js"; -import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js"; +} from "../../../infra/outbound/session-binding-service.js"; +import { normalizeLegacySessionEntryDelivery } from "../../../infra/state-migrations.legacy-session-store.js"; +import { setActivePluginRegistry } from "../../../plugins/runtime.js"; +import { + createChannelTestPluginBase, + createTestRegistry, +} from "../../../test-utils/channel-plugins.js"; import type { EmbeddedAgentQueueMessageOptions, EmbeddedAgentQueueMessageOutcome, -} from "./embedded-agent-runner/runs.js"; -import type { AgentInternalEvent } from "./internal-events.js"; +} from "../../embedded-agent-runner/runs.js"; +import type { AgentInternalEvent } from "../../internal-events.js"; import { INTERNAL_RUNTIME_CONTEXT_BEGIN, INTERNAL_RUNTIME_CONTEXT_END, -} from "./internal-runtime-context.js"; +} from "../../internal-runtime-context.js"; +import { + createTaskCompletionEvent, + expectDeliveryPath, + expectRecordFields, + imageCompletionEvents, + mockCallArg, + musicCompletionEvents, + taskCompletionEvents, +} from "../../subagent-test-fixtures.test-helpers.js"; import { callGateway as runtimeCallGateway, dispatchGatewayMethodInProcess as runtimeDispatchGatewayMethodInProcess, @@ -29,15 +41,6 @@ import { resolveAnnounceOrigin, resolveSubagentCompletionOrigin, } from "./subagent-announce-origin.js"; -import { - createTaskCompletionEvent, - expectDeliveryPath, - expectRecordFields, - imageCompletionEvents, - mockCallArg, - musicCompletionEvents, - taskCompletionEvents, -} from "./subagent-test-fixtures.test-helpers.js"; const sessionDeliveryQueueMocks = vi.hoisted(() => ({ enqueueClaimedSessionDelivery: vi.fn((_payload: unknown, _leaseMs: number) => ({ @@ -49,20 +52,20 @@ const sessionDeliveryQueueMocks = vi.hoisted(() => ({ scheduleSessionDelivery: vi.fn(async () => true), })); -vi.mock("./subagent-completion-delivery.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../completion/subagent-completion-delivery.js", async (importOriginal) => ({ + ...(await importOriginal()), admitCorrelatedSubagentSessionDelivery: (params: { payload: Record }) => sessionDeliveryQueueMocks.enqueueClaimedSessionDelivery(params.payload, 125_000), })); -vi.mock("../infra/session-delivery-queue.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../../../infra/session-delivery-queue.js", async (importOriginal) => ({ + ...(await importOriginal()), enqueueClaimedSessionDelivery: sessionDeliveryQueueMocks.enqueueClaimedSessionDelivery, releaseSessionDeliveryClaim: sessionDeliveryQueueMocks.releaseSessionDeliveryClaim, })); -vi.mock("../infra/session-delivery-queue-runtime.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../../../infra/session-delivery-queue-runtime.js", async (importOriginal) => ({ + ...(await importOriginal()), scheduleSessionDelivery: sessionDeliveryQueueMocks.scheduleSessionDelivery, })); diff --git a/src/agents/subagent-announce-delivery.ts b/src/agents/subagents/announce/subagent-announce-delivery.ts similarity index 96% rename from src/agents/subagent-announce-delivery.ts rename to src/agents/subagents/announce/subagent-announce-delivery.ts index 06449657c71c..449ececf2542 100644 --- a/src/agents/subagent-announce-delivery.ts +++ b/src/agents/subagents/announce/subagent-announce-delivery.ts @@ -6,34 +6,34 @@ import { clampTimerTimeoutMs } from "@openclaw/normalization-core/number-coercion"; import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce"; import { normalizeUniqueTrimmedStringList } from "@openclaw/normalization-core/string-normalization"; -import { completionRequiresMessageToolDelivery } from "../auto-reply/reply/completion-delivery-policy.js"; -import { sanitizePendingFinalDeliveryText } from "../auto-reply/reply/pending-final-delivery.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { isFastTestRuntimeEnv } from "../infra/env.js"; -import { isOutboundDeliveryError } from "../infra/outbound/deliver-types.js"; -import { sourceDeliveryTargetsMatch } from "../infra/outbound/source-delivery-plan.js"; -import { scheduleSessionDelivery } from "../infra/session-delivery-queue-runtime.js"; +import { completionRequiresMessageToolDelivery } from "../../../auto-reply/reply/completion-delivery-policy.js"; +import { sanitizePendingFinalDeliveryText } from "../../../auto-reply/reply/pending-final-delivery.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { isFastTestRuntimeEnv } from "../../../infra/env.js"; +import { isOutboundDeliveryError } from "../../../infra/outbound/deliver-types.js"; +import { sourceDeliveryTargetsMatch } from "../../../infra/outbound/source-delivery-plan.js"; +import { scheduleSessionDelivery } from "../../../infra/session-delivery-queue-runtime.js"; import { enqueueClaimedSessionDelivery, releaseSessionDeliveryClaim, -} from "../infra/session-delivery-queue.js"; -import { stringifyRouteThreadId } from "../plugin-sdk/channel-route.js"; -import { defaultRuntime } from "../runtime.js"; +} from "../../../infra/session-delivery-queue.js"; +import { stringifyRouteThreadId } from "../../../plugin-sdk/channel-route.js"; +import { defaultRuntime } from "../../../runtime.js"; import { isAgentMediatedCompletionSourceTool, shouldPreserveUserFacingSessionStateForInputProvenance, -} from "../sessions/input-provenance.js"; -import { deriveSessionChatTypeFromKey } from "../sessions/session-chat-type-shared.js"; -import { isCronRunSessionKey, isCronSessionKey } from "../sessions/session-key-utils.js"; -import { isNonTerminalAgentRunStatus } from "../shared/agent-run-status.js"; -import { sessionDeliveryChannel } from "../utils/delivery-context.shared.js"; +} from "../../../sessions/input-provenance.js"; +import { deriveSessionChatTypeFromKey } from "../../../sessions/session-chat-type-shared.js"; +import { isCronRunSessionKey, isCronSessionKey } from "../../../sessions/session-key-utils.js"; +import { isNonTerminalAgentRunStatus } from "../../../shared/agent-run-status.js"; +import { sessionDeliveryChannel } from "../../../utils/delivery-context.shared.js"; import { INTERNAL_MESSAGE_CHANNEL, isGatewayMessageChannel, normalizeMessageChannel, -} from "../utils/message-channel.js"; -import { sanitizeAgentRunTerminalReplyText } from "./agent-run-terminal-reply.js"; -import { resolveDefaultAgentId } from "./agent-scope-config.js"; +} from "../../../utils/message-channel.js"; +import { sanitizeAgentRunTerminalReplyText } from "../../agent-run-terminal-reply.js"; +import { resolveDefaultAgentId } from "../../agent-scope-config.js"; import { getAgentCommandDeliveryFailure, getGatewayAgentResult, @@ -43,20 +43,25 @@ import { hasPayloadOutcomeSendEvidence, hasUnaccountedMessagingToolAggregateEvidence, resolveExplicitFinalSourceReplyDeliveryEvidence, -} from "./embedded-agent-runner/delivery-evidence.js"; +} from "../../embedded-agent-runner/delivery-evidence.js"; import { hasIntentionalSilentAgentPayload, hasVisibleAgentPayload, -} from "./embedded-agent-runner/message-visibility.js"; -import type { EmbeddedAgentQueueMessageOptions } from "./embedded-agent-runner/run-state.js"; -import type { EmbeddedAgentQueueMessageOutcome } from "./embedded-agent-runner/runs.js"; -import { isFailoverError } from "./failover-error.js"; -import { mediaUrlsFromGeneratedAttachments } from "./generated-attachments.js"; +} from "../../embedded-agent-runner/message-visibility.js"; +import type { EmbeddedAgentQueueMessageOptions } from "../../embedded-agent-runner/run-state.js"; +import type { EmbeddedAgentQueueMessageOutcome } from "../../embedded-agent-runner/runs.js"; +import { isFailoverError } from "../../failover-error.js"; +import { mediaUrlsFromGeneratedAttachments } from "../../generated-attachments.js"; import { AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION, hasGeneratedMediaCompletionEvent, -} from "./internal-event-contract.js"; -import { formatAgentInternalEventsForPrompt, type AgentInternalEvent } from "./internal-events.js"; +} from "../../internal-event-contract.js"; +import { + formatAgentInternalEventsForPrompt, + type AgentInternalEvent, +} from "../../internal-events.js"; +import { admitCorrelatedSubagentSessionDelivery } from "../completion/subagent-completion-delivery.js"; +import { getSubagentDepthFromSessionStore } from "../spawn/subagent-depth.js"; import { callGateway, dispatchGatewayMethodInProcess, @@ -84,8 +89,6 @@ import { resolveGeneratedMediaSessionDeliveryRoute, type DeliveryContext, } from "./subagent-announce-origin.js"; -import { admitCorrelatedSubagentSessionDelivery } from "./subagent-completion-delivery.js"; -import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; import { resolveRequesterStoreKey } from "./subagent-requester-store-key.js"; const DEFAULT_SUBAGENT_ANNOUNCE_TIMEOUT_MS = 120_000; diff --git a/src/agents/subagent-announce-descendant-wake.ts b/src/agents/subagents/announce/subagent-announce-descendant-wake.ts similarity index 91% rename from src/agents/subagent-announce-descendant-wake.ts rename to src/agents/subagents/announce/subagent-announce-descendant-wake.ts index 62e30eee759e..1cfb4fcc4a7e 100644 --- a/src/agents/subagent-announce-descendant-wake.ts +++ b/src/agents/subagents/announce/subagent-announce-descendant-wake.ts @@ -1,9 +1,10 @@ // Descendant-settle wake replaces an ended nested orchestrator run while // preserving lifecycle ownership. import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; -import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js"; -import { buildAnnounceIdempotencyKey } from "./announce-idempotency.js"; +import { getAgentEventLifecycleGeneration } from "../../../infra/agent-events.js"; +import { INTERNAL_MESSAGE_CHANNEL } from "../../../utils/message-channel.js"; +import { buildAnnounceIdempotencyKey } from "../../announce-idempotency.js"; +import { terminateAcceptedCollectorRun } from "../spawn/subagent-spawn-cleanup.js"; import { loadSessionEntryByKey, runAnnounceDeliveryWithRetry, @@ -14,13 +15,12 @@ import type { dispatchGatewayMethodInProcess, getRuntimeConfig, } from "./subagent-announce.runtime.js"; -import { terminateAcceptedCollectorRun } from "./subagents/spawn/subagent-spawn-cleanup.js"; type DescendantWakeDeps = { callGateway: typeof callGateway; dispatchGatewayMethodInProcess: typeof dispatchGatewayMethodInProcess; getRuntimeConfig: typeof getRuntimeConfig; - replaceSubagentRunAfterSteer: typeof import("./subagent-registry-runtime.js").replaceSubagentRunAfterSteer; + replaceSubagentRunAfterSteer: typeof import("../registry/subagent-registry-runtime.js").replaceSubagentRunAfterSteer; }; type UsableSessionEntryGuard = (entry: unknown) => entry is Record; diff --git a/src/agents/subagent-announce-dispatch.test.ts b/src/agents/subagents/announce/subagent-announce-dispatch.test.ts similarity index 100% rename from src/agents/subagent-announce-dispatch.test.ts rename to src/agents/subagents/announce/subagent-announce-dispatch.test.ts diff --git a/src/agents/subagent-announce-dispatch.ts b/src/agents/subagents/announce/subagent-announce-dispatch.ts similarity index 100% rename from src/agents/subagent-announce-dispatch.ts rename to src/agents/subagents/announce/subagent-announce-dispatch.ts diff --git a/src/agents/subagent-announce-handoff.test.ts b/src/agents/subagents/announce/subagent-announce-handoff.test.ts similarity index 95% rename from src/agents/subagent-announce-handoff.test.ts rename to src/agents/subagents/announce/subagent-announce-handoff.test.ts index e5fc69295a43..1f023df68731 100644 --- a/src/agents/subagent-announce-handoff.test.ts +++ b/src/agents/subagents/announce/subagent-announce-handoff.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION } from "./internal-event-contract.js"; -import type { AgentInternalEvent } from "./internal-events.js"; +import { AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION } from "../../internal-event-contract.js"; +import type { AgentInternalEvent } from "../../internal-events.js"; import { isSubagentAnnounceCompletionHandoff, isTrustedSubagentCompletionHandoffForRun, diff --git a/src/agents/subagent-announce-handoff.ts b/src/agents/subagents/announce/subagent-announce-handoff.ts similarity index 92% rename from src/agents/subagent-announce-handoff.ts rename to src/agents/subagents/announce/subagent-announce-handoff.ts index ec8e5905811a..ef259ddde1fa 100644 --- a/src/agents/subagent-announce-handoff.ts +++ b/src/agents/subagents/announce/subagent-announce-handoff.ts @@ -1,6 +1,6 @@ -import type { InputProvenance } from "../sessions/input-provenance.js"; -import { AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION } from "./internal-event-contract.js"; -import type { AgentInternalEvent } from "./internal-events.js"; +import type { InputProvenance } from "../../../sessions/input-provenance.js"; +import { AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION } from "../../internal-event-contract.js"; +import type { AgentInternalEvent } from "../../internal-events.js"; export type TrustedSubagentCompletionHandoff = { kind: "subagent-completion"; diff --git a/src/agents/subagent-announce-origin.ts b/src/agents/subagents/announce/subagent-announce-origin.ts similarity index 90% rename from src/agents/subagent-announce-origin.ts rename to src/agents/subagents/announce/subagent-announce-origin.ts index b363b48d329b..9c01ecfefbf1 100644 --- a/src/agents/subagent-announce-origin.ts +++ b/src/agents/subagents/announce/subagent-announce-origin.ts @@ -7,40 +7,43 @@ import { normalizeOptionalLowercaseString, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import { getLoadedChannelPluginForRead } from "../channels/plugins/registry-loaded.js"; -import type { ChannelId } from "../channels/plugins/types.public.js"; -import { routeFromConversationRef, routeToDeliveryFields } from "../channels/route-projection.js"; -import type { SessionEntry } from "../config/sessions/types.js"; +import { getLoadedChannelPluginForRead } from "../../../channels/plugins/registry-loaded.js"; +import type { ChannelId } from "../../../channels/plugins/types.public.js"; +import { + routeFromConversationRef, + routeToDeliveryFields, +} from "../../../channels/route-projection.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; import { stripTargetKindPrefix, stripTargetProviderPrefix, stripTargetTopicSuffix, -} from "../infra/outbound/channel-target-prefix.js"; -import type { ConversationRef } from "../infra/outbound/session-binding-service.js"; -import type { SessionDeliveryRoute } from "../infra/session-delivery-queue.js"; -import { stringifyRouteThreadId } from "../plugin-sdk/channel-route.js"; -import { normalizeAccountId } from "../routing/session-key.js"; -import { deriveSessionChatTypeFromKey } from "../sessions/session-chat-type-shared.js"; +} from "../../../infra/outbound/channel-target-prefix.js"; +import type { ConversationRef } from "../../../infra/outbound/session-binding-service.js"; +import type { SessionDeliveryRoute } from "../../../infra/session-delivery-queue.js"; +import { stringifyRouteThreadId } from "../../../plugin-sdk/channel-route.js"; +import { normalizeAccountId } from "../../../routing/session-key.js"; +import { deriveSessionChatTypeFromKey } from "../../../sessions/session-chat-type-shared.js"; import { deliveryContextFromSession, mergeDeliveryContext, normalizeDeliveryContext, -} from "../utils/delivery-context.shared.js"; -import type { DeliveryContext } from "../utils/delivery-context.types.js"; +} from "../../../utils/delivery-context.shared.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; import { INTERNAL_MESSAGE_CHANNEL, isDeliverableMessageChannel, isGatewayMessageChannel, isInternalMessageChannel, normalizeMessageChannel, -} from "../utils/message-channel.js"; +} from "../../../utils/message-channel.js"; +import type { SpawnSubagentMode } from "../spawn/subagent-spawn.types.js"; import { createBoundDeliveryRouter, getGlobalHookRunner, resolveConversationIdFromTargets, } from "./subagent-announce-delivery.runtime.js"; -import type { SpawnSubagentMode } from "./subagents/spawn/subagent-spawn.types.js"; -export type { DeliveryContext } from "../utils/delivery-context.types.js"; +export type { DeliveryContext } from "../../../utils/delivery-context.types.js"; function normalizeAnnounceRouteTarget(context?: DeliveryContext): string | undefined { const rawTo = normalizeOptionalString(context?.to); diff --git a/src/agents/subagent-announce-output.test-support.ts b/src/agents/subagents/announce/subagent-announce-output.test-support.ts similarity index 100% rename from src/agents/subagent-announce-output.test-support.ts rename to src/agents/subagents/announce/subagent-announce-output.test-support.ts diff --git a/src/agents/subagent-announce-output.test.ts b/src/agents/subagents/announce/subagent-announce-output.test.ts similarity index 99% rename from src/agents/subagent-announce-output.test.ts rename to src/agents/subagents/announce/subagent-announce-output.test.ts index ba5f0dbee2c4..54abec685139 100644 --- a/src/agents/subagent-announce-output.test.ts +++ b/src/agents/subagents/announce/subagent-announce-output.test.ts @@ -10,7 +10,7 @@ import { readSubagentOutput, } from "./subagent-announce-output.test-support.js"; -type CallGateway = typeof import("../gateway/call.js").callGateway; +type CallGateway = typeof import("../../../gateway/call.js").callGateway; type GetRuntimeConfig = typeof import("./subagent-announce.runtime.js").getRuntimeConfig; type ReadSessionEntry = typeof import("./subagent-announce.runtime.js").readSessionEntry; type ReadSessionMessagesAsync = diff --git a/src/agents/subagent-announce-output.ts b/src/agents/subagents/announce/subagent-announce-output.ts similarity index 96% rename from src/agents/subagent-announce-output.ts rename to src/agents/subagents/announce/subagent-announce-output.ts index c54cdd459ad7..49cced52c7f0 100644 --- a/src/agents/subagent-announce-output.ts +++ b/src/agents/subagents/announce/subagent-announce-output.ts @@ -5,13 +5,19 @@ */ import { asFiniteNumber } from "@openclaw/normalization-core/number-coercion"; import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; -import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; -import type { SessionTranscriptRuntimeTarget } from "../config/sessions/session-accessor.js"; -import { resolveFreshSessionTotalTokens } from "../config/sessions/types.js"; -import { isFastTestRuntimeEnv } from "../infra/env.js"; -import { formatDurationCompact } from "../infra/format-time/format-duration.js"; -import { buildAgentRunTerminalOutcomeFromWaitResult } from "./agent-run-terminal-outcome.js"; -import { wrapPromptDataBlock } from "./sanitize-for-prompt.js"; +import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js"; +import type { SessionTranscriptRuntimeTarget } from "../../../config/sessions/session-accessor.js"; +import { resolveFreshSessionTotalTokens } from "../../../config/sessions/types.js"; +import { isFastTestRuntimeEnv } from "../../../infra/env.js"; +import { formatDurationCompact } from "../../../infra/format-time/format-duration.js"; +import { buildAgentRunTerminalOutcomeFromWaitResult } from "../../agent-run-terminal-outcome.js"; +import { wrapPromptDataBlock } from "../../sanitize-for-prompt.js"; +import { extractAssistantText, sanitizeTextContent } from "../../tools/chat-history-text.js"; +import { + isAnnounceSkip, + selectDeliverableSessionsReply, +} from "../../tools/sessions-send-tokens.js"; +import { compareSubagentRunGeneration } from "../registry/subagent-run-generation.js"; import { captureSubagentCompletionReplyUsing, readLatestSubagentOutputWithRetryUsing, @@ -24,10 +30,7 @@ import { resolveAgentIdFromSessionKey, resolveStorePath, } from "./subagent-announce.runtime.js"; -import { compareSubagentRunGeneration } from "./subagent-run-generation.js"; import { assistantCallsSessionsYield, isSessionsYieldToolResult } from "./subagent-yield-output.js"; -import { extractAssistantText, sanitizeTextContent } from "./tools/chat-history-text.js"; -import { isAnnounceSkip, selectDeliverableSessionsReply } from "./tools/sessions-send-tokens.js"; const FAST_TEST_RETRY_INTERVAL_MS = 8; const MAX_CHILD_COMPLETION_RESULT_CHARS = 512; diff --git a/src/agents/subagent-announce.capture-completion-reply.test.ts b/src/agents/subagents/announce/subagent-announce.capture-completion-reply.test.ts similarity index 100% rename from src/agents/subagent-announce.capture-completion-reply.test.ts rename to src/agents/subagents/announce/subagent-announce.capture-completion-reply.test.ts diff --git a/src/agents/subagent-announce.format.e2e.test.ts b/src/agents/subagents/announce/subagent-announce.format.e2e.test.ts similarity index 99% rename from src/agents/subagent-announce.format.e2e.test.ts rename to src/agents/subagents/announce/subagent-announce.format.e2e.test.ts index fb9e8cce186f..31137775613c 100644 --- a/src/agents/subagent-announce.format.e2e.test.ts +++ b/src/agents/subagents/announce/subagent-announce.format.e2e.test.ts @@ -1,31 +1,34 @@ // Subagent announce format e2e tests exercise the full announce flow with // channel fixtures, session stores, hooks, and gateway calls wired together. import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; +import { SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js"; import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot, type OpenClawConfig, -} from "../config/config.js"; -import * as configSessions from "../config/sessions.js"; -import type { SessionEntry } from "../config/sessions/types.js"; -import * as gatewayCall from "../gateway/call.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; +} from "../../../config/config.js"; +import * as configSessions from "../../../config/sessions.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import * as gatewayCall from "../../../gateway/call.js"; +import { getAgentEventLifecycleGeneration } from "../../../infra/agent-events.js"; import { testing as sessionBindingServiceTesting, registerSessionBindingAdapter, -} from "../infra/outbound/session-binding-service.js"; -import { normalizeLegacySessionEntryDelivery } from "../infra/state-migrations.legacy-session-store.js"; -import * as hookRunnerGlobal from "../plugins/hook-runner-global.js"; -import type { HookRunner } from "../plugins/hooks.js"; -import { setActivePluginRegistry } from "../plugins/runtime.js"; -import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js"; +} from "../../../infra/outbound/session-binding-service.js"; +import { normalizeLegacySessionEntryDelivery } from "../../../infra/state-migrations.legacy-session-store.js"; +import * as hookRunnerGlobal from "../../../plugins/hook-runner-global.js"; +import type { HookRunner } from "../../../plugins/hooks.js"; +import { setActivePluginRegistry } from "../../../plugins/runtime.js"; +import { + createChannelTestPluginBase, + createTestRegistry, +} from "../../../test-utils/channel-plugins.js"; import { buildAnnounceIdFromChildRun, buildAnnounceIdempotencyKey, -} from "./announce-idempotency.js"; -import * as embeddedRuns from "./embedded-agent-runner/runs.js"; -import { FailoverError } from "./failover-error.js"; +} from "../../announce-idempotency.js"; +import * as embeddedRuns from "../../embedded-agent-runner/runs.js"; +import { FailoverError } from "../../failover-error.js"; import { testing as subagentAnnounceDeliveryTesting } from "./subagent-announce-delivery.test-support.js"; import { runSubagentAnnounceDispatch } from "./subagent-announce-dispatch.js"; import { testing as subagentAnnounceOutputTesting } from "./subagent-announce-output.test-support.js"; @@ -332,8 +335,8 @@ function loadSessionStoreFixture(): Record { }) as unknown as Record; } -vi.mock("./subagent-registry.js", () => subagentRegistryMock); -vi.mock("./subagent-registry-runtime.js", () => subagentRegistryMock); +vi.mock("../registry/subagent-registry.js", () => subagentRegistryMock); +vi.mock("../registry/subagent-registry-runtime.js", () => subagentRegistryMock); describe("subagent announce formatting", () => { let previousFastTestEnv: string | undefined; diff --git a/src/agents/subagent-announce.live.test.ts b/src/agents/subagents/announce/subagent-announce.live.test.ts similarity index 96% rename from src/agents/subagent-announce.live.test.ts rename to src/agents/subagents/announce/subagent-announce.live.test.ts index 73995bdc6651..d9667aa4492c 100644 --- a/src/agents/subagent-announce.live.test.ts +++ b/src/agents/subagents/announce/subagent-announce.live.test.ts @@ -4,25 +4,28 @@ import { randomBytes, randomUUID } from "node:crypto"; import fs from "node:fs/promises"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { clearRuntimeConfigSnapshot, type OpenClawConfig } from "../config/config.js"; -import { callGateway as realCallGateway } from "../gateway/call.js"; -import { GatewayClient } from "../gateway/client.js"; -import { dispatchGatewayMethodInProcess as realDispatchGatewayMethodInProcess } from "../gateway/server-plugins.js"; -import { startGatewayServer, type GatewayServer } from "../gateway/server.js"; -import { extractPayloadText } from "../gateway/test-helpers.agent-results.js"; -import { onAgentEvent, type AgentEventPayload } from "../infra/agent-events.js"; -import { isTruthyEnvValue } from "../infra/env.js"; -import { clearCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-state.js"; +import { clearRuntimeConfigSnapshot, type OpenClawConfig } from "../../../config/config.js"; +import { callGateway as realCallGateway } from "../../../gateway/call.js"; +import { GatewayClient } from "../../../gateway/client.js"; +import { dispatchGatewayMethodInProcess as realDispatchGatewayMethodInProcess } from "../../../gateway/server-plugins.js"; +import { startGatewayServer, type GatewayServer } from "../../../gateway/server.js"; +import { extractPayloadText } from "../../../gateway/test-helpers.agent-results.js"; +import { onAgentEvent, type AgentEventPayload } from "../../../infra/agent-events.js"; +import { isTruthyEnvValue } from "../../../infra/env.js"; +import { clearCurrentPluginMetadataSnapshot } from "../../../plugins/current-plugin-metadata-state.js"; import { createOpenClawTestState, type OpenClawTestState, -} from "../test-utils/openclaw-test-state.js"; -import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; -import { isLiveTestEnabled, readLiveTestConfig } from "./live-test-helpers.js"; +} from "../../../test-utils/openclaw-test-state.js"; +import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../../utils/message-channel.js"; +import { isLiveTestEnabled, readLiveTestConfig } from "../../live-test-helpers.js"; +import { + resolveSubagentController, + steerControlledSubagentRun, +} from "../registry/subagent-control.js"; +import { listSubagentRunsForRequester } from "../registry/subagent-registry.test-helpers.js"; import { testing as subagentAnnounceDeliveryTesting } from "./subagent-announce-delivery.test-support.js"; import { testing as subagentAnnounceTesting } from "./subagent-announce.js"; -import { resolveSubagentController, steerControlledSubagentRun } from "./subagent-control.js"; -import { listSubagentRunsForRequester } from "./subagent-registry.test-helpers.js"; const LIVE = isLiveTestEnabled() && isTruthyEnvValue(process.env.OPENCLAW_LIVE_SUBAGENT_E2E); const describeLive = LIVE ? describe : describe.skip; diff --git a/src/agents/subagent-announce.requester-settle-wake.test.ts b/src/agents/subagents/announce/subagent-announce.requester-settle-wake.test.ts similarity index 99% rename from src/agents/subagent-announce.requester-settle-wake.test.ts rename to src/agents/subagents/announce/subagent-announce.requester-settle-wake.test.ts index da008d52bd06..b1398b1654a7 100644 --- a/src/agents/subagent-announce.requester-settle-wake.test.ts +++ b/src/agents/subagents/announce/subagent-announce.requester-settle-wake.test.ts @@ -2,7 +2,7 @@ // drain gating, batch idempotency, and the guards that keep the wake out of // nested/cron/single-delivered paths. import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; const deliverSpy = vi.fn( async ( @@ -30,7 +30,7 @@ const { registryRuntimeMock } = vi.hoisted(() => ({ }, })); -vi.mock("./subagent-registry-runtime.js", () => registryRuntimeMock); +vi.mock("../registry/subagent-registry-runtime.js", () => registryRuntimeMock); vi.mock("./subagent-announce.runtime.js", () => ({ callGateway: vi.fn(async () => ({})), @@ -59,7 +59,7 @@ vi.mock("./subagent-announce-delivery.js", () => ({ params.requesterOrigin, })); -vi.mock("./subagent-depth.js", () => ({ +vi.mock("../spawn/subagent-depth.js", () => ({ getSubagentDepthFromSessionStore: (sessionKey: string) => sessionKey.split(":subagent:").length - 1, })); diff --git a/src/agents/subagent-announce.requester-settle-wake.ts b/src/agents/subagents/announce/subagent-announce.requester-settle-wake.ts similarity index 96% rename from src/agents/subagent-announce.requester-settle-wake.ts rename to src/agents/subagents/announce/subagent-announce.requester-settle-wake.ts index 531a82303c4c..e14cad92b1c8 100644 --- a/src/agents/subagent-announce.requester-settle-wake.ts +++ b/src/agents/subagents/announce/subagent-announce.requester-settle-wake.ts @@ -4,16 +4,22 @@ * Lifecycle owns the persisted outbox state on retained subagent run rows; * this module selects a drained wave and delivers its synthesized wake. */ -import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; -import { logWarn } from "../logger.js"; -import { isCronSessionKey } from "../sessions/session-key-utils.js"; -import { createLazyImportLoader } from "../shared/lazy-promise.js"; +import { SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js"; +import { logWarn } from "../../../logger.js"; +import { isCronSessionKey } from "../../../sessions/session-key-utils.js"; +import { createLazyImportLoader } from "../../../shared/lazy-promise.js"; import { type DeliveryContext, normalizeDeliveryContext, -} from "../utils/delivery-context.shared.js"; -import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js"; -import { buildAnnounceIdempotencyKey } from "./announce-idempotency.js"; +} from "../../../utils/delivery-context.shared.js"; +import { INTERNAL_MESSAGE_CHANNEL } from "../../../utils/message-channel.js"; +import { buildAnnounceIdempotencyKey } from "../../announce-idempotency.js"; +import type { + RequesterSettleWakeState, + SubagentRunRecord, +} from "../registry/subagent-registry.types.js"; +import { hasSubagentRunEnded } from "../registry/subagent-run-liveness.js"; +import { getSubagentDepthFromSessionStore } from "../spawn/subagent-depth.js"; import { deliverSubagentAnnouncement, loadRequesterSessionEntry, @@ -25,12 +31,9 @@ import { filterCurrentDirectChildCompletionRows, } from "./subagent-announce-output.js"; import { hasUsableSessionEntry } from "./subagent-announce.js"; -import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; -import type { RequesterSettleWakeState, SubagentRunRecord } from "./subagent-registry.types.js"; -import { hasSubagentRunEnded } from "./subagent-run-liveness.js"; const subagentRegistryRuntimeLoader = createLazyImportLoader( - () => import("./subagent-registry-runtime.js"), + () => import("../registry/subagent-registry-runtime.js"), ); function loadSubagentRegistryRuntime() { diff --git a/src/agents/subagent-announce.runtime.ts b/src/agents/subagents/announce/subagent-announce.runtime.ts similarity index 51% rename from src/agents/subagent-announce.runtime.ts rename to src/agents/subagents/announce/subagent-announce.runtime.ts index 732967a9b60d..e7d5aaca08b1 100644 --- a/src/agents/subagent-announce.runtime.ts +++ b/src/agents/subagents/announce/subagent-announce.runtime.ts @@ -4,17 +4,17 @@ * Keeping these imports behind one module lets tests replace gateway/session * IO without changing the announce logic itself. */ -export { getRuntimeConfig } from "../config/config.js"; -export { resolveAgentIdFromSessionKey, resolveStorePath } from "../config/sessions.js"; -import { loadSessionEntry } from "../config/sessions/session-accessor.js"; +export { getRuntimeConfig } from "../../../config/config.js"; +export { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js"; +import { loadSessionEntry } from "../../../config/sessions/session-accessor.js"; export function readSessionEntry(storePath: string, sessionKey: string) { return loadSessionEntry({ storePath, sessionKey }); } -export { callGateway } from "../gateway/call.js"; -export { readSessionMessagesAsync } from "../gateway/session-transcript-readers.js"; -export { dispatchGatewayMethodInProcess } from "../gateway/server-plugins.js"; +export { callGateway } from "../../../gateway/call.js"; +export { readSessionMessagesAsync } from "../../../gateway/session-transcript-readers.js"; +export { dispatchGatewayMethodInProcess } from "../../../gateway/server-plugins.js"; export { isEmbeddedAgentRunActive, waitForEmbeddedAgentRunEnd, -} from "./embedded-agent-runner/runs.js"; +} from "../../embedded-agent-runner/runs.js"; diff --git a/src/agents/subagent-announce.test-support.ts b/src/agents/subagents/announce/subagent-announce.test-support.ts similarity index 89% rename from src/agents/subagent-announce.test-support.ts rename to src/agents/subagents/announce/subagent-announce.test-support.ts index 37bf066434fc..631926325117 100644 --- a/src/agents/subagent-announce.test-support.ts +++ b/src/agents/subagents/announce/subagent-announce.test-support.ts @@ -2,11 +2,11 @@ * Test runtime factory for subagent announce delivery. It wires gateway, * session-store, queue, and hook behavior to caller-provided mocks. */ -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { callGateway } from "../gateway/call.js"; -import type { dispatchGatewayMethodInProcess } from "../gateway/server-plugins.js"; -import type { EmbeddedAgentQueueMessageOptions } from "./embedded-agent-runner/run-state.js"; -import type { EmbeddedAgentQueueMessageOutcome } from "./embedded-agent-runner/runs.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { callGateway } from "../../../gateway/call.js"; +import type { dispatchGatewayMethodInProcess } from "../../../gateway/server-plugins.js"; +import type { EmbeddedAgentQueueMessageOptions } from "../../embedded-agent-runner/run-state.js"; +import type { EmbeddedAgentQueueMessageOutcome } from "../../embedded-agent-runner/runs.js"; type DeliveryRuntimeMockOptions = { callGateway: (request: unknown) => Promise; diff --git a/src/agents/subagent-announce.test.ts b/src/agents/subagents/announce/subagent-announce.test.ts similarity index 98% rename from src/agents/subagent-announce.test.ts rename to src/agents/subagents/announce/subagent-announce.test.ts index 636f6e33ecee..9ddaeff0c724 100644 --- a/src/agents/subagent-announce.test.ts +++ b/src/agents/subagents/announce/subagent-announce.test.ts @@ -1,8 +1,8 @@ // Subagent announce flow tests cover the seam-level orchestration between wait // outcomes, requester lookup, delivery, and cleanup. import { beforeEach, describe, expect, it, vi } from "vitest"; -import { normalizeSessionDeliveryState } from "../utils/delivery-context.shared.js"; -import type { EmbeddedAgentQueueMessageOutcome } from "./embedded-agent-runner/runs.js"; +import { normalizeSessionDeliveryState } from "../../../utils/delivery-context.shared.js"; +import type { EmbeddedAgentQueueMessageOutcome } from "../../embedded-agent-runner/runs.js"; import { createSubagentAnnounceDeliveryRuntimeMock } from "./subagent-announce.test-support.js"; type AgentCallRequest = { method?: string; params?: Record }; @@ -39,7 +39,7 @@ const queueEmbeddedAgentMessageWithOutcomeMock = vi.fn( const waitForEmbeddedAgentRunEndMock = vi.fn( async (_sessionId: string, _timeoutMs?: number) => true, ); -let mockConfig: ReturnType<(typeof import("../config/config.js"))["getRuntimeConfig"]> = { +let mockConfig: ReturnType<(typeof import("../../../config/config.js"))["getRuntimeConfig"]> = { session: { mainKey: "main", scope: "per-sender", @@ -214,8 +214,8 @@ vi.mock("./subagent-announce-delivery.js", () => ({ runAnnounceDeliveryWithRetry: async (params: { run: () => Promise }) => await params.run(), })); -vi.mock("./subagent-registry-runtime.js", () => subagentRegistryRuntimeMock); -import { defaultRuntime } from "../runtime.js"; +vi.mock("../registry/subagent-registry-runtime.js", () => subagentRegistryRuntimeMock); +import { defaultRuntime } from "../../../runtime.js"; import { applySubagentWaitOutcome } from "./subagent-announce-output.js"; import { runSubagentAnnounceFlow } from "./subagent-announce.js"; diff --git a/src/agents/subagent-announce.timeout.test.ts b/src/agents/subagents/announce/subagent-announce.timeout.test.ts similarity index 98% rename from src/agents/subagent-announce.timeout.test.ts rename to src/agents/subagents/announce/subagent-announce.timeout.test.ts index 0ff0515ebad6..7992af48f0d4 100644 --- a/src/agents/subagent-announce.timeout.test.ts +++ b/src/agents/subagents/announce/subagent-announce.timeout.test.ts @@ -19,7 +19,7 @@ let callGatewayImpl: (request: GatewayCall) => Promise = async (request return {}; }; let sessionStore: Record> = {}; -let configOverride: ReturnType<(typeof import("../config/config.js"))["getRuntimeConfig"]> = { +let configOverride: ReturnType<(typeof import("../../../config/config.js"))["getRuntimeConfig"]> = { session: { mainKey: "main", scope: "per-sender", @@ -75,8 +75,8 @@ function createTimeoutHistoryWithNoReply() { ]; } -vi.mock("../gateway/call.js", createGatewayCallModuleMock); -vi.mock("./subagent-depth.js", createSubagentDepthModuleMock); +vi.mock("../../../gateway/call.js", createGatewayCallModuleMock); +vi.mock("../spawn/subagent-depth.js", createSubagentDepthModuleMock); vi.mock("./subagent-announce-delivery.runtime.js", () => createSubagentAnnounceDeliveryRuntimeMock({ callGateway: async (request: unknown) => { @@ -196,7 +196,7 @@ vi.mock("./subagent-announce.runtime.js", () => ({ waitForEmbeddedAgentRunEnd: (sessionId: string, timeoutMs?: number) => waitForEmbeddedAgentRunEndMock(sessionId, timeoutMs), })); -vi.mock("./subagent-registry-runtime.js", () => ({ +vi.mock("../registry/subagent-registry-runtime.js", () => ({ countActiveDescendantRuns: () => 0, countPendingDescendantRuns: () => pendingDescendantRuns, countPendingDescendantRunsExcludingRun: () => 0, diff --git a/src/agents/subagent-announce.ts b/src/agents/subagents/announce/subagent-announce.ts similarity index 95% rename from src/agents/subagent-announce.ts rename to src/agents/subagents/announce/subagent-announce.ts index 66c3c51e856d..f540ce26b4e6 100644 --- a/src/agents/subagent-announce.ts +++ b/src/agents/subagents/announce/subagent-announce.ts @@ -11,22 +11,29 @@ import { startsWithSilentToken, stripLeadingSilentToken, stripSilentToken, -} from "../auto-reply/tokens.js"; -import { logWarn } from "../logger.js"; -import { defaultRuntime } from "../runtime.js"; -import { isCronSessionKey } from "../sessions/session-key-utils.js"; -import { createLazyImportLoader } from "../shared/lazy-promise.js"; +} from "../../../auto-reply/tokens.js"; +import { logWarn } from "../../../logger.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { isCronSessionKey } from "../../../sessions/session-key-utils.js"; +import { createLazyImportLoader } from "../../../shared/lazy-promise.js"; import { type DeliveryContext, normalizeDeliveryContext, -} from "../utils/delivery-context.shared.js"; -import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js"; -import type { AgentRunTerminalReplySnapshot } from "./agent-run-terminal-reply.js"; +} from "../../../utils/delivery-context.shared.js"; +import { INTERNAL_MESSAGE_CHANNEL } from "../../../utils/message-channel.js"; +import type { AgentRunTerminalReplySnapshot } from "../../agent-run-terminal-reply.js"; import { buildAnnounceIdFromChildRun, buildAnnounceIdempotencyKey, -} from "./announce-idempotency.js"; -import { formatAgentInternalEventsForPrompt, type AgentInternalEvent } from "./internal-events.js"; +} from "../../announce-idempotency.js"; +import { + formatAgentInternalEventsForPrompt, + type AgentInternalEvent, +} from "../../internal-events.js"; +import { isAnnounceSkip } from "../../tools/sessions-send-tokens.js"; +import { deleteSubagentSessionForCleanup } from "../registry/subagent-session-cleanup.js"; +import { getSubagentDepthFromSessionStore } from "../spawn/subagent-depth.js"; +import type { SpawnSubagentMode } from "../spawn/subagent-spawn.types.js"; import { deliverSubagentAnnouncement, loadRequesterSessionEntry, @@ -57,10 +64,6 @@ import { getRuntimeConfig, waitForEmbeddedAgentRunEnd, } from "./subagent-announce.runtime.js"; -import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; -import { deleteSubagentSessionForCleanup } from "./subagent-session-cleanup.js"; -import type { SpawnSubagentMode } from "./subagents/spawn/subagent-spawn.types.js"; -import { isAnnounceSkip } from "./tools/sessions-send-tokens.js"; type SubagentAnnounceDeps = { callGateway: typeof callGateway; @@ -79,14 +82,14 @@ const defaultSubagentAnnounceDeps: SubagentAnnounceDeps = { let subagentAnnounceDeps: SubagentAnnounceDeps = defaultSubagentAnnounceDeps; const subagentRegistryRuntimeLoader = createLazyImportLoader( - () => import("./subagent-registry-runtime.js"), + () => import("../registry/subagent-registry-runtime.js"), ); function loadSubagentRegistryRuntime() { return subagentRegistryRuntimeLoader.load(); } -export { buildSubagentSystemPrompt } from "./subagent-system-prompt.js"; +export { buildSubagentSystemPrompt } from "../spawn/subagent-system-prompt.js"; export { captureSubagentCompletionReply } from "./subagent-announce-output.js"; export type { SubagentRunOutcome } from "./subagent-announce-output.js"; diff --git a/src/agents/subagent-requester-store-key.ts b/src/agents/subagents/announce/subagent-requester-store-key.ts similarity index 76% rename from src/agents/subagent-requester-store-key.ts rename to src/agents/subagents/announce/subagent-requester-store-key.ts index e42d68102cc9..0047acd00390 100644 --- a/src/agents/subagent-requester-store-key.ts +++ b/src/agents/subagents/announce/subagent-requester-store-key.ts @@ -6,10 +6,10 @@ import { resolveAgentIdFromSessionKey, resolveMainSessionKey, -} from "../config/sessions/main-session.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { normalizeMainKey } from "../routing/session-key.js"; -import { resolveDefaultAgentId } from "./agent-scope-config.js"; +} from "../../../config/sessions/main-session.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { normalizeMainKey } from "../../../routing/session-key.js"; +import { resolveDefaultAgentId } from "../../agent-scope-config.js"; /** Resolve the canonical store key for a subagent requester session. */ export function resolveRequesterStoreKey(cfg: OpenClawConfig, requesterSessionKey: string): string { diff --git a/src/agents/subagent-yield-output.ts b/src/agents/subagents/announce/subagent-yield-output.ts similarity index 97% rename from src/agents/subagent-yield-output.ts rename to src/agents/subagents/announce/subagent-yield-output.ts index f4a7806b9339..daca4420c839 100644 --- a/src/agents/subagent-yield-output.ts +++ b/src/agents/subagents/announce/subagent-yield-output.ts @@ -5,7 +5,7 @@ */ import { safeParseJson } from "@openclaw/normalization-core"; import { asOptionalRecord } from "@openclaw/normalization-core/record-coerce"; -import { readTrimmedStringAlias } from "../utils/string-readers.js"; +import { readTrimmedStringAlias } from "../../../utils/string-readers.js"; function readToolName(value: unknown): string | undefined { const record = asOptionalRecord(value); diff --git a/src/agents/subagent-completion-admission.store.test.ts b/src/agents/subagents/completion/subagent-completion-admission.store.test.ts similarity index 92% rename from src/agents/subagent-completion-admission.store.test.ts rename to src/agents/subagents/completion/subagent-completion-admission.store.test.ts index c09ef20a88f1..a5886d16319e 100644 --- a/src/agents/subagent-completion-admission.store.test.ts +++ b/src/agents/subagents/completion/subagent-completion-admission.store.test.ts @@ -1,18 +1,22 @@ import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; -import { prepareClaimedSessionDelivery } from "../infra/session-delivery-queue-storage.js"; -import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js"; +import { useAutoCleanupTempDirTracker } from "../../../../test/helpers/temp-dir.js"; +import { prepareClaimedSessionDelivery } from "../../../infra/session-delivery-queue-storage.js"; +import { resolvePreferredOpenClawTmpDir } from "../../../infra/tmp-openclaw-dir.js"; import { closeOpenClawStateDatabaseForTest, openOpenClawStateDatabase, type OpenClawStateDatabase, -} from "../state/openclaw-state-db.js"; -import { ensureTaskRegistryReady, getTaskById } from "../tasks/runtime-internal.js"; -import { publishTaskRecordAfterAtomicStore } from "../tasks/task-registry.js"; -import type { TaskRecord } from "../tasks/task-registry.types.js"; -import { resetTaskRegistryForTests } from "../tasks/task-runtime.test-helpers.js"; -import { withEnvAsync } from "../test-utils/env.js"; +} from "../../../state/openclaw-state-db.js"; +import { ensureTaskRegistryReady, getTaskById } from "../../../tasks/runtime-internal.js"; +import { publishTaskRecordAfterAtomicStore } from "../../../tasks/task-registry.js"; +import type { TaskRecord } from "../../../tasks/task-registry.types.js"; +import { resetTaskRegistryForTests } from "../../../tasks/task-runtime.test-helpers.js"; +import { withEnvAsync } from "../../../test-utils/env.js"; +import { createSubagentRunRecord } from "../../subagent-test-fixtures.test-helpers.js"; +import { subagentRuns } from "../registry/subagent-registry-memory.js"; +import { loadSubagentRegistryFromSqlite } from "../registry/subagent-registry.store.sqlite.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; import { admitSubagentCompletionDelivery, settleSubagentCompletionDelivery, @@ -22,15 +26,11 @@ import { resolveCorrelatedSubagentDelivery, retrySubagentCompletionDelivery, } from "./subagent-completion-delivery.js"; -import { subagentRuns } from "./subagent-registry-memory.js"; -import { loadSubagentRegistryFromSqlite } from "./subagent-registry.store.sqlite.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { createSubagentRunRecord } from "./subagent-test-fixtures.test-helpers.js"; const resumeSubagentRun = vi.hoisted(() => vi.fn()); const tempDirs = useAutoCleanupTempDirTracker(afterEach); -vi.mock("./subagent-registry.js", () => ({ resumeSubagentRun })); +vi.mock("../registry/subagent-registry.js", () => ({ resumeSubagentRun })); describe("atomic subagent completion admission store", () => { let tempDir: string; diff --git a/src/agents/subagent-completion-admission.store.ts b/src/agents/subagents/completion/subagent-completion-admission.store.ts similarity index 90% rename from src/agents/subagent-completion-admission.store.ts rename to src/agents/subagents/completion/subagent-completion-admission.store.ts index 1229fc594b38..7781b54cd5cb 100644 --- a/src/agents/subagent-completion-admission.store.ts +++ b/src/agents/subagents/completion/subagent-completion-admission.store.ts @@ -2,23 +2,26 @@ import { bindDeliveryQueueEntry, loadDeliveryQueueEntryInDatabase, upsertBoundDeliveryQueueEntryInDatabase, -} from "../infra/delivery-queue-sqlite-bound.js"; +} from "../../../infra/delivery-queue-sqlite-bound.js"; import { SESSION_DELIVERY_QUEUE_NAME, type QueuedSessionDelivery, -} from "../infra/session-delivery-queue.js"; +} from "../../../infra/session-delivery-queue.js"; import { runOpenClawStateWriteTransaction, type OpenClawStateDatabase, type OpenClawStateDatabaseOptions, -} from "../state/openclaw-state-db.js"; -import { bindTaskRecord, upsertTaskRunRowInDatabase } from "../tasks/task-registry.store.sqlite.js"; -import type { TaskRecord } from "../tasks/task-registry.types.js"; +} from "../../../state/openclaw-state-db.js"; +import { + bindTaskRecord, + upsertTaskRunRowInDatabase, +} from "../../../tasks/task-registry.store.sqlite.js"; +import type { TaskRecord } from "../../../tasks/task-registry.types.js"; import { bindSubagentRunRecord, upsertSubagentRunRowInDatabase, -} from "./subagent-registry.store.sqlite.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; +} from "../registry/subagent-registry.store.sqlite.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; type AdmissionTestHooks = { afterBind?: () => unknown; diff --git a/src/agents/subagent-completion-delivery.ts b/src/agents/subagents/completion/subagent-completion-delivery.ts similarity index 92% rename from src/agents/subagent-completion-delivery.ts rename to src/agents/subagents/completion/subagent-completion-delivery.ts index dd3708fc7946..8450d1a82ce8 100644 --- a/src/agents/subagent-completion-delivery.ts +++ b/src/agents/subagents/completion/subagent-completion-delivery.ts @@ -1,8 +1,8 @@ import { getDeliveryQueueEntryStatus, loadDeliveryQueueEntryAnyStatus, -} from "../infra/delivery-queue-sqlite.js"; -import { scheduleSessionDelivery } from "../infra/session-delivery-queue-runtime.js"; +} from "../../../infra/delivery-queue-sqlite.js"; +import { scheduleSessionDelivery } from "../../../infra/session-delivery-queue-runtime.js"; import { prepareClaimedSessionDelivery, releaseSessionDeliveryClaim, @@ -12,23 +12,23 @@ import { type SessionDeliverySettledOutcome, SessionDeliveryDeadLetteredError, SessionDeliveryDeferredError, -} from "../infra/session-delivery-queue-storage.js"; -import type { OpenClawStateDatabaseOptions } from "../state/openclaw-state-db.js"; +} from "../../../infra/session-delivery-queue-storage.js"; +import type { OpenClawStateDatabaseOptions } from "../../../state/openclaw-state-db.js"; import { findTaskByRunId, getTaskById, publishTaskRecordAfterAtomicStore, -} from "../tasks/runtime-internal.js"; -import type { TaskRecord } from "../tasks/task-registry.types.js"; +} from "../../../tasks/runtime-internal.js"; +import type { TaskRecord } from "../../../tasks/task-registry.types.js"; +import { ensureDeliveryState } from "../registry/subagent-delivery-state.js"; +import { ANNOUNCE_COMPLETION_HARD_EXPIRY_MS } from "../registry/subagent-registry-helpers.js"; +import { subagentRuns } from "../registry/subagent-registry-memory.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; import { admitSubagentCompletionDelivery, settleSubagentCompletionDelivery, } from "./subagent-completion-admission.store.js"; import { resolveSubagentCompletionResultText } from "./subagent-completion-result.js"; -import { ensureDeliveryState } from "./subagent-delivery-state.js"; -import { ANNOUNCE_COMPLETION_HARD_EXPIRY_MS } from "./subagent-registry-helpers.js"; -import { subagentRuns } from "./subagent-registry-memory.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; const CLAIM_LEASE_MS = 125_000; const SUSPENDED_RETENTION_MS = 7 * 24 * 60 * 60_000; @@ -228,7 +228,7 @@ export async function settleCorrelatedSubagentDelivery( settleSubagentCompletionDelivery({ subagent, task: projectedTask }); publishCommittedRecords(subagent, projectedTask); if (outcome === "recovered") { - const { resumeSubagentRun } = await import("./subagent-registry.js"); + const { resumeSubagentRun } = await import("../registry/subagent-registry.js"); resumeSubagentRun(subagent.runId); } } @@ -280,7 +280,7 @@ export async function retrySubagentCompletionDelivery( const projectedTask = projectRedrivenTask(task, redrive, "pending", now); settleSubagentCompletionDelivery({ subagent: redrive, task: projectedTask, databaseOptions }); publishCommittedRecords(redrive, projectedTask); - const { resumeSubagentRun } = await import("./subagent-registry.js"); + const { resumeSubagentRun } = await import("../registry/subagent-registry.js"); resumeSubagentRun(redrive.runId); return { ok: true, task: getTaskById(taskId), duplicateRisk: true }; } diff --git a/src/agents/subagent-completion-result.test.ts b/src/agents/subagents/completion/subagent-completion-result.test.ts similarity index 100% rename from src/agents/subagent-completion-result.test.ts rename to src/agents/subagents/completion/subagent-completion-result.test.ts diff --git a/src/agents/subagent-completion-result.ts b/src/agents/subagents/completion/subagent-completion-result.ts similarity index 83% rename from src/agents/subagent-completion-result.ts rename to src/agents/subagents/completion/subagent-completion-result.ts index 6fe153a2f59a..6227466892b3 100644 --- a/src/agents/subagent-completion-result.ts +++ b/src/agents/subagents/completion/subagent-completion-result.ts @@ -1,5 +1,5 @@ -import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { selectDeliverableSessionsReply } from "./tools/sessions-send-tokens.js"; +import { selectDeliverableSessionsReply } from "../../tools/sessions-send-tokens.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; /** Selects the canonical operator-visible result from captured completion state. */ export function resolveSubagentCompletionResultText( diff --git a/src/agents/subagent-active-context.test.ts b/src/agents/subagents/registry/subagent-active-context.test.ts similarity index 98% rename from src/agents/subagent-active-context.test.ts rename to src/agents/subagents/registry/subagent-active-context.test.ts index 18768fa56d22..d0e3dff934e0 100644 --- a/src/agents/subagent-active-context.test.ts +++ b/src/agents/subagents/registry/subagent-active-context.test.ts @@ -1,7 +1,7 @@ // Active subagent prompt tests cover the compact system prompt block that tells // a parent session which child runs are still in flight. import { beforeEach, describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import { buildActiveSubagentSystemPromptAddition } from "./subagent-active-context.js"; import { addSubagentRunForTests, diff --git a/src/agents/subagent-active-context.ts b/src/agents/subagents/registry/subagent-active-context.ts similarity index 90% rename from src/agents/subagent-active-context.ts rename to src/agents/subagents/registry/subagent-active-context.ts index 9f3c38345590..029f1f4e7645 100644 --- a/src/agents/subagent-active-context.ts +++ b/src/agents/subagents/registry/subagent-active-context.ts @@ -3,11 +3,14 @@ * * Renders sanitized runtime-owned subagent state into system prompt additions. */ -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { sanitizeForPromptLiteral } from "../../sanitize-for-prompt.js"; +import { + resolveInternalSessionKey, + resolveMainSessionAlias, +} from "../../tools/sessions-helpers.js"; import { listControlledSubagentRuns } from "./subagent-control.js"; import { buildSubagentList } from "./subagent-list.js"; -import { resolveInternalSessionKey, resolveMainSessionAlias } from "./tools/sessions-helpers.js"; // Prompt data is sanitized then JSON-quoted so active subagent state cannot add // executable prompt instructions through labels or task text. diff --git a/src/agents/subagents/registry/subagent-control.runtime.ts b/src/agents/subagents/registry/subagent-control.runtime.ts new file mode 100644 index 000000000000..45bbbb5e4ce7 --- /dev/null +++ b/src/agents/subagents/registry/subagent-control.runtime.ts @@ -0,0 +1,8 @@ +/** + * Runtime seams used by subagent control for queue and embedded-run cancellation. + */ +export { clearSessionQueues } from "../../../auto-reply/reply/queue.js"; +export { + abortEmbeddedAgentRun, + isEmbeddedAgentRunActive, +} from "../../embedded-agent-runner/runs.js"; diff --git a/src/agents/subagent-control.test-support.ts b/src/agents/subagents/registry/subagent-control.test-support.ts similarity index 79% rename from src/agents/subagent-control.test-support.ts rename to src/agents/subagents/registry/subagent-control.test-support.ts index 5f0ad1679420..351a7d018b4d 100644 --- a/src/agents/subagent-control.test-support.ts +++ b/src/agents/subagents/registry/subagent-control.test-support.ts @@ -2,8 +2,8 @@ export * from "./subagent-control.js"; type ControlRuntime = typeof import("./subagent-control.runtime.js"); type ControlDeps = { - callGateway: typeof import("../gateway/call.js").callGateway; - patchSessionEntry: typeof import("../config/sessions/session-accessor.js").patchSessionEntry; + callGateway: typeof import("../../../gateway/call.js").callGateway; + patchSessionEntry: typeof import("../../../config/sessions/session-accessor.js").patchSessionEntry; abortEmbeddedAgentRun: ControlRuntime["abortEmbeddedAgentRun"]; isEmbeddedAgentRunActive: ControlRuntime["isEmbeddedAgentRunActive"]; clearSessionQueues: ControlRuntime["clearSessionQueues"]; diff --git a/src/agents/subagent-control.test.ts b/src/agents/subagents/registry/subagent-control.test.ts similarity index 99% rename from src/agents/subagent-control.test.ts rename to src/agents/subagents/registry/subagent-control.test.ts index 3e3c13212adc..120ac29aea91 100644 --- a/src/agents/subagent-control.test.ts +++ b/src/agents/subagents/registry/subagent-control.test.ts @@ -8,23 +8,24 @@ import type { SessionAccessScope, SessionEntryPatchContext, SessionEntryPatchOptions, -} from "../config/sessions/session-accessor.js"; +} from "../../../config/sessions/session-accessor.js"; import { loadSessionEntry, replaceSessionEntry, replaceSessionEntrySync, -} from "../config/sessions/session-accessor.js"; -import type { SessionEntry } from "../config/sessions/types.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { CallGatewayOptions } from "../gateway/call.js"; -import { rotateAgentEventLifecycleGeneration } from "../infra/agent-events.js"; +} from "../../../config/sessions/session-accessor.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { CallGatewayOptions } from "../../../gateway/call.js"; +import { rotateAgentEventLifecycleGeneration } from "../../../infra/agent-events.js"; import { beginSessionWorkAdmission, consumeSessionWorkAdmissionHandoff, getActiveSessionLifecycleMutationCount, SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS, -} from "../sessions/session-lifecycle-admission.js"; -import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js"; +} from "../../../sessions/session-lifecycle-admission.js"; +import { SUBAGENT_KILL_TASK_ERROR } from "../../../tasks/detached-task-runtime-contract.js"; +import { createSubagentRunRecord } from "../../subagent-test-fixtures.test-helpers.js"; import { buildControlledSubagentRunsReadContext, testing, @@ -47,11 +48,10 @@ import { resetSubagentRegistryForTests, } from "./subagent-registry.test-helpers.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { createSubagentRunRecord } from "./subagent-test-fixtures.test-helpers.js"; -type GatewayCaller = typeof import("../gateway/call.js").callGateway; +type GatewayCaller = typeof import("../../../gateway/call.js").callGateway; -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: vi.fn(), })); @@ -60,7 +60,7 @@ const detachedTaskRuntimeMocks = vi.hoisted(() => ({ finalizeTaskRunByRunId: vi.fn<(_params: unknown) => unknown[]>(() => []), })); -vi.mock("../tasks/detached-task-runtime.js", () => ({ +vi.mock("../../../tasks/detached-task-runtime.js", () => ({ createQueuedTaskRun: vi.fn(() => null), createRunningTaskRun: vi.fn(() => null), startTaskRunByRunId: vi.fn(() => []), @@ -72,7 +72,7 @@ vi.mock("../tasks/detached-task-runtime.js", () => ({ findDetachedTaskRun: detachedTaskRuntimeMocks.findDetachedTaskRun, })); -vi.mock("./run-wait.js", () => { +vi.mock("../../run-wait.js", () => { const readLatestAssistantReplySnapshot = async (params: { sessionKey: string; limit?: number; diff --git a/src/agents/subagent-control.ts b/src/agents/subagents/registry/subagent-control.ts similarity index 96% rename from src/agents/subagent-control.ts rename to src/agents/subagents/registry/subagent-control.ts index dfc7b7c12307..f940b1b9b6fd 100644 --- a/src/agents/subagent-control.ts +++ b/src/agents/subagents/registry/subagent-control.ts @@ -1,36 +1,44 @@ /** Controller-authorized subagent list, kill, steer, and message operations. */ import crypto from "node:crypto"; -import type { ClearSessionQueueResult } from "../auto-reply/reply/queue.js"; -import { resolveSubagentLabel, sortSubagentRuns } from "../auto-reply/reply/subagents-utils.js"; -import { resolveStorePath } from "../config/sessions/paths.js"; -import { loadSessionEntry, patchSessionEntry } from "../config/sessions/session-accessor.js"; -import type { SessionEntry } from "../config/sessions/types.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { callGateway } from "../gateway/call.js"; -import { logVerbose } from "../globals.js"; +import type { ClearSessionQueueResult } from "../../../auto-reply/reply/queue.js"; +import { + resolveSubagentLabel, + sortSubagentRuns, +} from "../../../auto-reply/reply/subagents-utils.js"; +import { resolveStorePath } from "../../../config/sessions/paths.js"; +import { loadSessionEntry, patchSessionEntry } from "../../../config/sessions/session-accessor.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { callGateway } from "../../../gateway/call.js"; +import { logVerbose } from "../../../globals.js"; import { getAgentEventLifecycleGeneration, isAgentEventLifecycleGenerationCurrent, -} from "../infra/agent-events.js"; -import { formatErrorMessage } from "../infra/errors.js"; -import { isSubagentSessionKey, parseAgentSessionKey } from "../routing/session-key.js"; +} from "../../../infra/agent-events.js"; +import { formatErrorMessage } from "../../../infra/errors.js"; +import { isSubagentSessionKey, parseAgentSessionKey } from "../../../routing/session-key.js"; import { interruptSessionWorkAdmissions, runExclusiveSessionLifecycleMutation, SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS, -} from "../sessions/session-lifecycle-admission.js"; -import { createLazyImportLoader } from "../shared/lazy-promise.js"; +} from "../../../sessions/session-lifecycle-admission.js"; +import { createLazyImportLoader } from "../../../shared/lazy-promise.js"; import { SUBAGENT_KILL_TASK_ERROR, type DetachedTaskTerminalState, -} from "../tasks/detached-task-runtime-contract.js"; -import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js"; -import { AGENT_LANE_SUBAGENT } from "./lanes.js"; +} from "../../../tasks/detached-task-runtime-contract.js"; +import { INTERNAL_MESSAGE_CHANNEL } from "../../../utils/message-channel.js"; +import { AGENT_LANE_SUBAGENT } from "../../lanes.js"; import { readLatestAssistantReplySnapshot, waitForAgentRunAndReadUpdatedAssistantReply, -} from "./run-wait.js"; -import { resolveStoredSubagentCapabilities } from "./subagent-capabilities.js"; +} from "../../run-wait.js"; +import { + resolveInternalSessionKey, + resolveMainSessionAlias, +} from "../../tools/sessions-helpers.js"; +import { resolveStoredSubagentCapabilities } from "../spawn/subagent-capabilities.js"; +import { terminateAcceptedCollectorRun } from "../spawn/subagent-spawn-cleanup.js"; import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js"; import { resolveSessionEntryForKey } from "./subagent-list.js"; import { @@ -54,8 +62,6 @@ import { replaceSubagentRunAfterSteer, } from "./subagent-registry.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { terminateAcceptedCollectorRun } from "./subagents/spawn/subagent-spawn-cleanup.js"; -import { resolveInternalSessionKey, resolveMainSessionAlias } from "./tools/sessions-helpers.js"; /** Recent-run default window used by subagent control UI/tools. */ export const DEFAULT_RECENT_MINUTES = 30; diff --git a/src/agents/subagent-delivery-state.test.ts b/src/agents/subagents/registry/subagent-delivery-state.test.ts similarity index 100% rename from src/agents/subagent-delivery-state.test.ts rename to src/agents/subagents/registry/subagent-delivery-state.test.ts diff --git a/src/agents/subagent-delivery-state.ts b/src/agents/subagents/registry/subagent-delivery-state.ts similarity index 98% rename from src/agents/subagent-delivery-state.ts rename to src/agents/subagents/registry/subagent-delivery-state.ts index bd39e290e287..23a3086275b9 100644 --- a/src/agents/subagent-delivery-state.ts +++ b/src/agents/subagents/registry/subagent-delivery-state.ts @@ -1,4 +1,4 @@ -import { normalizeAgentRunTerminalReplySnapshot } from "./agent-run-terminal-reply.js"; +import { normalizeAgentRunTerminalReplySnapshot } from "../../agent-run-terminal-reply.js"; import type { SubagentCompletionDeliveryState, SubagentCompletionState, diff --git a/src/agents/subagent-lifecycle-events.ts b/src/agents/subagents/registry/subagent-lifecycle-events.ts similarity index 100% rename from src/agents/subagent-lifecycle-events.ts rename to src/agents/subagents/registry/subagent-lifecycle-events.ts diff --git a/src/agents/subagent-list.test.ts b/src/agents/subagents/registry/subagent-list.test.ts similarity index 99% rename from src/agents/subagent-list.test.ts rename to src/agents/subagents/registry/subagent-list.test.ts index 3fd26bfbdd98..91609983c098 100644 --- a/src/agents/subagent-list.test.ts +++ b/src/agents/subagents/registry/subagent-list.test.ts @@ -4,8 +4,8 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { replaceSessionEntry } from "../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../../config/config.js"; +import { replaceSessionEntry } from "../../../config/sessions/session-accessor.js"; import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js"; import { buildSubagentList } from "./subagent-list.js"; import { diff --git a/src/agents/subagent-list.ts b/src/agents/subagents/registry/subagent-list.ts similarity index 93% rename from src/agents/subagent-list.ts rename to src/agents/subagents/registry/subagent-list.ts index 6b7d30f0e82a..2e2610dc652c 100644 --- a/src/agents/subagent-list.ts +++ b/src/agents/subagents/registry/subagent-list.ts @@ -4,19 +4,22 @@ * Combines live registry runs and persisted session metadata for sessions_list/subagents views. */ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; -import { resolveSubagentLabel, sortSubagentRuns } from "../auto-reply/reply/subagents-utils.js"; -import { resolveStorePath } from "../config/sessions/paths.js"; -import { listSessionEntriesReadOnly } from "../config/sessions/session-accessor.js"; -import type { SessionEntry } from "../config/sessions/types.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { formatDurationCompact } from "../infra/format-time/format-duration.js"; -import { parseAgentSessionKey, type ParsedAgentSessionKey } from "../routing/session-key.js"; +import { + resolveSubagentLabel, + sortSubagentRuns, +} from "../../../auto-reply/reply/subagents-utils.js"; +import { resolveStorePath } from "../../../config/sessions/paths.js"; +import { listSessionEntriesReadOnly } from "../../../config/sessions/session-accessor.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { formatDurationCompact } from "../../../infra/format-time/format-duration.js"; +import { parseAgentSessionKey, type ParsedAgentSessionKey } from "../../../routing/session-key.js"; import { formatTokenUsageDisplay, resolveTotalTokens, truncateLine, -} from "../shared/subagents-format.js"; -import { resolveModelDisplayName, resolveModelDisplayRef } from "./model-selection-display.js"; +} from "../../../shared/subagents-format.js"; +import { resolveModelDisplayName, resolveModelDisplayRef } from "../../model-selection-display.js"; import { subagentRuns } from "./subagent-registry-memory.js"; import { buildSubagentRunReadIndexFromRuns } from "./subagent-registry-queries.js"; import { diff --git a/src/agents/subagent-recovery-state.ts b/src/agents/subagents/registry/subagent-recovery-state.ts similarity index 91% rename from src/agents/subagent-recovery-state.ts rename to src/agents/subagents/registry/subagent-recovery-state.ts index ad837fb156eb..b4890d31ce54 100644 --- a/src/agents/subagent-recovery-state.ts +++ b/src/agents/subagents/registry/subagent-recovery-state.ts @@ -1,5 +1,5 @@ -import type { SessionEntry } from "../config/sessions.js"; -import { isAgentEventLifecycleGenerationCurrent } from "../infra/agent-events.js"; +import type { SessionEntry } from "../../../config/sessions.js"; +import { isAgentEventLifecycleGenerationCurrent } from "../../../infra/agent-events.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; export function shouldSuppressSubagentRecoverySessionEffects(entry: SubagentRunRecord): boolean { diff --git a/src/agents/subagent-registry-announce-read.ts b/src/agents/subagents/registry/subagent-registry-announce-read.ts similarity index 94% rename from src/agents/subagent-registry-announce-read.ts rename to src/agents/subagents/registry/subagent-registry-announce-read.ts index 9bafd0bce89e..577c900a9395 100644 --- a/src/agents/subagent-registry-announce-read.ts +++ b/src/agents/subagents/registry/subagent-registry-announce-read.ts @@ -3,8 +3,8 @@ * announce delivery code on normalized registry snapshots instead of reaching * into persistence or mutation paths. */ -import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js"; -import type { DeliveryContext } from "../utils/delivery-context.types.js"; +import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; import { subagentRuns } from "./subagent-registry-memory.js"; import { countPendingDescendantRunsExcludingRunFromRuns, diff --git a/src/agents/subagent-registry-cleanup.test.ts b/src/agents/subagents/registry/subagent-registry-cleanup.test.ts similarity index 100% rename from src/agents/subagent-registry-cleanup.test.ts rename to src/agents/subagents/registry/subagent-registry-cleanup.test.ts diff --git a/src/agents/subagent-registry-cleanup.ts b/src/agents/subagents/registry/subagent-registry-cleanup.ts similarity index 100% rename from src/agents/subagent-registry-cleanup.ts rename to src/agents/subagents/registry/subagent-registry-cleanup.ts diff --git a/src/agents/subagent-registry-completion-runtime.ts b/src/agents/subagents/registry/subagent-registry-completion-runtime.ts similarity index 99% rename from src/agents/subagent-registry-completion-runtime.ts rename to src/agents/subagents/registry/subagent-registry-completion-runtime.ts index 825e31bccde4..2a89a060581d 100644 --- a/src/agents/subagent-registry-completion-runtime.ts +++ b/src/agents/subagents/registry/subagent-registry-completion-runtime.ts @@ -1,7 +1,7 @@ import { isGatewayRestartDraining, runWithGatewayIndependentRootWorkAdmission, -} from "../process/gateway-work-admission.js"; +} from "../../../process/gateway-work-admission.js"; import { SUBAGENT_ENDED_REASON_ERROR } from "./subagent-lifecycle-events.js"; import { createPendingLifecycleScheduler } from "./subagent-registry-pending-lifecycle.js"; import type { SubagentCompletionRequest, SubagentRunRecord } from "./subagent-registry.types.js"; diff --git a/src/agents/subagent-registry-completion.test.ts b/src/agents/subagents/registry/subagent-registry-completion.test.ts similarity index 98% rename from src/agents/subagent-registry-completion.test.ts rename to src/agents/subagents/registry/subagent-registry-completion.test.ts index c7ab6d8ef6fa..65f841dc2776 100644 --- a/src/agents/subagent-registry-completion.test.ts +++ b/src/agents/subagents/registry/subagent-registry-completion.test.ts @@ -11,7 +11,7 @@ const lifecycleMocks = vi.hoisted(() => ({ runSubagentEnded: vi.fn(async () => {}), })); -vi.mock("../plugins/hook-runner-global.js", () => ({ +vi.mock("../../../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: lifecycleMocks.getGlobalHookRunner, })); function createRunEntry(): SubagentRunRecord { diff --git a/src/agents/subagent-registry-completion.ts b/src/agents/subagents/registry/subagent-registry-completion.ts similarity index 92% rename from src/agents/subagent-registry-completion.ts rename to src/agents/subagents/registry/subagent-registry-completion.ts index 3ec92d8670c0..e08bf043d0c9 100644 --- a/src/agents/subagent-registry-completion.ts +++ b/src/agents/subagents/registry/subagent-registry-completion.ts @@ -3,15 +3,15 @@ * Compares outcomes, maps them to lifecycle events, and emits completion hooks * exactly once per completed child run. */ -import { createSubsystemLogger } from "../logging/subsystem.js"; -import { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; +import { createSubsystemLogger } from "../../../logging/subsystem.js"; +import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js"; import { SUBAGENT_KILL_TASK_ERROR, type DetachedTaskTerminalState, -} from "../tasks/detached-task-runtime-contract.js"; -import { resolveRequiredCompletionTerminalResult } from "../tasks/task-completion-contract.js"; -import type { SubagentRunOutcome } from "./subagent-announce-output.js"; -import { resolveSubagentCompletionResultText } from "./subagent-completion-result.js"; +} from "../../../tasks/detached-task-runtime-contract.js"; +import { resolveRequiredCompletionTerminalResult } from "../../../tasks/task-completion-contract.js"; +import type { SubagentRunOutcome } from "../announce/subagent-announce-output.js"; +import { resolveSubagentCompletionResultText } from "../completion/subagent-completion-result.js"; import { SUBAGENT_ENDED_REASON_KILLED, SUBAGENT_ENDED_OUTCOME_ERROR, diff --git a/src/agents/subagent-registry-context-cleanup.test.ts b/src/agents/subagents/registry/subagent-registry-context-cleanup.test.ts similarity index 100% rename from src/agents/subagent-registry-context-cleanup.test.ts rename to src/agents/subagents/registry/subagent-registry-context-cleanup.test.ts diff --git a/src/agents/subagent-registry-context-cleanup.ts b/src/agents/subagents/registry/subagent-registry-context-cleanup.ts similarity index 97% rename from src/agents/subagent-registry-context-cleanup.ts rename to src/agents/subagents/registry/subagent-registry-context-cleanup.ts index 2ac875c80076..841bce49fec5 100644 --- a/src/agents/subagent-registry-context-cleanup.ts +++ b/src/agents/subagents/registry/subagent-registry-context-cleanup.ts @@ -1,5 +1,5 @@ -import { withPluginRuntimeRegistryScope } from "../plugins/runtime/gateway-request-scope.js"; -import { removeInternalSessionEffectsSession } from "./internal-session-effects.js"; +import { withPluginRuntimeRegistryScope } from "../../../plugins/runtime/gateway-request-scope.js"; +import { removeInternalSessionEffectsSession } from "../../internal-session-effects.js"; import { SUBAGENT_ENDED_OUTCOME_KILLED, SUBAGENT_ENDED_REASON_COMPLETE, diff --git a/src/agents/subagent-registry-deps.ts b/src/agents/subagents/registry/subagent-registry-deps.ts similarity index 80% rename from src/agents/subagent-registry-deps.ts rename to src/agents/subagents/registry/subagent-registry-deps.ts index 04aa57fbe40f..8a26c40d9299 100644 --- a/src/agents/subagent-registry-deps.ts +++ b/src/agents/subagents/registry/subagent-registry-deps.ts @@ -1,15 +1,16 @@ -import type { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js"; -import { getRuntimeConfig } from "../config/config.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { ResolveContextEngineOptions } from "../context-engine/registry.js"; -import type { ContextEngine } from "../context-engine/types.js"; -import { callGateway } from "../gateway/call.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { getGatewayRecoveryRuntime } from "../gateway/server-recovery-runtime-context.js"; -import { onAgentEvent, type AgentEventPayload } from "../infra/agent-events.js"; -import type { PluginRegistry } from "../plugins/registry-types.js"; -import { createLazyImportLoader, createLazyPromiseLoader } from "../shared/lazy-promise.js"; -import { importRuntimeModule } from "../shared/runtime-import.js"; +import type { cleanupBrowserSessionsForLifecycleEnd } from "../../../browser-lifecycle-cleanup.js"; +import { getRuntimeConfig } from "../../../config/config.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { ResolveContextEngineOptions } from "../../../context-engine/registry.js"; +import type { ContextEngine } from "../../../context-engine/types.js"; +import { callGateway } from "../../../gateway/call.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; +import { getGatewayRecoveryRuntime } from "../../../gateway/server-recovery-runtime-context.js"; +import { onAgentEvent, type AgentEventPayload } from "../../../infra/agent-events.js"; +import type { PluginRegistry } from "../../../plugins/registry-types.js"; +import { createLazyImportLoader, createLazyPromiseLoader } from "../../../shared/lazy-promise.js"; +import { importRuntimeModule } from "../../../shared/runtime-import.js"; +import { resolveAgentTimeoutMs } from "../../timeout.js"; import { getSubagentRunsSnapshotForChildSession, getSubagentRunsSnapshotForController, @@ -18,18 +19,17 @@ import { persistSubagentRunsToDiskOrThrow, restoreSubagentRunsFromDisk, } from "./subagent-registry-state.js"; -import { resolveAgentTimeoutMs } from "./timeout.js"; type SubagentAnnounceModule = Pick< - typeof import("./subagent-announce.js"), + typeof import("../announce/subagent-announce.js"), "captureSubagentCompletionReply" | "runSubagentAnnounceFlow" >; type RequesterSettleWakeModule = Pick< - typeof import("./subagent-announce.requester-settle-wake.js"), + typeof import("../announce/subagent-announce.requester-settle-wake.js"), "maybeWakeRequesterAfterAllChildrenSettled" >; type BrowserCleanupModule = Pick< - typeof import("../browser-lifecycle-cleanup.js"), + typeof import("../../../browser-lifecycle-cleanup.js"), "cleanupBrowserSessionsForLifecycleEnd" >; @@ -62,10 +62,10 @@ export type SubagentRegistryDeps = { }; const subagentAnnounceLoader = createLazyImportLoader( - () => import("./subagent-announce.js"), + () => import("../announce/subagent-announce.js"), ); const browserCleanupLoader = createLazyImportLoader( - () => import("../browser-lifecycle-cleanup.js"), + () => import("../../../browser-lifecycle-cleanup.js"), ); async function loadSubagentAnnounceModule(): Promise { @@ -98,7 +98,7 @@ const defaultSubagentRegistryDeps: SubagentRegistryDeps = { (await loadSubagentAnnounceModule()).runSubagentAnnounceFlow(params), maybeWakeRequesterAfterAllChildrenSettled: async (params) => ( - await import("./subagent-announce.requester-settle-wake.js") + await import("../announce/subagent-announce.requester-settle-wake.js") ).maybeWakeRequesterAfterAllChildrenSettled(params), }; @@ -121,7 +121,7 @@ const subagentRegistryRuntimeLoader = createLazyPromiseLoader(() => ), ); const subagentRegistryPluginRuntimeLoader = createLazyPromiseLoader( - () => import("./runtime-plugins.js"), + () => import("../../runtime-plugins.js"), ); export async function loadSubagentRegistryPluginRuntimeHandle(params: { diff --git a/src/agents/subagent-registry-helpers.test.ts b/src/agents/subagents/registry/subagent-registry-helpers.test.ts similarity index 98% rename from src/agents/subagent-registry-helpers.test.ts rename to src/agents/subagents/registry/subagent-registry-helpers.test.ts index ec86196d8189..0e7b1762aaba 100644 --- a/src/agents/subagent-registry-helpers.test.ts +++ b/src/agents/subagents/registry/subagent-registry-helpers.test.ts @@ -2,7 +2,8 @@ // for announce delivery give-up paths. import { promises as fs } from "node:fs"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { defaultRuntime } from "../runtime.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { updateSwarmCollectorCompletion } from "../swarm/swarm-collector.js"; import { capFrozenResultText, logAnnounceGiveUp, @@ -13,7 +14,6 @@ import { updateSubagentArchiveAtMs, } from "./subagent-registry-helpers.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { updateSwarmCollectorCompletion } from "./subagents/swarm/swarm-collector.js"; function createRunEntry(overrides: Partial = {}): SubagentRunRecord { return { diff --git a/src/agents/subagent-registry-helpers.ts b/src/agents/subagents/registry/subagent-registry-helpers.ts similarity index 96% rename from src/agents/subagent-registry-helpers.ts rename to src/agents/subagents/registry/subagent-registry-helpers.ts index 8fe1c6a0b320..a9314364d016 100644 --- a/src/agents/subagent-registry-helpers.ts +++ b/src/agents/subagents/registry/subagent-registry-helpers.ts @@ -6,14 +6,14 @@ import fsSync, { promises as fs } from "node:fs"; import path from "node:path"; import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; -import { DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES } from "../config/agent-limits.js"; -import { getRuntimeConfig } from "../config/config.js"; -import { resolveAgentIdFromSessionKey, resolveStorePath } from "../config/sessions.js"; -import { patchSessionEntry } from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { computeBackoff } from "../infra/backoff.js"; -import { defaultRuntime } from "../runtime.js"; -import { truncateUtf8Prefix } from "../utils/utf8-truncate.js"; +import { DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES } from "../../../config/agent-limits.js"; +import { getRuntimeConfig } from "../../../config/config.js"; +import { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js"; +import { patchSessionEntry } from "../../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { computeBackoff } from "../../../infra/backoff.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { truncateUtf8Prefix } from "../../../utils/utf8-truncate.js"; import { getDeliveryAttemptCount, getDeliveryLastError } from "./subagent-delivery-state.js"; import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; diff --git a/src/agents/subagent-registry-lifecycle-bookkeeping.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-bookkeeping.ts similarity index 96% rename from src/agents/subagent-registry-lifecycle-bookkeeping.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-bookkeeping.ts index ce434c6bb129..46910246a11c 100644 --- a/src/agents/subagent-registry-lifecycle-bookkeeping.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-bookkeeping.ts @@ -1,7 +1,7 @@ -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; -import { defaultRuntime } from "../runtime.js"; -import { retireSessionMcpRuntimeForSessionKey } from "./agent-bundle-mcp-tools.js"; -import { removeInternalSessionEffectsSession } from "./internal-session-effects.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../../process/gateway-work-admission.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { retireSessionMcpRuntimeForSessionKey } from "../../agent-bundle-mcp-tools.js"; +import { removeInternalSessionEffectsSession } from "../../internal-session-effects.js"; import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js"; import { shouldSuppressSubagentRecoverySessionEffects } from "./subagent-recovery-state.js"; import type { createSubagentRegistryLifecycleCommon } from "./subagent-registry-lifecycle-common.js"; diff --git a/src/agents/subagent-registry-lifecycle-cleanup-base.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-cleanup-base.ts similarity index 96% rename from src/agents/subagent-registry-lifecycle-cleanup-base.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-cleanup-base.ts index a92e3a80fd44..d8e425ecc8d2 100644 --- a/src/agents/subagent-registry-lifecycle-cleanup-base.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-cleanup-base.ts @@ -1,10 +1,10 @@ -import { runWithoutOwnedSessionTranscriptWrites } from "../config/sessions/transcript-write-context.js"; +import { runWithoutOwnedSessionTranscriptWrites } from "../../../config/sessions/transcript-write-context.js"; import { isGatewayRestartDraining, runWithGatewayIndependentRootWorkAdmission, -} from "../process/gateway-work-admission.js"; -import { defaultRuntime } from "../runtime.js"; -import { retireSessionMcpRuntimeForSessionKey } from "./agent-bundle-mcp-tools.js"; +} from "../../../process/gateway-work-admission.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { retireSessionMcpRuntimeForSessionKey } from "../../agent-bundle-mcp-tools.js"; import { ensureCompletionState, ensureDeliveryState, diff --git a/src/agents/subagent-registry-lifecycle-cleanup.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-cleanup.ts similarity index 98% rename from src/agents/subagent-registry-lifecycle-cleanup.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-cleanup.ts index 01291cca0bf5..5cbb431dd819 100644 --- a/src/agents/subagent-registry-lifecycle-cleanup.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-cleanup.ts @@ -1,5 +1,5 @@ -import { defaultRuntime } from "../runtime.js"; -import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js"; +import { defaultRuntime } from "../../../runtime.js"; +import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; import { ensureCompletionState, ensureDeliveryState, @@ -31,7 +31,8 @@ import type { createSubagentRegistryLifecycleDelivery } from "./subagent-registr import type { createSubagentRegistryLifecycleRequesterWake } from "./subagent-registry-lifecycle-requester-wake.js"; import { loadSubagentSessionEntry } from "./subagent-session-reconciliation.js"; -type RunSubagentAnnounceFlow = (typeof import("./subagent-announce.js"))["runSubagentAnnounceFlow"]; +type RunSubagentAnnounceFlow = + (typeof import("../announce/subagent-announce.js"))["runSubagentAnnounceFlow"]; import type { SubagentRunRecord } from "./subagent-registry.types.js"; import { deleteSubagentSessionForCleanup } from "./subagent-session-cleanup.js"; diff --git a/src/agents/subagent-registry-lifecycle-common.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-common.ts similarity index 97% rename from src/agents/subagent-registry-lifecycle-common.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-common.ts index 3d712852b9d2..6ce9826d99fe 100644 --- a/src/agents/subagent-registry-lifecycle-common.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-common.ts @@ -1,5 +1,5 @@ import { sliceUtf16Safe } from "@openclaw/normalization-core/utf16-slice"; -import { formatErrorMessage, readErrorName } from "../infra/errors.js"; +import { formatErrorMessage, readErrorName } from "../../../infra/errors.js"; import type { SubagentRegistryLifecycleParams, SubagentRegistryLifecycleState, diff --git a/src/agents/subagent-registry-lifecycle-completion-support.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-completion-support.ts similarity index 90% rename from src/agents/subagent-registry-lifecycle-completion-support.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-completion-support.ts index eccda2e6cc00..b8682e693d45 100644 --- a/src/agents/subagent-registry-lifecycle-completion-support.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-completion-support.ts @@ -1,5 +1,5 @@ -import { createLazyImportLoader } from "../shared/lazy-promise.js"; -import type { SubagentRunOutcome } from "./subagent-announce-output.js"; +import { createLazyImportLoader } from "../../../shared/lazy-promise.js"; +import type { SubagentRunOutcome } from "../announce/subagent-announce-output.js"; import type { SubagentLifecycleEndedReason } from "./subagent-lifecycle-events.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; import { @@ -8,12 +8,12 @@ import { } from "./subagent-run-timeout.js"; type BrowserCleanupModule = Pick< - typeof import("../browser-lifecycle-cleanup.js"), + typeof import("../../../browser-lifecycle-cleanup.js"), "cleanupBrowserSessionsForLifecycleEnd" >; const browserCleanupLoader = createLazyImportLoader( - () => import("../browser-lifecycle-cleanup.js"), + () => import("../../../browser-lifecycle-cleanup.js"), ); export async function loadCleanupBrowserSessionsForLifecycleEnd(): Promise< diff --git a/src/agents/subagent-registry-lifecycle-completion.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-completion.ts similarity index 97% rename from src/agents/subagent-registry-lifecycle-completion.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-completion.ts index 69878108aa48..55a172fba2e1 100644 --- a/src/agents/subagent-registry-lifecycle-completion.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-completion.ts @@ -1,11 +1,17 @@ -import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; -import { isAgentEventLifecycleGenerationCurrent } from "../infra/agent-events.js"; -import { emitSessionLifecycleEvent } from "../sessions/session-lifecycle-events.js"; -import { recordSubagentTerminalState } from "../sessions/session-state-events.js"; -import type { DetachedTaskFindResult } from "../tasks/detached-task-runtime-contract.js"; -import { isProvisionalSubagentKillTask } from "../tasks/task-cancellation-state.js"; -import { mergeAgentRunTerminalReplySnapshot } from "./agent-run-terminal-reply.js"; -import { type SubagentRunOutcome, withSubagentOutcomeTiming } from "./subagent-announce-output.js"; +import { SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js"; +import { isAgentEventLifecycleGenerationCurrent } from "../../../infra/agent-events.js"; +import { emitSessionLifecycleEvent } from "../../../sessions/session-lifecycle-events.js"; +import { recordSubagentTerminalState } from "../../../sessions/session-state-events.js"; +import type { DetachedTaskFindResult } from "../../../tasks/detached-task-runtime-contract.js"; +import { isProvisionalSubagentKillTask } from "../../../tasks/task-cancellation-state.js"; +import { mergeAgentRunTerminalReplySnapshot } from "../../agent-run-terminal-reply.js"; +import { peekSwarmStructuredOutput } from "../../tools/structured-output-tool.js"; +import { + type SubagentRunOutcome, + withSubagentOutcomeTiming, +} from "../announce/subagent-announce-output.js"; +import { updateSwarmCollectorCompletion } from "../swarm/swarm-collector.js"; +import { releaseSwarmRun } from "../swarm/swarm-scheduler.js"; import { clearDeliveryState, ensureCompletionState } from "./subagent-delivery-state.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, @@ -33,9 +39,6 @@ import type { import type { createSubagentRegistryLifecycleDelivery } from "./subagent-registry-lifecycle-delivery.js"; import { createSubagentRegistryLifecycleTerminalCleanup } from "./subagent-registry-lifecycle-terminal-cleanup.js"; import type { SubagentCompletionRequest, SubagentRunRecord } from "./subagent-registry.types.js"; -import { updateSwarmCollectorCompletion } from "./subagents/swarm/swarm-collector.js"; -import { releaseSwarmRun } from "./subagents/swarm/swarm-scheduler.js"; -import { peekSwarmStructuredOutput } from "./tools/structured-output-tool.js"; export function createSubagentRegistryLifecycleCompletion( params: SubagentRegistryLifecycleParams, diff --git a/src/agents/subagent-registry-lifecycle-contracts.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-contracts.ts similarity index 81% rename from src/agents/subagent-registry-lifecycle-contracts.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-contracts.ts index 76509dcb70c6..baa9a362e36f 100644 --- a/src/agents/subagent-registry-lifecycle-contracts.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-contracts.ts @@ -1,15 +1,16 @@ -import type { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { callGateway as defaultCallGateway } from "../gateway/call.js"; -import type { DetachedTaskFindResult } from "../tasks/detached-task-runtime-contract.js"; +import type { cleanupBrowserSessionsForLifecycleEnd } from "../../../browser-lifecycle-cleanup.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { callGateway as defaultCallGateway } from "../../../gateway/call.js"; +import type { DetachedTaskFindResult } from "../../../tasks/detached-task-runtime-contract.js"; import type { SubagentLifecycleEndedReason } from "./subagent-lifecycle-events.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; type CaptureSubagentCompletionReply = - (typeof import("./subagent-announce.js"))["captureSubagentCompletionReply"]; -type RunSubagentAnnounceFlow = (typeof import("./subagent-announce.js"))["runSubagentAnnounceFlow"]; + (typeof import("../announce/subagent-announce.js"))["captureSubagentCompletionReply"]; +type RunSubagentAnnounceFlow = + (typeof import("../announce/subagent-announce.js"))["runSubagentAnnounceFlow"]; type MaybeWakeRequesterAfterAllChildrenSettled = - (typeof import("./subagent-announce.requester-settle-wake.js"))["maybeWakeRequesterAfterAllChildrenSettled"]; + (typeof import("../announce/subagent-announce.requester-settle-wake.js"))["maybeWakeRequesterAfterAllChildrenSettled"]; export type SubagentRegistryLifecycleParams = { runs: Map; resumedRuns: Set; diff --git a/src/agents/subagent-registry-lifecycle-delivery.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-delivery.ts similarity index 94% rename from src/agents/subagent-registry-lifecycle-delivery.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-delivery.ts index 527192e4fd3a..7366c6619494 100644 --- a/src/agents/subagent-registry-lifecycle-delivery.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-delivery.ts @@ -1,27 +1,27 @@ import { uniqueStrings } from "@openclaw/normalization-core/string-normalization"; -import { resolveStorePath } from "../config/sessions/paths.js"; +import { resolveStorePath } from "../../../config/sessions/paths.js"; import { loadSessionEntryReadOnly, type SessionTranscriptRuntimeTarget, -} from "../config/sessions/session-accessor.js"; -import { resolveSessionStorePathForScope } from "../config/sessions/session-store-path.js"; -import { resolveAgentIdFromSessionKey } from "../routing/session-key.js"; -import { extractTextFromChatContent } from "../shared/chat-content.js"; -import type { DetachedTaskFindResult } from "../tasks/detached-task-runtime-contract.js"; +} from "../../../config/sessions/session-accessor.js"; +import { resolveSessionStorePathForScope } from "../../../config/sessions/session-store-path.js"; +import { resolveAgentIdFromSessionKey } from "../../../routing/session-key.js"; +import { extractTextFromChatContent } from "../../../shared/chat-content.js"; +import type { DetachedTaskFindResult } from "../../../tasks/detached-task-runtime-contract.js"; import { completeTaskRunByRunId, failTaskRunByRunId, setDetachedTaskDeliveryStatusByRunId, -} from "../tasks/detached-task-runtime.js"; -import { resolveRequiredCompletionDeliveryFailureTerminalResult } from "../tasks/task-completion-contract.js"; +} from "../../../tasks/detached-task-runtime.js"; +import { resolveRequiredCompletionDeliveryFailureTerminalResult } from "../../../tasks/task-completion-contract.js"; import { buildAnnounceIdFromChildRun, buildAnnounceIdempotencyKey, -} from "./announce-idempotency.js"; -import { isSilentAgentReplyText } from "./embedded-agent-runner/message-visibility.js"; -import type { SubagentAnnounceDeliveryResult } from "./subagent-announce-dispatch.js"; -import type { SubagentRunOutcome } from "./subagent-announce-output.js"; -import { resolveSubagentCompletionResultText } from "./subagent-completion-result.js"; +} from "../../announce-idempotency.js"; +import { isSilentAgentReplyText } from "../../embedded-agent-runner/message-visibility.js"; +import type { SubagentAnnounceDeliveryResult } from "../announce/subagent-announce-dispatch.js"; +import type { SubagentRunOutcome } from "../announce/subagent-announce-output.js"; +import { resolveSubagentCompletionResultText } from "../completion/subagent-completion-result.js"; import { clearDeliveryState, ensureCompletionState, diff --git a/src/agents/subagent-registry-lifecycle-requester-wake.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-requester-wake.ts similarity index 97% rename from src/agents/subagent-registry-lifecycle-requester-wake.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-requester-wake.ts index f8dd88a4272d..6abfc0dda93e 100644 --- a/src/agents/subagent-registry-lifecycle-requester-wake.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle-requester-wake.ts @@ -1,5 +1,5 @@ -import { runWithoutOwnedSessionTranscriptWrites } from "../config/sessions/transcript-write-context.js"; -import { runWithGatewayIndependentRootWorkContinuation } from "../process/gateway-work-admission.js"; +import { runWithoutOwnedSessionTranscriptWrites } from "../../../config/sessions/transcript-write-context.js"; +import { runWithGatewayIndependentRootWorkContinuation } from "../../../process/gateway-work-admission.js"; import type { createSubagentRegistryLifecycleCommon } from "./subagent-registry-lifecycle-common.js"; import type { SubagentRegistryLifecycleParams, @@ -9,7 +9,7 @@ import type { RequesterSettleWakeState, SubagentRunRecord } from "./subagent-reg import { hasSubagentRunEnded } from "./subagent-run-liveness.js"; type RequesterSettleWakeBatchState = - import("./subagent-announce.requester-settle-wake.js").RequesterSettleWakeBatchState; + import("../announce/subagent-announce.requester-settle-wake.js").RequesterSettleWakeBatchState; export function createSubagentRegistryLifecycleRequesterWake( params: SubagentRegistryLifecycleParams, diff --git a/src/agents/subagent-registry-lifecycle-terminal-cleanup.ts b/src/agents/subagents/registry/subagent-registry-lifecycle-terminal-cleanup.ts similarity index 100% rename from src/agents/subagent-registry-lifecycle-terminal-cleanup.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle-terminal-cleanup.ts diff --git a/src/agents/subagent-registry-lifecycle.test.ts b/src/agents/subagents/registry/subagent-registry-lifecycle.test.ts similarity index 99% rename from src/agents/subagent-registry-lifecycle.test.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle.test.ts index 7167a3af77b6..fa8bfb020649 100644 --- a/src/agents/subagent-registry-lifecycle.test.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle.test.ts @@ -1,13 +1,13 @@ // Subagent registry lifecycle tests cover completion, cleanup, announce retry, // detached task status, and resource retirement around child-run endings. import { beforeEach, describe, expect, it, vi } from "vitest"; -import { resolveSessionStorePathForScope } from "../config/sessions/session-store-path.js"; +import { resolveSessionStorePathForScope } from "../../../config/sessions/session-store-path.js"; import { runWithOwnedSessionTranscriptWrite, withOwnedSessionTranscriptWrites, -} from "../config/sessions/transcript-write-context.js"; -import type { CallGatewayOptions } from "../gateway/call.js"; -import { getAgentEventLifecycleGeneration } from "../infra/agent-events.js"; +} from "../../../config/sessions/transcript-write-context.js"; +import type { CallGatewayOptions } from "../../../gateway/call.js"; +import { getAgentEventLifecycleGeneration } from "../../../infra/agent-events.js"; import { getActiveGatewayRootWorkCount, markGatewayRestartDraining, @@ -15,13 +15,14 @@ import { runWithGatewayIndependentRootWorkAdmission, tryBeginGatewaySuspendAdmission, waitForActiveGatewayRootWork, -} from "../process/gateway-work-admission.js"; -import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js"; +} from "../../../process/gateway-work-admission.js"; +import { SUBAGENT_KILL_TASK_ERROR } from "../../../tasks/detached-task-runtime-contract.js"; import { buildAnnounceIdFromChildRun, buildAnnounceIdempotencyKey, -} from "./announce-idempotency.js"; -import type { SubagentAnnounceDeliveryResult } from "./subagent-announce-dispatch.js"; +} from "../../announce-idempotency.js"; +import { createStructuredOutputTool } from "../../tools/structured-output-tool.js"; +import type { SubagentAnnounceDeliveryResult } from "../announce/subagent-announce-dispatch.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, @@ -31,7 +32,6 @@ import { shouldSuppressSubagentRecoverySessionEffects } from "./subagent-recover import { createSubagentRegistryLifecycleController } from "./subagent-registry-lifecycle.js"; import { markSubagentRunPausedAfterYield } from "./subagent-registry-run-manager.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { createStructuredOutputTool } from "./tools/structured-output-tool.js"; type LifecycleControllerParams = Parameters[0]; type LifecycleController = ReturnType; @@ -122,17 +122,17 @@ const sessionReconciliationMocks = vi.hoisted(() => ({ loadSubagentSessionEntry: vi.fn(), })); -vi.mock("../tasks/detached-task-runtime.js", () => ({ +vi.mock("../../../tasks/detached-task-runtime.js", () => ({ completeTaskRunByRunId: taskExecutorMocks.completeTaskRunByRunId, failTaskRunByRunId: taskExecutorMocks.failTaskRunByRunId, setDetachedTaskDeliveryStatusByRunId: taskExecutorMocks.setDetachedTaskDeliveryStatusByRunId, })); -vi.mock("../sessions/session-lifecycle-events.js", () => ({ +vi.mock("../../../sessions/session-lifecycle-events.js", () => ({ emitSessionLifecycleEvent: lifecycleEventMocks.emitSessionLifecycleEvent, })); -vi.mock("../browser-lifecycle-cleanup.js", () => ({ +vi.mock("../../../browser-lifecycle-cleanup.js", () => ({ cleanupBrowserSessionsForLifecycleEnd: browserLifecycleCleanupMocks.cleanupBrowserSessionsForLifecycleEnd, })); @@ -143,11 +143,11 @@ vi.mock("./subagent-registry-lifecycle-completion-support.js", async (importOrig completionSupportMocks.loadCleanupBrowserSessionsForLifecycleEnd, })); -vi.mock("./agent-bundle-mcp-tools.js", () => ({ +vi.mock("../../agent-bundle-mcp-tools.js", () => ({ retireSessionMcpRuntimeForSessionKey: bundleMcpRuntimeMocks.retireSessionMcpRuntimeForSessionKey, })); -vi.mock("./internal-session-effects.js", () => ({ +vi.mock("../../internal-session-effects.js", () => ({ removeInternalSessionEffectsSession: internalSessionEffectsMocks.removeInternalSessionEffectsSession, })); @@ -157,17 +157,17 @@ vi.mock("./subagent-session-reconciliation.js", async (importOriginal) => ({ loadSubagentSessionEntry: sessionReconciliationMocks.loadSubagentSessionEntry, })); -vi.mock("../runtime.js", () => ({ +vi.mock("../../../runtime.js", () => ({ defaultRuntime: { log: runtimeMocks.log, }, })); -vi.mock("../utils/delivery-context.shared.js", () => ({ +vi.mock("../../../utils/delivery-context.shared.js", () => ({ normalizeDeliveryContext: (origin: unknown) => origin ?? "agent", })); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ captureSubagentCompletionReply: vi.fn(async () => undefined), runSubagentAnnounceFlow: vi.fn(async () => false), })); diff --git a/src/agents/subagent-registry-lifecycle.ts b/src/agents/subagents/registry/subagent-registry-lifecycle.ts similarity index 95% rename from src/agents/subagent-registry-lifecycle.ts rename to src/agents/subagents/registry/subagent-registry-lifecycle.ts index faf235a6b43b..6cdbb252fa67 100644 --- a/src/agents/subagent-registry-lifecycle.ts +++ b/src/agents/subagents/registry/subagent-registry-lifecycle.ts @@ -1,10 +1,10 @@ -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../../process/gateway-work-admission.js"; /** * Subagent registry lifecycle transitions. * * Completes/fails task runs, clears delivery state, emits lifecycle events, and cleans attached resources. */ -import type { AcceptedSessionSpawn } from "./accepted-session-spawn.js"; +import type { AcceptedSessionSpawn } from "../../accepted-session-spawn.js"; import { createSubagentRegistryLifecycleCleanupBase } from "./subagent-registry-lifecycle-cleanup-base.js"; import { createSubagentRegistryLifecycleCleanup } from "./subagent-registry-lifecycle-cleanup.js"; import { createSubagentRegistryLifecycleCommon } from "./subagent-registry-lifecycle-common.js"; diff --git a/src/agents/subagent-registry-listener.ts b/src/agents/subagents/registry/subagent-registry-listener.ts similarity index 94% rename from src/agents/subagent-registry-listener.ts rename to src/agents/subagents/registry/subagent-registry-listener.ts index 8a3ac57e113c..84880a0e2523 100644 --- a/src/agents/subagent-registry-listener.ts +++ b/src/agents/subagents/registry/subagent-registry-listener.ts @@ -1,13 +1,13 @@ -import type { AgentEventPayload } from "../infra/agent-events.js"; -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; +import type { AgentEventPayload } from "../../../infra/agent-events.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../../process/gateway-work-admission.js"; import { formatAbandonedLivenessError, formatBlockedLivenessError, isAbandonedLivenessState, isBlockedLivenessState, -} from "../shared/agent-liveness.js"; -import { normalizeAgentRunTerminalReplySnapshot } from "./agent-run-terminal-reply.js"; -import { isAbortedAgentStopReason } from "./run-termination.js"; +} from "../../../shared/agent-liveness.js"; +import { normalizeAgentRunTerminalReplySnapshot } from "../../agent-run-terminal-reply.js"; +import { isAbortedAgentStopReason } from "../../run-termination.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, diff --git a/src/agents/subagent-registry-maintenance.ts b/src/agents/subagents/registry/subagent-registry-maintenance.ts similarity index 97% rename from src/agents/subagent-registry-maintenance.ts rename to src/agents/subagents/registry/subagent-registry-maintenance.ts index 51020e77343a..9fde2d0dded1 100644 --- a/src/agents/subagent-registry-maintenance.ts +++ b/src/agents/subagents/registry/subagent-registry-maintenance.ts @@ -3,7 +3,7 @@ * Preserves child session keys while runs are active, pending delivery, or * awaiting completion announces so pruning cannot delete needed transcripts. */ -import { registerSessionMaintenancePreserveKeysProvider } from "../config/sessions/store-maintenance-preserve.js"; +import { registerSessionMaintenancePreserveKeysProvider } from "../../../config/sessions/store-maintenance-preserve.js"; import { isDeliverySuspended } from "./subagent-delivery-state.js"; import { subagentRuns } from "./subagent-registry-memory.js"; import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js"; diff --git a/src/agents/subagent-registry-memory.test.ts b/src/agents/subagents/registry/subagent-registry-memory.test.ts similarity index 100% rename from src/agents/subagent-registry-memory.test.ts rename to src/agents/subagents/registry/subagent-registry-memory.test.ts diff --git a/src/agents/subagent-registry-memory.ts b/src/agents/subagents/registry/subagent-registry-memory.ts similarity index 100% rename from src/agents/subagent-registry-memory.ts rename to src/agents/subagents/registry/subagent-registry-memory.ts diff --git a/src/agents/subagent-registry-pending-lifecycle.ts b/src/agents/subagents/registry/subagent-registry-pending-lifecycle.ts similarity index 100% rename from src/agents/subagent-registry-pending-lifecycle.ts rename to src/agents/subagents/registry/subagent-registry-pending-lifecycle.ts diff --git a/src/agents/subagent-registry-public-api.ts b/src/agents/subagents/registry/subagent-registry-public-api.ts similarity index 99% rename from src/agents/subagent-registry-public-api.ts rename to src/agents/subagents/registry/subagent-registry-public-api.ts index 2b2fdae07903..b1e7d4133c4a 100644 --- a/src/agents/subagent-registry-public-api.ts +++ b/src/agents/subagents/registry/subagent-registry-public-api.ts @@ -2,7 +2,7 @@ import { ackLeasedAgentSteeringItemsFromSubagentRuns, leasePendingAgentSteeringItemsFromSubagentRuns, releaseLeasedAgentSteeringItemsFromSubagentRuns, -} from "./agent-steering-queue.js"; +} from "../../agent-steering-queue.js"; import type { SubagentRegistryDeps } from "./subagent-registry-deps.js"; import type { createSubagentRegistryLifecycleController } from "./subagent-registry-lifecycle.js"; import { getSubagentRunsForChildSession } from "./subagent-registry-memory.js"; diff --git a/src/agents/subagent-registry-queries.test.ts b/src/agents/subagents/registry/subagent-registry-queries.test.ts similarity index 99% rename from src/agents/subagent-registry-queries.test.ts rename to src/agents/subagents/registry/subagent-registry-queries.test.ts index 7749c1225a9e..6ab79b569bf0 100644 --- a/src/agents/subagent-registry-queries.test.ts +++ b/src/agents/subagents/registry/subagent-registry-queries.test.ts @@ -1,6 +1,10 @@ // Subagent registry query tests cover liveness, descendant counting, requester // lookup, and stale-row handling for in-memory run snapshots. import { describe, expect, it } from "vitest"; +import { + createSubagentRunRecord, + type SubagentRunRecordOverrides, +} from "../../subagent-test-fixtures.test-helpers.js"; import { countActiveRunsForSessionFromRuns, countPendingDescendantRunsExcludingRunFromRuns, @@ -13,10 +17,6 @@ import { shouldIgnorePostCompletionAnnounceForSessionFromRuns, } from "./subagent-registry-queries.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { - createSubagentRunRecord, - type SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; const STALE_UNENDED_SUBAGENT_RUN_MS = 2 * 60 * 60 * 1_000; diff --git a/src/agents/subagent-registry-queries.ts b/src/agents/subagents/registry/subagent-registry-queries.ts similarity index 99% rename from src/agents/subagent-registry-queries.ts rename to src/agents/subagents/registry/subagent-registry-queries.ts index ad0c3a04acd8..51b7a8c62198 100644 --- a/src/agents/subagent-registry-queries.ts +++ b/src/agents/subagents/registry/subagent-registry-queries.ts @@ -3,7 +3,7 @@ * * Keeps tree traversal and filtering independent from persistence and mutable process state. */ -import type { DeliveryContext } from "../utils/delivery-context.types.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; import { isDeliverySuspended } from "./subagent-delivery-state.js"; import type { SubagentRunReadRecord, SubagentRunRecord } from "./subagent-registry.types.js"; import { compareSubagentRunGeneration } from "./subagent-run-generation.js"; diff --git a/src/agents/subagent-registry-read-context.test.ts b/src/agents/subagents/registry/subagent-registry-read-context.test.ts similarity index 99% rename from src/agents/subagent-registry-read-context.test.ts rename to src/agents/subagents/registry/subagent-registry-read-context.test.ts index 79f0b46fd649..a39a5d425339 100644 --- a/src/agents/subagent-registry-read-context.test.ts +++ b/src/agents/subagents/registry/subagent-registry-read-context.test.ts @@ -1,6 +1,10 @@ // Subagent registry read-context tests cover the indexed snapshot used by hot // prompt/control paths instead of repeatedly scanning the run map. import { describe, expect, it } from "vitest"; +import { + createSubagentRunRecord, + type SubagentRunRecordOverrides, +} from "../../subagent-test-fixtures.test-helpers.js"; import { buildLatestSubagentRunReadIndexFromRuns, buildSubagentRunReadIndexFromRuns, @@ -14,10 +18,6 @@ import { type SubagentRunReadIndex, } from "./subagent-registry-queries.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { - createSubagentRunRecord, - type SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; function makeRun(overrides: Partial): SubagentRunRecord { const runId = overrides.runId ?? "run-default"; diff --git a/src/agents/subagent-registry-read.scoped.test.ts b/src/agents/subagents/registry/subagent-registry-read.scoped.test.ts similarity index 100% rename from src/agents/subagent-registry-read.scoped.test.ts rename to src/agents/subagents/registry/subagent-registry-read.scoped.test.ts diff --git a/src/agents/subagent-registry-read.ts b/src/agents/subagents/registry/subagent-registry-read.ts similarity index 98% rename from src/agents/subagent-registry-read.ts rename to src/agents/subagents/registry/subagent-registry-read.ts index 797110073d74..4b28e9a7c547 100644 --- a/src/agents/subagent-registry-read.ts +++ b/src/agents/subagents/registry/subagent-registry-read.ts @@ -3,7 +3,7 @@ * * Combines persisted snapshots with in-memory live runs for UI, announce, control, and recovery paths. */ -import { getAgentRunContext } from "../infra/agent-run-registry.js"; +import { getAgentRunContext } from "../../../infra/agent-run-registry.js"; import { getSubagentRunsForChildSession, subagentRuns } from "./subagent-registry-memory.js"; import { buildLatestSubagentRunReadIndexFromRuns, diff --git a/src/agents/subagent-registry-requester-yield.test.ts b/src/agents/subagents/registry/subagent-registry-requester-yield.test.ts similarity index 100% rename from src/agents/subagent-registry-requester-yield.test.ts rename to src/agents/subagents/registry/subagent-registry-requester-yield.test.ts diff --git a/src/agents/subagent-registry-requester-yield.ts b/src/agents/subagents/registry/subagent-registry-requester-yield.ts similarity index 98% rename from src/agents/subagent-registry-requester-yield.ts rename to src/agents/subagents/registry/subagent-registry-requester-yield.ts index 07534337f846..4208bd177ab2 100644 --- a/src/agents/subagent-registry-requester-yield.ts +++ b/src/agents/subagents/registry/subagent-registry-requester-yield.ts @@ -1,5 +1,5 @@ /** Settles durable child ownership when the spawning requester turn ends. */ -import type { AcceptedSessionSpawn } from "./accepted-session-spawn.js"; +import type { AcceptedSessionSpawn } from "../../accepted-session-spawn.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; /** Persists explicit yield intent before the requester run is aborted. */ diff --git a/src/agents/subagent-registry-restart-recovery-coordinator.ts b/src/agents/subagents/registry/subagent-registry-restart-recovery-coordinator.ts similarity index 98% rename from src/agents/subagent-registry-restart-recovery-coordinator.ts rename to src/agents/subagents/registry/subagent-registry-restart-recovery-coordinator.ts index bafa1144d886..0288379d8bb5 100644 --- a/src/agents/subagent-registry-restart-recovery-coordinator.ts +++ b/src/agents/subagents/registry/subagent-registry-restart-recovery-coordinator.ts @@ -1,4 +1,4 @@ -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; import { getLatestSubagentRunByChildSessionKeyFromRuns } from "./subagent-registry-queries.js"; import type { RestartRecoveryParams, diff --git a/src/agents/subagent-registry-restart-recovery-helpers.ts b/src/agents/subagents/registry/subagent-registry-restart-recovery-helpers.ts similarity index 92% rename from src/agents/subagent-registry-restart-recovery-helpers.ts rename to src/agents/subagents/registry/subagent-registry-restart-recovery-helpers.ts index 84017d7b676e..9df99fd9aa9e 100644 --- a/src/agents/subagent-registry-restart-recovery-helpers.ts +++ b/src/agents/subagents/registry/subagent-registry-restart-recovery-helpers.ts @@ -1,7 +1,7 @@ import { createHash } from "node:crypto"; -import { loadSessionEntry } from "../config/sessions/session-accessor.js"; -import * as agentEvents from "../infra/agent-events.js"; -import { truncateUtf16Safe } from "../utils.js"; +import { loadSessionEntry } from "../../../config/sessions/session-accessor.js"; +import * as agentEvents from "../../../infra/agent-events.js"; +import { truncateUtf16Safe } from "../../../utils.js"; import type { SubagentRestartRecoveryReceipt, SubagentRunRecord, diff --git a/src/agents/subagent-registry-restart-recovery-session.ts b/src/agents/subagents/registry/subagent-registry-restart-recovery-session.ts similarity index 94% rename from src/agents/subagent-registry-restart-recovery-session.ts rename to src/agents/subagents/registry/subagent-registry-restart-recovery-session.ts index fa00b65707d4..3552b2a8a981 100644 --- a/src/agents/subagent-registry-restart-recovery-session.ts +++ b/src/agents/subagents/registry/subagent-registry-restart-recovery-session.ts @@ -1,4 +1,4 @@ -import { patchSessionEntry } from "../config/sessions/session-accessor.js"; +import { patchSessionEntry } from "../../../config/sessions/session-accessor.js"; export async function settleAcceptedRecoverySession(params: { attempts: number; diff --git a/src/agents/subagent-registry-restart-recovery.test.ts b/src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts similarity index 98% rename from src/agents/subagent-registry-restart-recovery.test.ts rename to src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts index 31acca7fff7f..6dadf57ba242 100644 --- a/src/agents/subagent-registry-restart-recovery.test.ts +++ b/src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts @@ -1,18 +1,18 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { SessionEntry } from "../config/sessions/types.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { rotateAgentEventLifecycleGeneration } from "../infra/agent-events.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; +import { rotateAgentEventLifecycleGeneration } from "../../../infra/agent-events.js"; import { consumeSessionWorkAdmissionHandoff, type SessionWorkAdmissionLease, -} from "../sessions/session-lifecycle-admission.js"; -import { getLatestSubagentRunByChildSessionKeyFromRuns } from "./subagent-registry-queries.js"; -import { recoverInterruptedSubagentRow } from "./subagent-registry-restart-recovery.js"; -import type { SubagentRunRecord } from "./subagent-registry.types.js"; +} from "../../../sessions/session-lifecycle-admission.js"; import { createSubagentRunRecord, type SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; +} from "../../subagent-test-fixtures.test-helpers.js"; +import { getLatestSubagentRunByChildSessionKeyFromRuns } from "./subagent-registry-queries.js"; +import { recoverInterruptedSubagentRow } from "./subagent-registry-restart-recovery.js"; +import type { SubagentRunRecord } from "./subagent-registry.types.js"; const mocks = vi.hoisted(() => ({ entries: {} as Record, @@ -21,18 +21,18 @@ const mocks = vi.hoisted(() => ({ readSessionMessages: vi.fn(async () => [] as unknown[]), })); -vi.mock("../config/config.js", () => ({ +vi.mock("../../../config/config.js", () => ({ getRuntimeConfig: () => ({ session: { store: undefined } }), })); -vi.mock("../config/sessions.js", () => ({ +vi.mock("../../../config/sessions.js", () => ({ resolveAgentIdFromSessionKey: () => "main", resolveStorePath: () => "/tmp/subagent-recovery.sqlite", })); -vi.mock("../config/sessions/session-accessor.js", () => ({ +vi.mock("../../../config/sessions/session-accessor.js", () => ({ loadSessionEntry: mocks.loadSessionEntry, patchSessionEntry: mocks.patchSessionEntry, })); -vi.mock("../gateway/session-transcript-readers.js", () => ({ +vi.mock("../../../gateway/session-transcript-readers.js", () => ({ extractMessageRole: (message: { role?: string }) => message?.role, extractMessageText: (message: { content?: string }) => message?.content ?? null, readSessionMessagesAsync: mocks.readSessionMessages, diff --git a/src/agents/subagent-registry-restart-recovery.ts b/src/agents/subagents/registry/subagent-registry-restart-recovery.ts similarity index 97% rename from src/agents/subagent-registry-restart-recovery.ts rename to src/agents/subagents/registry/subagent-registry-restart-recovery.ts index 8abfce141778..9bdbe4316199 100644 --- a/src/agents/subagent-registry-restart-recovery.ts +++ b/src/agents/subagents/registry/subagent-registry-restart-recovery.ts @@ -1,19 +1,19 @@ -import { getRuntimeConfig } from "../config/config.js"; -import { resolveAgentIdFromSessionKey, resolveStorePath } from "../config/sessions.js"; -import { loadSessionEntry, patchSessionEntry } from "../config/sessions/session-accessor.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; +import { getRuntimeConfig } from "../../../config/config.js"; +import { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js"; +import { loadSessionEntry, patchSessionEntry } from "../../../config/sessions/session-accessor.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; import { extractMessageRole, extractMessageText, readSessionMessagesAsync, -} from "../gateway/session-transcript-readers.js"; -import * as agentEvents from "../infra/agent-events.js"; -import { formatErrorMessage } from "../infra/errors.js"; +} from "../../../gateway/session-transcript-readers.js"; +import * as agentEvents from "../../../infra/agent-events.js"; +import { formatErrorMessage } from "../../../infra/errors.js"; import { beginSessionWorkAdmission, cancelSessionWorkAdmissionHandoff, -} from "../sessions/session-lifecycle-admission.js"; -import { resolveInternalSessionEffectsTarget } from "./internal-session-effects.js"; +} from "../../../sessions/session-lifecycle-admission.js"; +import { resolveInternalSessionEffectsTarget } from "../../internal-session-effects.js"; import { formatSubagentRecoveryWedgedReason, isSubagentRecoveryWedgedEntry, diff --git a/src/agents/subagent-registry-restore.ts b/src/agents/subagents/registry/subagent-registry-restore.ts similarity index 96% rename from src/agents/subagent-registry-restore.ts rename to src/agents/subagents/registry/subagent-registry-restore.ts index c73cd3786bcb..d9ad68fac88e 100644 --- a/src/agents/subagent-registry-restore.ts +++ b/src/agents/subagents/registry/subagent-registry-restore.ts @@ -1,14 +1,18 @@ -import { ADMIN_SCOPE } from "../gateway/method-scopes.js"; +import { ADMIN_SCOPE } from "../../../gateway/method-scopes.js"; import { getAgentEventLifecycleGeneration, isAgentEventLifecycleGenerationCurrent, -} from "../infra/agent-events.js"; +} from "../../../infra/agent-events.js"; import { runWithGatewayIndependentRootWorkAdmission, GatewayDrainingError, -} from "../process/gateway-work-admission.js"; -import { emitSessionLifecycleEvent } from "../sessions/session-lifecycle-events.js"; -import { applySubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; +} from "../../../process/gateway-work-admission.js"; +import { emitSessionLifecycleEvent } from "../../../sessions/session-lifecycle-events.js"; +import { applySubagentLaunchAuthorization } from "../spawn/subagent-launch-authorization.js"; +import { retrySubagentCleanup } from "../spawn/subagent-spawn-cleanup.js"; +import { readGatewayRunId } from "../spawn/subagent-spawn-gateway.js"; +import { resolveSwarmConfig } from "../swarm/swarm-config.js"; +import { enqueueSwarmRun } from "../swarm/swarm-scheduler.js"; import type { SubagentRegistryDeps } from "./subagent-registry-deps.js"; import { reconcileOrphanedRestoredRuns, @@ -21,10 +25,6 @@ import { loadSubagentSessionEntry, type SubagentSessionStoreCache, } from "./subagent-session-reconciliation.js"; -import { retrySubagentCleanup } from "./subagents/spawn/subagent-spawn-cleanup.js"; -import { readGatewayRunId } from "./subagents/spawn/subagent-spawn-gateway.js"; -import { resolveSwarmConfig } from "./subagents/swarm/swarm-config.js"; -import { enqueueSwarmRun } from "./subagents/swarm/swarm-scheduler.js"; type RestoredQueuedFailureSettlementClaim = { entry: SubagentRunRecord; diff --git a/src/agents/subagent-registry-run-manager.ts b/src/agents/subagents/registry/subagent-registry-run-manager.ts similarity index 97% rename from src/agents/subagent-registry-run-manager.ts rename to src/agents/subagents/registry/subagent-registry-run-manager.ts index d1642577705c..41c345e132c5 100644 --- a/src/agents/subagent-registry-run-manager.ts +++ b/src/agents/subagents/registry/subagent-registry-run-manager.ts @@ -3,34 +3,39 @@ * * Waits for child runs, records terminal outcomes, creates task-runtime entries, and archives completed sessions. */ -import { getRuntimeConfig } from "../config/config.js"; -import { runWithoutOwnedSessionTranscriptWrites } from "../config/sessions/transcript-write-context.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { callGateway } from "../gateway/call.js"; +import { getRuntimeConfig } from "../../../config/config.js"; +import { runWithoutOwnedSessionTranscriptWrites } from "../../../config/sessions/transcript-write-context.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { callGateway } from "../../../gateway/call.js"; import { getAgentEventLifecycleGeneration, isAgentEventLifecycleGenerationCurrent, -} from "../infra/agent-events.js"; -import { isFastTestRuntimeEnv } from "../infra/env.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; +} from "../../../infra/agent-events.js"; +import { isFastTestRuntimeEnv } from "../../../infra/env.js"; +import { createSubsystemLogger } from "../../../logging/subsystem.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../../process/gateway-work-admission.js"; import { SUBAGENT_KILL_TASK_ERROR, type DetachedTaskFindResult, -} from "../tasks/detached-task-runtime-contract.js"; +} from "../../../tasks/detached-task-runtime-contract.js"; import { createQueuedTaskRun, createRunningTaskRun, finalizeTaskRunByRunId, startTaskRunByRunId, -} from "../tasks/detached-task-runtime.js"; -import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js"; -import type { DeliveryContext } from "../utils/delivery-context.types.js"; -import { buildAgentRunTerminalOutcomeFromWaitResult } from "./agent-run-terminal-outcome.js"; -import { removeInternalSessionEffectsSession } from "./internal-session-effects.js"; -import type { AgentRunSessionTarget } from "./run-session-target.js"; -import { isRecoverableAgentWaitError, waitForAgentRun } from "./run-wait.js"; -import { type SubagentRunOutcome, withSubagentOutcomeTiming } from "./subagent-announce-output.js"; +} from "../../../tasks/detached-task-runtime.js"; +import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; +import { buildAgentRunTerminalOutcomeFromWaitResult } from "../../agent-run-terminal-outcome.js"; +import { removeInternalSessionEffectsSession } from "../../internal-session-effects.js"; +import type { AgentRunSessionTarget } from "../../run-session-target.js"; +import { isRecoverableAgentWaitError, waitForAgentRun } from "../../run-wait.js"; +import { + type SubagentRunOutcome, + withSubagentOutcomeTiming, +} from "../announce/subagent-announce-output.js"; +import { updateSwarmCollectorCompletion } from "../swarm/swarm-collector.js"; +import { isSwarmRunQueued, removeQueuedSwarmRun } from "../swarm/swarm-scheduler.js"; import { clearDeliveryState, ensureCompletionState, @@ -69,8 +74,6 @@ import { getSubagentSessionStartedAt, } from "./subagent-session-metrics.js"; import type { SubagentSessionCompletion } from "./subagent-session-reconciliation.js"; -import { updateSwarmCollectorCompletion } from "./subagents/swarm/swarm-collector.js"; -import { isSwarmRunQueued, removeQueuedSwarmRun } from "./subagents/swarm/swarm-scheduler.js"; const log = createSubsystemLogger("agents/subagent-registry"); const RECOVERABLE_WAIT_RETRY_DELAY_MS = isFastTestRuntimeEnv() ? 25 : 5_000; diff --git a/src/agents/subagent-registry-runtime.ts b/src/agents/subagents/registry/subagent-registry-runtime.ts similarity index 100% rename from src/agents/subagent-registry-runtime.ts rename to src/agents/subagents/registry/subagent-registry-runtime.ts diff --git a/src/agents/subagent-registry-state.test.ts b/src/agents/subagents/registry/subagent-registry-state.test.ts similarity index 100% rename from src/agents/subagent-registry-state.test.ts rename to src/agents/subagents/registry/subagent-registry-state.test.ts diff --git a/src/agents/subagent-registry-state.ts b/src/agents/subagents/registry/subagent-registry-state.ts similarity index 99% rename from src/agents/subagent-registry-state.ts rename to src/agents/subagents/registry/subagent-registry-state.ts index 52152ec4ab84..388574907922 100644 --- a/src/agents/subagent-registry-state.ts +++ b/src/agents/subagents/registry/subagent-registry-state.ts @@ -1,4 +1,4 @@ -import { isVitestRuntimeEnv } from "../infra/env.js"; +import { isVitestRuntimeEnv } from "../../../infra/env.js"; /** * Subagent registry state persistence bridge. * diff --git a/src/agents/subagent-registry-suspended-delivery.ts b/src/agents/subagents/registry/subagent-registry-suspended-delivery.ts similarity index 100% rename from src/agents/subagent-registry-suspended-delivery.ts rename to src/agents/subagents/registry/subagent-registry-suspended-delivery.ts diff --git a/src/agents/subagent-registry-sweep-kill.ts b/src/agents/subagents/registry/subagent-registry-sweep-kill.ts similarity index 96% rename from src/agents/subagent-registry-sweep-kill.ts rename to src/agents/subagents/registry/subagent-registry-sweep-kill.ts index 2921ff358d28..dfc395c14f4c 100644 --- a/src/agents/subagent-registry-sweep-kill.ts +++ b/src/agents/subagents/registry/subagent-registry-sweep-kill.ts @@ -1,12 +1,15 @@ -import { getRuntimeConfig } from "../config/config.js"; -import { resolveAgentIdFromSessionKey, resolveStorePath } from "../config/sessions.js"; -import { isAgentEventLifecycleGenerationCurrent } from "../infra/agent-events.js"; -import { getAgentRunContext } from "../infra/agent-run-registry.js"; -import { runExclusiveSessionLifecycleMutation } from "../sessions/session-lifecycle-admission.js"; -import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js"; -import { finalizeTaskRunByRunId, findDetachedTaskRun } from "../tasks/detached-task-runtime.js"; -import { isProvisionalSubagentKillTask } from "../tasks/task-cancellation-state.js"; -import type { TaskRecord } from "../tasks/task-registry.types.js"; +import { getRuntimeConfig } from "../../../config/config.js"; +import { resolveAgentIdFromSessionKey, resolveStorePath } from "../../../config/sessions.js"; +import { isAgentEventLifecycleGenerationCurrent } from "../../../infra/agent-events.js"; +import { getAgentRunContext } from "../../../infra/agent-run-registry.js"; +import { runExclusiveSessionLifecycleMutation } from "../../../sessions/session-lifecycle-admission.js"; +import { SUBAGENT_KILL_TASK_ERROR } from "../../../tasks/detached-task-runtime-contract.js"; +import { + finalizeTaskRunByRunId, + findDetachedTaskRun, +} from "../../../tasks/detached-task-runtime.js"; +import { isProvisionalSubagentKillTask } from "../../../tasks/task-cancellation-state.js"; +import type { TaskRecord } from "../../../tasks/task-registry.types.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, diff --git a/src/agents/subagent-registry-sweeper-recovery.test.ts b/src/agents/subagents/registry/subagent-registry-sweeper-recovery.test.ts similarity index 97% rename from src/agents/subagent-registry-sweeper-recovery.test.ts rename to src/agents/subagents/registry/subagent-registry-sweeper-recovery.test.ts index 854b95ec7c3e..8ef24d032198 100644 --- a/src/agents/subagent-registry-sweeper-recovery.test.ts +++ b/src/agents/subagents/registry/subagent-registry-sweeper-recovery.test.ts @@ -1,12 +1,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { createDeferred } from "../../test/helpers/promise.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { resetGatewayWorkAdmission } from "../process/gateway-work-admission.js"; +import { createDeferred } from "../../../../test/helpers/promise.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; +import { resetGatewayWorkAdmission } from "../../../process/gateway-work-admission.js"; +import { createSubagentRunRecord } from "../../subagent-test-fixtures.test-helpers.js"; import { reconcileDurableSubagentKillIntent } from "./subagent-registry-sweep-kill.js"; import { retireSupersededSubagentRun } from "./subagent-registry-sweeper-retire.js"; import { createSubagentRegistrySweeper } from "./subagent-registry-sweeper.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { createSubagentRunRecord } from "./subagent-test-fixtures.test-helpers.js"; const recoverRow = vi.hoisted(() => vi.fn()); const getAgentRunContext = vi.hoisted(() => vi.fn<(_runId: string) => unknown>(() => undefined)); @@ -32,16 +32,16 @@ vi.mock("./subagent-registry-restart-recovery.js", async (importOriginal) => { recoverInterruptedSubagentRow: recoverRow, }; }); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ isAgentEventLifecycleGenerationCurrent: () => true, })); -vi.mock("../infra/agent-run-registry.js", () => ({ +vi.mock("../../../infra/agent-run-registry.js", () => ({ getAgentRunContext, })); -vi.mock("./internal-session-effects.js", () => ({ +vi.mock("../../internal-session-effects.js", () => ({ removeInternalSessionEffectsSession, })); -vi.mock("../tasks/detached-task-runtime.js", () => detachedTaskRuntime); +vi.mock("../../../tasks/detached-task-runtime.js", () => detachedTaskRuntime); vi.mock("./subagent-control.runtime.js", () => killRuntime); vi.mock("./subagent-session-reconciliation.js", async (importOriginal) => { const actual = await importOriginal(); diff --git a/src/agents/subagent-registry-sweeper-retire.ts b/src/agents/subagents/registry/subagent-registry-sweeper-retire.ts similarity index 95% rename from src/agents/subagent-registry-sweeper-retire.ts rename to src/agents/subagents/registry/subagent-registry-sweeper-retire.ts index 462bab4e54d0..6740c6be93f8 100644 --- a/src/agents/subagent-registry-sweeper-retire.ts +++ b/src/agents/subagents/registry/subagent-registry-sweeper-retire.ts @@ -1,4 +1,4 @@ -import { removeInternalSessionEffectsSession } from "./internal-session-effects.js"; +import { removeInternalSessionEffectsSession } from "../../internal-session-effects.js"; import { shouldSuppressSubagentRecoverySessionEffects } from "./subagent-recovery-state.js"; import { safeRemoveAttachmentsDir } from "./subagent-registry-helpers.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; diff --git a/src/agents/subagent-registry-sweeper.ts b/src/agents/subagents/registry/subagent-registry-sweeper.ts similarity index 97% rename from src/agents/subagent-registry-sweeper.ts rename to src/agents/subagents/registry/subagent-registry-sweeper.ts index 34085c0fb82b..c13de7ed5a1b 100644 --- a/src/agents/subagent-registry-sweeper.ts +++ b/src/agents/subagents/registry/subagent-registry-sweeper.ts @@ -1,10 +1,10 @@ -import type { callGateway } from "../gateway/call.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import { getAgentRunContext } from "../infra/agent-run-registry.js"; -import { isFastTestRuntimeEnv } from "../infra/env.js"; -import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js"; -import { emitSessionLifecycleEvent } from "../sessions/session-lifecycle-events.js"; -import { createLazyImportLoader } from "../shared/lazy-promise.js"; +import type { callGateway } from "../../../gateway/call.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; +import { getAgentRunContext } from "../../../infra/agent-run-registry.js"; +import { isFastTestRuntimeEnv } from "../../../infra/env.js"; +import { runWithGatewayIndependentRootWorkAdmission } from "../../../process/gateway-work-admission.js"; +import { emitSessionLifecycleEvent } from "../../../sessions/session-lifecycle-events.js"; +import { createLazyImportLoader } from "../../../shared/lazy-promise.js"; import { SUBAGENT_ENDED_REASON_ERROR } from "./subagent-lifecycle-events.js"; import { shouldSuppressSubagentRecoverySessionEffects } from "./subagent-recovery-state.js"; import type { createSubagentRegistryCompletionRuntime } from "./subagent-registry-completion-runtime.js"; diff --git a/src/agents/subagent-registry.announce-loop-guard.test.ts b/src/agents/subagents/registry/subagent-registry.announce-loop-guard.test.ts similarity index 97% rename from src/agents/subagent-registry.announce-loop-guard.test.ts rename to src/agents/subagents/registry/subagent-registry.announce-loop-guard.test.ts index bf3d2cc4fadb..b5cf9c794972 100644 --- a/src/agents/subagent-registry.announce-loop-guard.test.ts +++ b/src/agents/subagents/registry/subagent-registry.announce-loop-guard.test.ts @@ -26,11 +26,11 @@ const mocks = vi.hoisted(() => ({ resolveAgentTimeoutMs: vi.fn(() => 60_000), })); -vi.mock("../config/config.js", () => ({ +vi.mock("../../../config/config.js", () => ({ getRuntimeConfig: mocks.getRuntimeConfig, })); -vi.mock("../config/sessions.js", () => ({ +vi.mock("../../../config/sessions.js", () => ({ loadSessionStore: () => sessionStore, resolveAgentIdFromSessionKey: (key: string) => { const match = key.match(/^agent:([^:]+)/); @@ -41,7 +41,7 @@ vi.mock("../config/sessions.js", () => ({ updateSessionStore: mocks.updateSessionStore, })); -vi.mock("../config/sessions/session-accessor.js", () => { +vi.mock("../../../config/sessions/session-accessor.js", () => { const listSessionEntries = () => Object.entries(sessionStore).map(([sessionKey, entry]) => ({ sessionKey, entry })); const loadSessionEntry = (scope: { sessionKey: keyof typeof sessionStore }) => @@ -55,11 +55,11 @@ vi.mock("../config/sessions/session-accessor.js", () => { }; }); -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: mocks.callGateway, })); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ getAgentEventLifecycleGeneration: () => "test-generation", isAgentEventLifecycleGenerationCurrent: (generation: string) => generation === "test-generation", onAgentEvent: mocks.onAgentEvent, @@ -72,7 +72,7 @@ vi.mock("./subagent-registry.store.sqlite.js", () => ({ saveSubagentRegistryToSqlite: mocks.saveSubagentRegistryToSqlite, })); -vi.mock("./timeout.js", () => ({ +vi.mock("../../timeout.js", () => ({ resolveAgentTimeoutMs: mocks.resolveAgentTimeoutMs, })); diff --git a/src/agents/subagent-registry.archive.e2e.test.ts b/src/agents/subagents/registry/subagent-registry.archive.e2e.test.ts similarity index 95% rename from src/agents/subagent-registry.archive.e2e.test.ts rename to src/agents/subagents/registry/subagent-registry.archive.e2e.test.ts index 4da3e0e74b88..77f2d753bdc3 100644 --- a/src/agents/subagent-registry.archive.e2e.test.ts +++ b/src/agents/subagents/registry/subagent-registry.archive.e2e.test.ts @@ -4,15 +4,15 @@ import { promises as fs } from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { callGateway } from "../gateway/call.js"; -import { onAgentEvent } from "../infra/agent-events.js"; -import { getAgentRunContext } from "../infra/agent-run-registry.js"; -import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js"; -import { getDetachedTaskLifecycleRuntime } from "../tasks/detached-task-runtime.js"; +import { callGateway } from "../../../gateway/call.js"; +import { onAgentEvent } from "../../../infra/agent-events.js"; +import { getAgentRunContext } from "../../../infra/agent-run-registry.js"; +import { SUBAGENT_KILL_TASK_ERROR } from "../../../tasks/detached-task-runtime-contract.js"; +import { getDetachedTaskLifecycleRuntime } from "../../../tasks/detached-task-runtime.js"; import { resetDetachedTaskLifecycleRuntimeForTests, setDetachedTaskLifecycleRuntime, -} from "../tasks/task-runtime.test-helpers.js"; +} from "../../../tasks/task-runtime.test-helpers.js"; const taskRuntimeMocks = vi.hoisted(() => ({ finalizeTaskRunByRunId: vi.fn<(_params: unknown) => unknown[]>(() => [{}]), @@ -37,7 +37,7 @@ const flushSweepMicrotasks = async () => { await Promise.resolve(); }; -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: vi.fn(async (request: unknown) => { const method = (request as { method?: string }).method; if (method === "agent.wait") { @@ -48,62 +48,65 @@ vi.mock("../gateway/call.js", () => ({ }), })); -vi.mock("../tasks/detached-task-runtime.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../../../tasks/detached-task-runtime.js", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, finalizeTaskRunByRunId: taskRuntimeMocks.finalizeTaskRunByRunId, }; }); -vi.mock("../tasks/task-status-access.js", () => ({ +vi.mock("../../../tasks/task-status-access.js", () => ({ findTaskByRunIdForStatus: taskStatusMocks.findTaskByRunIdForStatus, listTasksForSessionKeyForStatus: taskStatusMocks.listTasksForSessionKeyForStatus, })); -vi.mock("../config/sessions/session-accessor.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../../../config/sessions/session-accessor.js", async (importOriginal) => { + const actual = + await importOriginal(); return { ...actual, listSessionEntriesReadOnly: sessionAccessorMocks.listSessionEntriesReadOnly, }; }); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ getAgentEventLifecycleGeneration: () => "test-generation", isAgentEventLifecycleGenerationCurrent: (generation: string) => generation === "test-generation", onAgentEvent: vi.fn((_handler: unknown) => noop), registerAgentEventLifecycleRotationHandler: vi.fn(), })); -vi.mock("../infra/agent-run-registry.js", () => ({ +vi.mock("../../../infra/agent-run-registry.js", () => ({ getAgentRunContext: vi.fn(() => undefined), })); -vi.mock("../config/config.js", async () => { - const actual = await vi.importActual("../config/config.js"); +vi.mock("../../../config/config.js", async () => { + const actual = await vi.importActual( + "../../../config/config.js", + ); return { ...actual, getRuntimeConfig: loadConfigMock, }; }); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: vi.fn(async () => true), })); -vi.mock("../plugins/hook-runner-global.js", () => ({ +vi.mock("../../../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: vi.fn(() => null), })); describe("subagent registry archive behavior", () => { let mod: typeof import("./subagent-registry.test-helpers.js"); let createCanonicalSubagentRunFixture: typeof import("./subagent-registry.persistence.test-support.js").createCanonicalSubagentRunFixture; - let createSubagentRunRecord: typeof import("./subagent-test-fixtures.test-helpers.js").createSubagentRunRecord; + let createSubagentRunRecord: typeof import("../../subagent-test-fixtures.test-helpers.js").createSubagentRunRecord; beforeAll(async () => { ({ createCanonicalSubagentRunFixture } = await import("./subagent-registry.persistence.test-support.js")); - ({ createSubagentRunRecord } = await import("./subagent-test-fixtures.test-helpers.js")); + ({ createSubagentRunRecord } = await import("../../subagent-test-fixtures.test-helpers.js")); mod = await import("./subagent-registry.test-helpers.js"); }); @@ -112,7 +115,8 @@ describe("subagent registry archive behavior", () => { ) => { mod.testing.setDepsForTest({ callGateway, - getRuntimeConfig: loadConfigMock as typeof import("../config/config.js").getRuntimeConfig, + getRuntimeConfig: + loadConfigMock as typeof import("../../../config/config.js").getRuntimeConfig, loadAgentRuntimePluginRegistryHandle: vi.fn(), maybeWakeRequesterAfterAllChildrenSettled: vi.fn(async (params) => { params.completeBatch([params.settledEntry.runId]); diff --git a/src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts b/src/agents/subagents/registry/subagent-registry.lifecycle-retry-grace.e2e.test.ts similarity index 94% rename from src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts rename to src/agents/subagents/registry/subagent-registry.lifecycle-retry-grace.e2e.test.ts index b4f36a2d9aff..18fa4ce7deda 100644 --- a/src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts +++ b/src/agents/subagents/registry/subagent-registry.lifecycle-retry-grace.e2e.test.ts @@ -1,13 +1,13 @@ // Lifecycle retry-grace e2e tests cover completion delivery retry behavior when // lifecycle events race gateway waits or transient announce failures. import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { testing as subagentAnnounceDeliveryTesting } from "./subagent-announce-delivery.test-support.js"; -import { testing as subagentAnnounceOutputTesting } from "./subagent-announce-output.test-support.js"; -import { testing as subagentAnnounceTesting } from "./subagent-announce.js"; +import { testing as subagentAnnounceDeliveryTesting } from "../announce/subagent-announce-delivery.test-support.js"; +import { testing as subagentAnnounceOutputTesting } from "../announce/subagent-announce-output.test-support.js"; +import { testing as subagentAnnounceTesting } from "../announce/subagent-announce.js"; import { maybeWakeRequesterAfterAllChildrenSettled, testing as settleWakeTesting, -} from "./subagent-announce.requester-settle-wake.js"; +} from "../announce/subagent-announce.requester-settle-wake.js"; import * as announceRead from "./subagent-registry-announce-read.js"; import * as mod from "./subagent-registry.test-helpers.js"; @@ -100,7 +100,7 @@ const loadConfigMock = vi.fn(() => ({ agents: { defaults: { subagents: { archiveAfterMinutes: 0 } } }, session: { mainKey: "main", scope: "per-sender" }, })); -vi.mock("../config/sessions.js", () => ({ +vi.mock("../../../config/sessions.js", () => ({ loadSessionStore: vi.fn(() => sessionStore), resolveAgentIdFromSessionKey: (key: string) => key.match(/^agent:([^:]+)/)?.[1] ?? "main", resolveStorePath: () => "/tmp/test-store", @@ -110,20 +110,20 @@ vi.mock("../config/sessions.js", () => ({ // The sqlite session accessor bypasses loadSessionStore, so serve session // entries (requester lookups included) from the same in-memory fixture. -vi.mock("../config/sessions/session-accessor.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../../../config/sessions/session-accessor.js", async (importOriginal) => ({ + ...(await importOriginal()), loadSessionEntry: (scope: { sessionKey: string }) => sessionStore[scope.sessionKey], })); -vi.mock("../plugins/hook-runner-global.js", () => ({ +vi.mock("../../../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: vi.fn(() => null), })); -vi.mock("../browser-lifecycle-cleanup.js", () => ({ +vi.mock("../../../browser-lifecycle-cleanup.js", () => ({ cleanupBrowserSessionsForLifecycleEnd: vi.fn(async () => {}), })); -vi.mock("./subagent-depth.js", () => ({ +vi.mock("../spawn/subagent-depth.js", () => ({ getSubagentDepthFromSessionStore: () => 0, })); @@ -181,26 +181,29 @@ describe("subagent registry lifecycle error grace", () => { }, ); mod.testing.setDepsForTest({ - callGateway: callGatewayMock as typeof import("../gateway/call.js").callGateway, - getRuntimeConfig: loadConfigMock as typeof import("../config/config.js").getRuntimeConfig, + callGateway: callGatewayMock as typeof import("../../../gateway/call.js").callGateway, + getRuntimeConfig: + loadConfigMock as typeof import("../../../config/config.js").getRuntimeConfig, loadAgentRuntimePluginRegistryHandle: () => undefined, onAgentEvent: - onAgentEventMock as unknown as typeof import("../infra/agent-events.js").onAgentEvent, + onAgentEventMock as unknown as typeof import("../../../infra/agent-events.js").onAgentEvent, persistSubagentRunsToDisk: noop, persistSubagentRunsToDiskOrThrow: noop, restoreSubagentRunsFromDisk: () => 0, }); subagentAnnounceTesting.setDepsForTest({ - callGateway: callGatewayMock as typeof import("../gateway/call.js").callGateway, - getRuntimeConfig: loadConfigMock as typeof import("../config/config.js").getRuntimeConfig, + callGateway: callGatewayMock as typeof import("../../../gateway/call.js").callGateway, + getRuntimeConfig: + loadConfigMock as typeof import("../../../config/config.js").getRuntimeConfig, loadSubagentRegistryRuntime: loadSubagentRegistryRuntimeForTest, }); settleWakeTesting.setDepsForTest({ loadSubagentRegistryRuntime: loadSubagentRegistryRuntimeForTest, }); subagentAnnounceDeliveryTesting.setDepsForTest({ - callGateway: callGatewayMock as typeof import("../gateway/call.js").callGateway, - getRuntimeConfig: loadConfigMock as typeof import("../config/config.js").getRuntimeConfig, + callGateway: callGatewayMock as typeof import("../../../gateway/call.js").callGateway, + getRuntimeConfig: + loadConfigMock as typeof import("../../../config/config.js").getRuntimeConfig, loadSessionEntry: ({ sessionKey }) => sessionStore[sessionKey], getRequesterSessionActivity: (requesterSessionKey: string) => { const entry = sessionStore[requesterSessionKey]; @@ -211,8 +214,9 @@ describe("subagent registry lifecycle error grace", () => { }, }); subagentAnnounceOutputTesting.setDepsForTest({ - callGateway: callGatewayMock as typeof import("../gateway/call.js").callGateway, - getRuntimeConfig: loadConfigMock as typeof import("../config/config.js").getRuntimeConfig, + callGateway: callGatewayMock as typeof import("../../../gateway/call.js").callGateway, + getRuntimeConfig: + loadConfigMock as typeof import("../../../config/config.js").getRuntimeConfig, readSessionEntry: (_storePath, sessionKey) => sessionStore[sessionKey], resolveAgentIdFromSessionKey: (key) => key?.match(/^agent:([^:]+)/)?.[1] ?? "main", resolveStorePath: () => "/tmp/test-store", diff --git a/src/agents/subagent-registry.mocks.shared.ts b/src/agents/subagents/registry/subagent-registry.mocks.shared.ts similarity index 83% rename from src/agents/subagent-registry.mocks.shared.ts rename to src/agents/subagents/registry/subagent-registry.mocks.shared.ts index 60058d23014b..1acdda1fde5e 100644 --- a/src/agents/subagent-registry.mocks.shared.ts +++ b/src/agents/subagents/registry/subagent-registry.mocks.shared.ts @@ -16,16 +16,16 @@ const sharedMocks = vi.hoisted(() => ({ onAgentEvent: vi.fn(() => noop), })); -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: sharedMocks.callGateway, })); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ getAgentEventLifecycleGeneration: () => "test-generation", isAgentEventLifecycleGenerationCurrent: (generation: string) => generation === "test-generation", onAgentEvent: sharedMocks.onAgentEvent, registerAgentEventLifecycleRotationHandler: vi.fn(), })); -vi.mock("../infra/agent-run-registry.js", () => ({ +vi.mock("../../../infra/agent-run-registry.js", () => ({ getAgentRunContext: () => undefined, })); diff --git a/src/agents/subagent-registry.nested.e2e.test.ts b/src/agents/subagents/registry/subagent-registry.nested.e2e.test.ts similarity index 97% rename from src/agents/subagent-registry.nested.e2e.test.ts rename to src/agents/subagents/registry/subagent-registry.nested.e2e.test.ts index 69e353177ad0..cd34b70ba603 100644 --- a/src/agents/subagent-registry.nested.e2e.test.ts +++ b/src/agents/subagents/registry/subagent-registry.nested.e2e.test.ts @@ -5,8 +5,10 @@ import { expectDefined } from "@openclaw/normalization-core"; import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import "./subagent-registry.mocks.shared.js"; -vi.mock("../config/config.js", async () => { - const actual = await vi.importActual("../config/config.js"); +vi.mock("../../../config/config.js", async () => { + const actual = await vi.importActual( + "../../../config/config.js", + ); return { ...actual, getRuntimeConfig: vi.fn(() => ({ @@ -15,7 +17,7 @@ vi.mock("../config/config.js", async () => { }; }); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: vi.fn(async () => true), buildSubagentSystemPrompt: vi.fn(() => "test prompt"), })); diff --git a/src/agents/subagent-registry.persistence.resume.test.ts b/src/agents/subagents/registry/subagent-registry.persistence.resume.test.ts similarity index 92% rename from src/agents/subagent-registry.persistence.resume.test.ts rename to src/agents/subagents/registry/subagent-registry.persistence.resume.test.ts index 28333f9bcc9c..b42d4f3bf644 100644 --- a/src/agents/subagent-registry.persistence.resume.test.ts +++ b/src/agents/subagents/registry/subagent-registry.persistence.resume.test.ts @@ -4,9 +4,9 @@ import os from "node:os"; import path from "node:path"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import "./subagent-registry.mocks.shared.js"; -import { closeOpenClawStateDatabaseForTest as closeSeedStateDatabase } from "../state/openclaw-state-db.js"; -import { withEnvAsync } from "../test-utils/env.js"; -import { cleanupSessionStateForTest } from "../test-utils/session-state-cleanup.js"; +import { closeOpenClawStateDatabaseForTest as closeSeedStateDatabase } from "../../../state/openclaw-state-db.js"; +import { withEnvAsync } from "../../../test-utils/env.js"; +import { cleanupSessionStateForTest } from "../../../test-utils/session-state-cleanup.js"; import { createSubagentRegistryTestDeps, writeSubagentSessionEntry, @@ -20,13 +20,13 @@ import type { SubagentRunRecord } from "./subagent-registry.types.js"; const { announceSpy } = vi.hoisted(() => ({ announceSpy: vi.fn(async () => true), })); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: announceSpy, })); let mod: typeof import("./subagent-registry.test-helpers.js"); -let callGatewayModule: typeof import("../gateway/call.js"); -let agentEventsModule: typeof import("../infra/agent-events.js"); -let registryStateDbModule: typeof import("../state/openclaw-state-db.js"); +let callGatewayModule: typeof import("../../../gateway/call.js"); +let agentEventsModule: typeof import("../../../infra/agent-events.js"); +let registryStateDbModule: typeof import("../../../state/openclaw-state-db.js"); describe("subagent registry persistence resume", () => { let tempStateDir: string | null = null; @@ -34,9 +34,9 @@ describe("subagent registry persistence resume", () => { beforeAll(async () => { vi.resetModules(); mod = await import("./subagent-registry.test-helpers.js"); - callGatewayModule = await import("../gateway/call.js"); - agentEventsModule = await import("../infra/agent-events.js"); - registryStateDbModule = await import("../state/openclaw-state-db.js"); + callGatewayModule = await import("../../../gateway/call.js"); + agentEventsModule = await import("../../../infra/agent-events.js"); + registryStateDbModule = await import("../../../state/openclaw-state-db.js"); }); beforeEach(() => { diff --git a/src/agents/subagent-registry.persistence.test-support.ts b/src/agents/subagents/registry/subagent-registry.persistence.test-support.ts similarity index 97% rename from src/agents/subagent-registry.persistence.test-support.ts rename to src/agents/subagents/registry/subagent-registry.persistence.test-support.ts index 115966173ec6..839693af8403 100644 --- a/src/agents/subagent-registry.persistence.test-support.ts +++ b/src/agents/subagents/registry/subagent-registry.persistence.test-support.ts @@ -5,13 +5,13 @@ */ import path from "node:path"; import { vi } from "vitest"; -import type { SessionEntry } from "../config/sessions.js"; +import type { SessionEntry } from "../../../config/sessions.js"; import { applySessionEntryLifecycleMutation, listSessionEntries, loadSessionEntry, replaceSessionEntry, -} from "../config/sessions/session-accessor.js"; +} from "../../../config/sessions/session-accessor.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; type SessionStore = Record>; diff --git a/src/agents/subagent-registry.persistence.test.ts b/src/agents/subagents/registry/subagent-registry.persistence.test.ts similarity index 98% rename from src/agents/subagent-registry.persistence.test.ts rename to src/agents/subagents/registry/subagent-registry.persistence.test.ts index d4a61c4ef787..ff8ea0e915cb 100644 --- a/src/agents/subagent-registry.persistence.test.ts +++ b/src/agents/subagents/registry/subagent-registry.persistence.test.ts @@ -6,13 +6,14 @@ import path from "node:path"; import { expectDefined } from "@openclaw/normalization-core"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import "./subagent-registry.mocks.shared.js"; -import { replaceSessionEntry } from "../config/sessions/session-accessor.js"; -import type { SessionEntry } from "../config/sessions/types.js"; -import { callGateway } from "../gateway/call.js"; -import { onAgentEvent } from "../infra/agent-events.js"; -import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js"; -import { captureEnv, setTestEnvValue, withEnv } from "../test-utils/env.js"; -import { cleanupSessionStateForTest } from "../test-utils/session-state-cleanup.js"; +import { replaceSessionEntry } from "../../../config/sessions/session-accessor.js"; +import type { SessionEntry } from "../../../config/sessions/types.js"; +import { callGateway } from "../../../gateway/call.js"; +import { onAgentEvent } from "../../../infra/agent-events.js"; +import { closeOpenClawStateDatabaseForTest } from "../../../state/openclaw-state-db.js"; +import { captureEnv, setTestEnvValue, withEnv } from "../../../test-utils/env.js"; +import { cleanupSessionStateForTest } from "../../../test-utils/session-state-cleanup.js"; +import { createAgentsWaitTool } from "../../tools/agents-wait-tool.js"; import { persistSubagentSessionTiming } from "./subagent-registry-helpers.js"; import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js"; import { @@ -39,12 +40,11 @@ import { resetSubagentRegistryForTests, } from "./subagent-registry.test-helpers.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { createAgentsWaitTool } from "./tools/agents-wait-tool.js"; const { announceSpy } = vi.hoisted(() => ({ announceSpy: vi.fn(async () => true), })); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: announceSpy, })); diff --git a/src/agents/subagents/registry/subagent-registry.runtime.ts b/src/agents/subagents/registry/subagent-registry.runtime.ts new file mode 100644 index 000000000000..babe9c7eec04 --- /dev/null +++ b/src/agents/subagents/registry/subagent-registry.runtime.ts @@ -0,0 +1,5 @@ +/** + * Runtime seams used by subagent registry code for plugin/context-engine initialization. + */ +export { ensureContextEnginesInitialized } from "../../../context-engine/init.js"; +export { resolveContextEngine } from "../../../context-engine/registry.js"; diff --git a/src/agents/subagent-registry.steer-restart.test.ts b/src/agents/subagents/registry/subagent-registry.steer-restart.test.ts similarity index 97% rename from src/agents/subagent-registry.steer-restart.test.ts rename to src/agents/subagents/registry/subagent-registry.steer-restart.test.ts index f08d13d298b2..8a9a3c9f8bdd 100644 --- a/src/agents/subagent-registry.steer-restart.test.ts +++ b/src/agents/subagents/registry/subagent-registry.steer-restart.test.ts @@ -4,10 +4,10 @@ import { expectDefined } from "@openclaw/normalization-core"; import { createRequireRecord } from "openclaw/plugin-sdk/test-fixtures"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import type { ContextEngine } from "../context-engine/types.js"; -import { getDetachedTaskLifecycleRuntime } from "../tasks/detached-task-runtime.js"; -import { setDetachedTaskLifecycleRuntime } from "../tasks/task-runtime.test-helpers.js"; -import { findTaskByRunIdForStatus } from "../tasks/task-status-access.js"; +import type { ContextEngine } from "../../../context-engine/types.js"; +import { getDetachedTaskLifecycleRuntime } from "../../../tasks/detached-task-runtime.js"; +import { setDetachedTaskLifecycleRuntime } from "../../../tasks/task-runtime.test-helpers.js"; +import { findTaskByRunIdForStatus } from "../../../tasks/task-status-access.js"; const noop = () => {}; let lifecycleHandler: @@ -44,7 +44,7 @@ const sessionStore = vi.hoisted( ), ); -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: vi.fn(async (opts: unknown) => { const request = opts as { method?: string }; if (request.method === "agent.wait") { @@ -54,7 +54,7 @@ vi.mock("../gateway/call.js", () => ({ }), })); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ getAgentEventLifecycleGeneration: () => "test-generation", isAgentEventLifecycleGenerationCurrent: (generation: string) => generation === "test-generation", registerAgentEventLifecycleRotationHandler: vi.fn(), @@ -64,13 +64,13 @@ vi.mock("../infra/agent-events.js", () => ({ }), })); -vi.mock("../config/config.js", () => ({ +vi.mock("../../../config/config.js", () => ({ getRuntimeConfig: vi.fn(() => ({ agents: { defaults: { subagents: { archiveAfterMinutes: 0 } } }, })), })); -vi.mock("../config/sessions.js", () => { +vi.mock("../../../config/sessions.js", () => { return { loadSessionStore: vi.fn(() => sessionStore), resolveAgentIdFromSessionKey: (key: string) => { @@ -83,8 +83,8 @@ vi.mock("../config/sessions.js", () => { }; }); -vi.mock("../config/sessions/session-accessor.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../../../config/sessions/session-accessor.js", async (importOriginal) => ({ + ...(await importOriginal()), listSessionEntriesReadOnly: () => Object.entries(sessionStore).map(([sessionKey, entry]) => ({ sessionKey, entry })), loadSessionEntry: (scope: { sessionKey: string }) => sessionStore[scope.sessionKey], @@ -148,16 +148,16 @@ const noopContextEngine = { assemble: async () => ({ messages: [], estimatedTokens: 0 }), compact: async () => ({ ok: true, compacted: false }), } satisfies ContextEngine; -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ captureSubagentCompletionReply: vi.fn(async () => undefined), runSubagentAnnounceFlow: announceSpy, })); -vi.mock("../browser-lifecycle-cleanup.js", () => ({ +vi.mock("../../../browser-lifecycle-cleanup.js", () => ({ cleanupBrowserSessionsForLifecycleEnd: vi.fn(async () => {}), })); -vi.mock("../plugins/hook-runner-global.js", () => ({ +vi.mock("../../../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: vi.fn(() => ({ hasHooks: (hookName: string) => hookName === "subagent_ended", runSubagentEnded: runSubagentEndedHookMock, @@ -168,11 +168,11 @@ vi.mock("../plugins/hook-runner-global.js", () => ({ resetGlobalHookRunner: vi.fn(), })); -vi.mock("../sessions/session-lifecycle-events.js", () => ({ +vi.mock("../../../sessions/session-lifecycle-events.js", () => ({ emitSessionLifecycleEvent: emitSessionLifecycleEventMock, })); -vi.mock("./internal-session-effects.js", () => ({ +vi.mock("../../internal-session-effects.js", () => ({ removeInternalSessionEffectsSession: removeInternalSessionEffectsSessionMock, })); diff --git a/src/agents/subagent-registry.store.sqlite.test.ts b/src/agents/subagents/registry/subagent-registry.store.sqlite.test.ts similarity index 98% rename from src/agents/subagent-registry.store.sqlite.test.ts rename to src/agents/subagents/registry/subagent-registry.store.sqlite.test.ts index 6ba5255ff653..4d01f4597441 100644 --- a/src/agents/subagent-registry.store.sqlite.test.ts +++ b/src/agents/subagents/registry/subagent-registry.store.sqlite.test.ts @@ -3,13 +3,13 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js"; -import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js"; +import { executeSqliteQuerySync, getNodeSqliteKysely } from "../../../infra/kysely-sync.js"; +import type { DB as OpenClawStateKyselyDatabase } from "../../../state/openclaw-state-db.generated.js"; import { closeOpenClawStateDatabaseForTest, openOpenClawStateDatabase, -} from "../state/openclaw-state-db.js"; -import { withEnvAsync } from "../test-utils/env.js"; +} from "../../../state/openclaw-state-db.js"; +import { withEnvAsync } from "../../../test-utils/env.js"; import { loadSubagentRunsForChildSessionFromSqlite, loadSubagentRunsForControllerFromSqlite, diff --git a/src/agents/subagent-registry.store.sqlite.ts b/src/agents/subagents/registry/subagent-registry.store.sqlite.ts similarity index 98% rename from src/agents/subagent-registry.store.sqlite.ts rename to src/agents/subagents/registry/subagent-registry.store.sqlite.ts index 411a264446f9..379a823f2b92 100644 --- a/src/agents/subagent-registry.store.sqlite.ts +++ b/src/agents/subagents/registry/subagent-registry.store.sqlite.ts @@ -7,14 +7,14 @@ import { safeParseJson } from "@openclaw/normalization-core"; import { asFiniteNumber as normalizeFiniteNumber } from "@openclaw/normalization-core/number-coercion"; import { isRecord } from "@openclaw/normalization-core/record-coerce"; import { sql, type Insertable, type Selectable, type Updateable } from "kysely"; -import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js"; -import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js"; +import { executeSqliteQuerySync, getNodeSqliteKysely } from "../../../infra/kysely-sync.js"; +import type { DB as OpenClawStateKyselyDatabase } from "../../../state/openclaw-state-db.generated.js"; import { openOpenClawStateDatabase, runOpenClawStateWriteTransaction, type OpenClawStateDatabase, -} from "../state/openclaw-state-db.js"; -import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js"; +} from "../../../state/openclaw-state-db.js"; +import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; import { normalizeSubagentRunState } from "./subagent-delivery-state.js"; import type { SubagentRunReadRecord, SubagentRunRecord } from "./subagent-registry.types.js"; diff --git a/src/agents/subagent-registry.test-helpers.ts b/src/agents/subagents/registry/subagent-registry.test-helpers.ts similarity index 79% rename from src/agents/subagent-registry.test-helpers.ts rename to src/agents/subagents/registry/subagent-registry.test-helpers.ts index 42d7bbde3827..4636d12efcb9 100644 --- a/src/agents/subagent-registry.test-helpers.ts +++ b/src/agents/subagents/registry/subagent-registry.test-helpers.ts @@ -1,7 +1,11 @@ export * from "./subagent-registry.js"; -import { collectSessionMaintenancePreserveKeys } from "../config/sessions/store-maintenance-preserve.js"; -import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js"; +import { collectSessionMaintenancePreserveKeys } from "../../../config/sessions/store-maintenance-preserve.js"; +import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; +import { + createSubagentRunRecord, + type SubagentRunRecordOverrides, +} from "../../subagent-test-fixtures.test-helpers.js"; import { subagentRuns } from "./subagent-registry-memory.js"; import { countPendingDescendantRunsExcludingRunFromRuns, @@ -12,10 +16,6 @@ import { } from "./subagent-registry-queries.js"; import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; -import { - createSubagentRunRecord, - type SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; export { getSubagentSessionRuntimeMs, getSubagentSessionStartedAt, @@ -42,24 +42,24 @@ type RegistryTestApi = { }; type RegistryDeps = { - callGateway: typeof import("../gateway/call.js").callGateway; + callGateway: typeof import("../../../gateway/call.js").callGateway; getGatewayRecoveryRuntime: () => - | import("../gateway/server-instance-runtime.types.js").GatewayRecoveryRuntime + | import("../../../gateway/server-instance-runtime.types.js").GatewayRecoveryRuntime | undefined; - captureSubagentCompletionReply: typeof import("./subagent-announce.js").captureSubagentCompletionReply; - cleanupBrowserSessionsForLifecycleEnd: typeof import("../browser-lifecycle-cleanup.js").cleanupBrowserSessionsForLifecycleEnd; + captureSubagentCompletionReply: typeof import("../announce/subagent-announce.js").captureSubagentCompletionReply; + cleanupBrowserSessionsForLifecycleEnd: typeof import("../../../browser-lifecycle-cleanup.js").cleanupBrowserSessionsForLifecycleEnd; getSubagentRunsSnapshotForRead: typeof import("./subagent-registry-state.js").getSubagentRunsSnapshotForRead; - getRuntimeConfig: typeof import("../config/config.js").getRuntimeConfig; - onAgentEvent: typeof import("../infra/agent-events.js").onAgentEvent; + getRuntimeConfig: typeof import("../../../config/config.js").getRuntimeConfig; + onAgentEvent: typeof import("../../../infra/agent-events.js").onAgentEvent; persistSubagentRunsToDisk: typeof import("./subagent-registry-state.js").persistSubagentRunsToDisk; persistSubagentRunsToDiskOrThrow: typeof import("./subagent-registry-state.js").persistSubagentRunsToDiskOrThrow; - resolveAgentTimeoutMs: typeof import("./timeout.js").resolveAgentTimeoutMs; + resolveAgentTimeoutMs: typeof import("../../timeout.js").resolveAgentTimeoutMs; restoreSubagentRunsFromDisk: typeof import("./subagent-registry-state.js").restoreSubagentRunsFromDisk; - runSubagentAnnounceFlow: typeof import("./subagent-announce.js").runSubagentAnnounceFlow; - maybeWakeRequesterAfterAllChildrenSettled: typeof import("./subagent-announce.requester-settle-wake.js").maybeWakeRequesterAfterAllChildrenSettled; + runSubagentAnnounceFlow: typeof import("../announce/subagent-announce.js").runSubagentAnnounceFlow; + maybeWakeRequesterAfterAllChildrenSettled: typeof import("../announce/subagent-announce.requester-settle-wake.js").maybeWakeRequesterAfterAllChildrenSettled; ensureContextEnginesInitialized?: () => void; loadAgentRuntimePluginRegistryHandle?: import("./subagent-registry-deps.js").SubagentRegistryDeps["loadAgentRuntimePluginRegistryHandle"]; - resolveContextEngine?: typeof import("../context-engine/registry.js").resolveContextEngine; + resolveContextEngine?: typeof import("../../../context-engine/registry.js").resolveContextEngine; }; function getRegistryTestApi(): RegistryTestApi { diff --git a/src/agents/subagent-registry.test.ts b/src/agents/subagents/registry/subagent-registry.test.ts similarity index 99% rename from src/agents/subagent-registry.test.ts rename to src/agents/subagents/registry/subagent-registry.test.ts index ff23b22bb308..2a6362e468d6 100644 --- a/src/agents/subagent-registry.test.ts +++ b/src/agents/subagents/registry/subagent-registry.test.ts @@ -5,41 +5,55 @@ import os from "node:os"; import path from "node:path"; import { expectDefined } from "@openclaw/normalization-core"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import type { SessionEntry } from "../config/sessions.js"; +import type { SessionEntry } from "../../../config/sessions.js"; import type { SessionAccessScope, SessionEntryPatchContext, SessionEntryPatchOptions, -} from "../config/sessions/session-accessor.js"; +} from "../../../config/sessions/session-accessor.js"; import { runWithOwnedSessionTranscriptWrite, withOwnedSessionTranscriptWrites, -} from "../config/sessions/transcript-write-context.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { GatewayRecoveryRuntime } from "../gateway/server-instance-runtime.types.js"; -import type { AgentEventPayload } from "../infra/agent-events.js"; -import { createEmptyPluginRegistry } from "../plugins/registry-empty.js"; -import { getPluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js"; +} from "../../../config/sessions/transcript-write-context.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { GatewayRecoveryRuntime } from "../../../gateway/server-instance-runtime.types.js"; +import type { AgentEventPayload } from "../../../infra/agent-events.js"; +import { createEmptyPluginRegistry } from "../../../plugins/registry-empty.js"; +import { getPluginRuntimeGatewayRequestScope } from "../../../plugins/runtime/gateway-request-scope.js"; import { getActiveGatewayRootWorkCount, markGatewayRestartDraining, resetGatewayWorkAdmission, tryBeginGatewaySuspendAdmission, -} from "../process/gateway-work-admission.js"; -import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js"; +} from "../../../process/gateway-work-admission.js"; +import { SUBAGENT_KILL_TASK_ERROR } from "../../../tasks/detached-task-runtime-contract.js"; import { createRunningTaskRun, findDetachedTaskRun, finalizeTaskRunByRunId, getDetachedTaskLifecycleRuntime, -} from "../tasks/detached-task-runtime.js"; +} from "../../../tasks/detached-task-runtime.js"; import { resetDetachedTaskLifecycleRuntimeForTests, resetTaskFlowRegistryForTests, resetTaskRegistryForTests, setDetachedTaskLifecycleRuntime, -} from "../tasks/task-runtime.test-helpers.js"; -import { findTaskByRunIdForStatus } from "../tasks/task-status-access.js"; +} from "../../../tasks/task-runtime.test-helpers.js"; +import { findTaskByRunIdForStatus } from "../../../tasks/task-status-access.js"; +import { + createSessionStore, + createSubagentRunParams, + createSubagentRunRecord, + expectRecordFields, + mockGatewayMethods, + mockCallArg as getMockCallArg, + waitForFast, +} from "../../subagent-test-fixtures.test-helpers.js"; +import type { + SubagentRunParamsOverrides, + SubagentRunRecordOverrides, +} from "../../subagent-test-fixtures.test-helpers.js"; +import { testing as swarmSchedulerTesting } from "../swarm/swarm-scheduler.test-support.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, @@ -50,20 +64,6 @@ import type { ContextEngineSubagentEndedParams, SubagentRunRecord, } from "./subagent-registry.types.js"; -import { - createSessionStore, - createSubagentRunParams, - createSubagentRunRecord, - expectRecordFields, - mockGatewayMethods, - mockCallArg as getMockCallArg, - waitForFast, -} from "./subagent-test-fixtures.test-helpers.js"; -import type { - SubagentRunParamsOverrides, - SubagentRunRecordOverrides, -} from "./subagent-test-fixtures.test-helpers.js"; -import { testing as swarmSchedulerTesting } from "./subagents/swarm/swarm-scheduler.test-support.js"; const noop = () => {}; @@ -205,35 +205,35 @@ const mocks = vi.hoisted(() => ({ lifecycleGeneration: "test-generation", })); -vi.mock("../gateway/call.js", () => ({ +vi.mock("../../../gateway/call.js", () => ({ callGateway: mocks.callGateway, })); -vi.mock("../infra/agent-events.js", () => ({ +vi.mock("../../../infra/agent-events.js", () => ({ getAgentEventLifecycleGeneration: () => mocks.lifecycleGeneration, isAgentEventLifecycleGenerationCurrent: (generation: string) => generation === mocks.lifecycleGeneration, onAgentEvent: mocks.onAgentEvent, registerAgentEventLifecycleRotationHandler: vi.fn(), })); -vi.mock("../infra/agent-run-registry.js", () => ({ +vi.mock("../../../infra/agent-run-registry.js", () => ({ getAgentRunContext: mocks.getAgentRunContext, })); -vi.mock("../config/config.js", () => { +vi.mock("../../../config/config.js", () => { return { getRuntimeConfig: mocks.getRuntimeConfig, }; }); -vi.mock("../config/sessions.js", () => ({ +vi.mock("../../../config/sessions.js", () => ({ loadSessionStore: mocks.loadSessionStore, resolveAgentIdFromSessionKey: mocks.resolveAgentIdFromSessionKey, resolveStorePath: mocks.resolveStorePath, updateSessionStore: mocks.updateSessionStore, })); -vi.mock("../config/sessions/session-accessor.js", () => ({ +vi.mock("../../../config/sessions/session-accessor.js", () => ({ listSessionEntries: mocks.listSessionEntries, listSessionEntriesReadOnly: mocks.listSessionEntries, loadSessionEntry: mocks.loadSessionEntry, @@ -241,7 +241,7 @@ vi.mock("../config/sessions/session-accessor.js", () => ({ patchSessionEntry: mocks.patchSessionEntry, })); -vi.mock("../sessions/session-lifecycle-events.js", () => ({ +vi.mock("../../../sessions/session-lifecycle-events.js", () => ({ emitSessionLifecycleEvent: mocks.emitSessionLifecycleEvent, })); @@ -255,28 +255,28 @@ vi.mock("./subagent-registry-state.js", () => ({ restoreSubagentRunsFromDisk: mocks.restoreSubagentRunsFromDisk, })); -vi.mock("./subagent-announce.js", () => ({ +vi.mock("../announce/subagent-announce.js", () => ({ captureSubagentCompletionReply: mocks.captureSubagentCompletionReply, runSubagentAnnounceFlow: mocks.runSubagentAnnounceFlow, })); -vi.mock("../plugins/hook-runner-global.js", () => ({ +vi.mock("../../../plugins/hook-runner-global.js", () => ({ getGlobalHookRunner: mocks.getGlobalHookRunner, })); -vi.mock("../context-engine/init.js", () => ({ +vi.mock("../../../context-engine/init.js", () => ({ ensureContextEnginesInitialized: mocks.ensureContextEnginesInitialized, })); -vi.mock("../context-engine/registry.js", () => ({ +vi.mock("../../../context-engine/registry.js", () => ({ resolveContextEngine: mocks.resolveContextEngine, })); -vi.mock("./timeout.js", () => ({ +vi.mock("../../timeout.js", () => ({ resolveAgentTimeoutMs: mocks.resolveAgentTimeoutMs, })); -vi.mock("./internal-session-effects.js", () => ({ +vi.mock("../../internal-session-effects.js", () => ({ removeInternalSessionEffectsSession: mocks.removeInternalSessionEffectsSession, })); @@ -510,7 +510,7 @@ describe("subagent registry seam flow", () => { }, }); mod.testing.setDepsForTest({ - callGateway: mocks.callGateway as typeof import("../gateway/call.js").callGateway, + callGateway: mocks.callGateway as typeof import("../../../gateway/call.js").callGateway, captureSubagentCompletionReply: mocks.captureSubagentCompletionReply, cleanupBrowserSessionsForLifecycleEnd: mocks.cleanupBrowserSessionsForLifecycleEnd, getGatewayRecoveryRuntime: mocks.getGatewayRecoveryRuntime, @@ -2068,7 +2068,7 @@ describe("subagent registry seam flow", () => { resumedRuns: new Set(), persist: vi.fn(), persistOrThrow, - callGateway: mocks.callGateway as typeof import("../gateway/call.js").callGateway, + callGateway: mocks.callGateway as typeof import("../../../gateway/call.js").callGateway, getRuntimeConfig: mocks.getRuntimeConfig, ensureListener: noop, startSweeper: noop, diff --git a/src/agents/subagent-registry.ts b/src/agents/subagents/registry/subagent-registry.ts similarity index 97% rename from src/agents/subagent-registry.ts rename to src/agents/subagents/registry/subagent-registry.ts index 67f9268b8cc5..8187fcf4f176 100644 --- a/src/agents/subagent-registry.ts +++ b/src/agents/subagents/registry/subagent-registry.ts @@ -1,14 +1,15 @@ /** Coordinates subagent registration, lifecycle, delivery, steering, recovery, and persistence. */ -import type { AgentWaitParams } from "../../packages/gateway-protocol/src/index.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { callGateway } from "../gateway/call.js"; -import { getGatewayRecoveryRuntime } from "../gateway/server-recovery-runtime-context.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; +import type { AgentWaitParams } from "../../../../packages/gateway-protocol/src/index.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { callGateway } from "../../../gateway/call.js"; +import { getGatewayRecoveryRuntime } from "../../../gateway/server-recovery-runtime-context.js"; +import { createSubsystemLogger } from "../../../logging/subsystem.js"; import { isGatewayRestartDraining, runWithGatewayIndependentRootWorkAdmission, -} from "../process/gateway-work-admission.js"; -import { prependAgentSteeringPrompt } from "./agent-steering-queue.js"; +} from "../../../process/gateway-work-admission.js"; +import { prependAgentSteeringPrompt } from "../../agent-steering-queue.js"; +import { terminateAcceptedCollectorRun } from "../spawn/subagent-spawn-cleanup.js"; import { isDeliverySuspended } from "./subagent-delivery-state.js"; import { createSubagentRegistryCompletionRuntime } from "./subagent-registry-completion-runtime.js"; import { emitSubagentProgressEndedHook } from "./subagent-registry-completion.js"; @@ -47,7 +48,6 @@ import { resolveSubagentSessionCompletion, resolveSubagentSessionStartedAt, } from "./subagent-session-reconciliation.js"; -import { terminateAcceptedCollectorRun } from "./subagents/spawn/subagent-spawn-cleanup.js"; export type { SubagentRunRecord } from "./subagent-registry.types.js"; const log = createSubsystemLogger("agents/subagent-registry"); diff --git a/src/agents/subagent-registry.types.ts b/src/agents/subagents/registry/subagent-registry.types.ts similarity index 95% rename from src/agents/subagent-registry.types.ts rename to src/agents/subagents/registry/subagent-registry.types.ts index 203aa3ed316a..ca6535e64da8 100644 --- a/src/agents/subagent-registry.types.ts +++ b/src/agents/subagents/registry/subagent-registry.types.ts @@ -1,12 +1,12 @@ -import type { SubagentEndReason } from "../context-engine/types.js"; +import type { SubagentEndReason } from "../../../context-engine/types.js"; /** Persisted execution, completion, delivery, and attachment state for child runs. */ -import type { DeliveryContext } from "../utils/delivery-context.types.js"; -import type { AgentRunTerminalReplySnapshot } from "./agent-run-terminal-reply.js"; -import type { AgentRunSessionTarget } from "./run-session-target.js"; -import type { SubagentRunOutcome } from "./subagent-announce-output.js"; -import type { SubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; +import type { AgentRunTerminalReplySnapshot } from "../../agent-run-terminal-reply.js"; +import type { AgentRunSessionTarget } from "../../run-session-target.js"; +import type { SubagentRunOutcome } from "../announce/subagent-announce-output.js"; +import type { SubagentLaunchAuthorization } from "../spawn/subagent-launch-authorization.js"; +import type { SpawnSubagentMode } from "../spawn/subagent-spawn.types.js"; import type { SubagentLifecycleEndedReason } from "./subagent-lifecycle-events.js"; -import type { SpawnSubagentMode } from "./subagents/spawn/subagent-spawn.types.js"; export type SubagentCompletionRequest = { runId: string; diff --git a/src/agents/subagent-run-generation.ts b/src/agents/subagents/registry/subagent-run-generation.ts similarity index 100% rename from src/agents/subagent-run-generation.ts rename to src/agents/subagents/registry/subagent-run-generation.ts diff --git a/src/agents/subagent-run-liveness.test.ts b/src/agents/subagents/registry/subagent-run-liveness.test.ts similarity index 100% rename from src/agents/subagent-run-liveness.test.ts rename to src/agents/subagents/registry/subagent-run-liveness.test.ts diff --git a/src/agents/subagent-run-liveness.ts b/src/agents/subagents/registry/subagent-run-liveness.ts similarity index 100% rename from src/agents/subagent-run-liveness.ts rename to src/agents/subagents/registry/subagent-run-liveness.ts diff --git a/src/agents/subagent-run-timeout.test.ts b/src/agents/subagents/registry/subagent-run-timeout.test.ts similarity index 97% rename from src/agents/subagent-run-timeout.test.ts rename to src/agents/subagents/registry/subagent-run-timeout.test.ts index 8f6531b42d98..68fc8c23e38c 100644 --- a/src/agents/subagent-run-timeout.test.ts +++ b/src/agents/subagents/registry/subagent-run-timeout.test.ts @@ -1,7 +1,7 @@ // Subagent run timeout tests keep semantic deadlines separate from the maximum // delay that Node timers can safely schedule. import { describe, expect, it } from "vitest"; -import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js"; +import { MAX_TIMER_TIMEOUT_MS } from "../../../shared/number-coercion.js"; import { resolveSubagentRunDeadlineMs, resolveSubagentRunDurationMs, diff --git a/src/agents/subagent-run-timeout.ts b/src/agents/subagents/registry/subagent-run-timeout.ts similarity index 98% rename from src/agents/subagent-run-timeout.ts rename to src/agents/subagents/registry/subagent-run-timeout.ts index a4c92576b386..9e48c382e65a 100644 --- a/src/agents/subagent-run-timeout.ts +++ b/src/agents/subagents/registry/subagent-run-timeout.ts @@ -6,7 +6,7 @@ import { asDateTimestampMs, finiteSecondsToTimerSafeMilliseconds, -} from "../shared/number-coercion.js"; +} from "../../../shared/number-coercion.js"; import type { SubagentRunRecord } from "./subagent-registry.types.js"; type SubagentRunDeadlineRecord = Pick< diff --git a/src/agents/subagent-session-cleanup.ts b/src/agents/subagents/registry/subagent-session-cleanup.ts similarity index 89% rename from src/agents/subagent-session-cleanup.ts rename to src/agents/subagents/registry/subagent-session-cleanup.ts index 9160df6854ad..56ead58ece82 100644 --- a/src/agents/subagent-session-cleanup.ts +++ b/src/agents/subagents/registry/subagent-session-cleanup.ts @@ -2,9 +2,9 @@ * Cleanup helper for subagent sessions. It deletes child session state through * the gateway and preserves lifecycle-hook behavior for session-mode spawns. */ -import { SESSION_LIFECYCLE_CHANGED_ERROR_REASON } from "../config/sessions/lifecycle.js"; -import type { callGateway } from "../gateway/call.js"; -import type { SpawnSubagentMode } from "./subagents/spawn/subagent-spawn.types.js"; +import { SESSION_LIFECYCLE_CHANGED_ERROR_REASON } from "../../../config/sessions/lifecycle.js"; +import type { callGateway } from "../../../gateway/call.js"; +import type { SpawnSubagentMode } from "../spawn/subagent-spawn.types.js"; type CallGateway = (options: Parameters[0]) => Promise; type SubagentSessionCleanupOutcome = "deleted" | "changed" | "failed"; diff --git a/src/agents/subagent-session-metrics.ts b/src/agents/subagents/registry/subagent-session-metrics.ts similarity index 100% rename from src/agents/subagent-session-metrics.ts rename to src/agents/subagents/registry/subagent-session-metrics.ts diff --git a/src/agents/subagent-session-reconciliation.ts b/src/agents/subagents/registry/subagent-session-reconciliation.ts similarity index 96% rename from src/agents/subagent-session-reconciliation.ts rename to src/agents/subagents/registry/subagent-session-reconciliation.ts index 382104de8e72..728ef0b066d5 100644 --- a/src/agents/subagent-session-reconciliation.ts +++ b/src/agents/subagents/registry/subagent-session-reconciliation.ts @@ -4,18 +4,18 @@ * Infers child completion from persisted session entries when registry updates arrive late. */ import { asFiniteNumber } from "@openclaw/normalization-core/number-coercion"; -import { getRuntimeConfig } from "../config/config.js"; +import { getRuntimeConfig } from "../../../config/config.js"; import { resolveAgentIdFromSessionKey, resolveStorePath, type SessionEntry, -} from "../config/sessions.js"; +} from "../../../config/sessions.js"; import { listSessionEntriesReadOnly, loadSessionEntryReadOnly, -} from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { SubagentRunOutcome } from "./subagent-announce-output.js"; +} from "../../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import type { SubagentRunOutcome } from "../announce/subagent-announce-output.js"; import { SUBAGENT_ENDED_REASON_COMPLETE, SUBAGENT_ENDED_REASON_ERROR, diff --git a/src/agents/acp-parent-stream-store.sqlite.test-support.ts b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test-support.ts similarity index 83% rename from src/agents/acp-parent-stream-store.sqlite.test-support.ts rename to src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test-support.ts index c8043334a69b..46308c5d27f7 100644 --- a/src/agents/acp-parent-stream-store.sqlite.test-support.ts +++ b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test-support.ts @@ -1,9 +1,9 @@ -import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js"; -import type { DB as OpenClawAgentKyselyDatabase } from "../state/openclaw-agent-db.generated.js"; +import { executeSqliteQuerySync, getNodeSqliteKysely } from "../../../infra/kysely-sync.js"; +import type { DB as OpenClawAgentKyselyDatabase } from "../../../state/openclaw-agent-db.generated.js"; import { openOpenClawAgentDatabase, type OpenClawAgentDatabaseOptions, -} from "../state/openclaw-agent-db.js"; +} from "../../../state/openclaw-agent-db.js"; import type { AcpParentStreamEvent } from "./acp-parent-stream-store.sqlite.js"; type AcpParentStreamDatabase = Pick; diff --git a/src/agents/acp-parent-stream-store.sqlite.test.ts b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test.ts similarity index 94% rename from src/agents/acp-parent-stream-store.sqlite.test.ts rename to src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test.ts index 25ca3a5b9ad9..5276a1840ab5 100644 --- a/src/agents/acp-parent-stream-store.sqlite.test.ts +++ b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.test.ts @@ -1,11 +1,11 @@ import { afterEach, describe, expect, it } from "vitest"; -import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js"; -import type { DB as OpenClawAgentKyselyDatabase } from "../state/openclaw-agent-db.generated.js"; +import { executeSqliteQuerySync, getNodeSqliteKysely } from "../../../infra/kysely-sync.js"; +import type { DB as OpenClawAgentKyselyDatabase } from "../../../state/openclaw-agent-db.generated.js"; import { closeOpenClawAgentDatabasesForTest, runOpenClawAgentWriteTransaction, -} from "../state/openclaw-agent-db.js"; -import { withTempDir } from "../test-helpers/temp-dir.js"; +} from "../../../state/openclaw-agent-db.js"; +import { withTempDir } from "../../../test-helpers/temp-dir.js"; import { recordAcpParentStreamEvents } from "./acp-parent-stream-store.sqlite.js"; import { listAcpParentStreamEventsForTest } from "./acp-parent-stream-store.sqlite.test-support.js"; diff --git a/src/agents/acp-parent-stream-store.sqlite.ts b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.ts similarity index 92% rename from src/agents/acp-parent-stream-store.sqlite.ts rename to src/agents/subagents/spawn/acp-parent-stream-store.sqlite.ts index 5cdd003fa3f3..e3261f6a291a 100644 --- a/src/agents/acp-parent-stream-store.sqlite.ts +++ b/src/agents/subagents/spawn/acp-parent-stream-store.sqlite.ts @@ -3,12 +3,12 @@ import { executeSqliteQuerySync, executeSqliteQueryTakeFirstSync, getNodeSqliteKysely, -} from "../infra/kysely-sync.js"; -import type { DB as OpenClawAgentKyselyDatabase } from "../state/openclaw-agent-db.generated.js"; +} from "../../../infra/kysely-sync.js"; +import type { DB as OpenClawAgentKyselyDatabase } from "../../../state/openclaw-agent-db.generated.js"; import { runOpenClawAgentWriteTransaction, type OpenClawAgentDatabaseOptions, -} from "../state/openclaw-agent-db.js"; +} from "../../../state/openclaw-agent-db.js"; type AcpParentStreamDatabase = Pick; diff --git a/src/agents/subagents/spawn/acp-spawn-admission.ts b/src/agents/subagents/spawn/acp-spawn-admission.ts index e880701e2b7b..6943dfcb4f50 100644 --- a/src/agents/subagents/spawn/acp-spawn-admission.ts +++ b/src/agents/subagents/spawn/acp-spawn-admission.ts @@ -1,6 +1,6 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { listTasksForOwnerKey } from "../../../tasks/runtime-internal.js"; -import { getSubagentRunByChildSessionKey } from "../../subagent-registry.js"; +import { getSubagentRunByChildSessionKey } from "../registry/subagent-registry.js"; function isActiveTaskStatus(status: string | undefined): boolean { return status === "queued" || status === "running"; diff --git a/src/agents/subagents/spawn/acp-spawn-parent-stream.test.ts b/src/agents/subagents/spawn/acp-spawn-parent-stream.test.ts index 8ad47b955933..ef28d34a63bf 100644 --- a/src/agents/subagents/spawn/acp-spawn-parent-stream.test.ts +++ b/src/agents/subagents/spawn/acp-spawn-parent-stream.test.ts @@ -22,10 +22,10 @@ vi.mock("../../../infra/heartbeat-wake.js", async () => { ); }); -vi.mock("../../acp-parent-stream-store.sqlite.js", async () => { +vi.mock("./acp-parent-stream-store.sqlite.js", async () => { return await mergeMockedModule( - await vi.importActual( - "../../acp-parent-stream-store.sqlite.js", + await vi.importActual( + "./acp-parent-stream-store.sqlite.js", ), () => ({ recordAcpParentStreamEvents: (...args: unknown[]) => recordAcpParentStreamEventsMock(...args), diff --git a/src/agents/subagents/spawn/acp-spawn-parent-stream.ts b/src/agents/subagents/spawn/acp-spawn-parent-stream.ts index b9c9e634800b..194d7e32d8a9 100644 --- a/src/agents/subagents/spawn/acp-spawn-parent-stream.ts +++ b/src/agents/subagents/spawn/acp-spawn-parent-stream.ts @@ -34,7 +34,7 @@ import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; import { recordAcpParentStreamEvents, type AcpParentStreamEvent, -} from "../../acp-parent-stream-store.sqlite.js"; +} from "./acp-parent-stream-store.sqlite.js"; const DEFAULT_STREAM_FLUSH_MS = 2_500; const DEFAULT_NO_OUTPUT_NOTICE_MS = 60_000; diff --git a/src/agents/subagents/spawn/acp-spawn-requester.ts b/src/agents/subagents/spawn/acp-spawn-requester.ts index 311953d881da..8abd0a022493 100644 --- a/src/agents/subagents/spawn/acp-spawn-requester.ts +++ b/src/agents/subagents/spawn/acp-spawn-requester.ts @@ -14,7 +14,6 @@ import { createSubsystemLogger } from "../../../logging/subsystem.js"; import { isSubagentSessionKey, parseAgentSessionKey } from "../../../routing/session-key.js"; import { normalizeDeliveryContext } from "../../../utils/delivery-context.shared.js"; import { resolveRequesterOriginForChild } from "../../spawn-requester-origin.js"; -import type { SessionCapabilityStore } from "../../subagent-capabilities.js"; import { resolveInternalSessionKey, resolveMainSessionAlias, @@ -23,6 +22,7 @@ import { hasSessionLocalHeartbeatRelayRoute, isHeartbeatEnabledForSessionAgent, } from "./acp-spawn-heartbeat.js"; +import type { SessionCapabilityStore } from "./subagent-capabilities.js"; const log = createSubsystemLogger("agents/acp-spawn"); diff --git a/src/agents/subagents/spawn/acp-spawn.test.ts b/src/agents/subagents/spawn/acp-spawn.test.ts index 7be3c10c16b6..bd90f944bedc 100644 --- a/src/agents/subagents/spawn/acp-spawn.test.ts +++ b/src/agents/subagents/spawn/acp-spawn.test.ts @@ -27,10 +27,10 @@ import { emitAcpLifecycleEnd, } from "../../command/attempt-execution.js"; import { resolveThinkingDefault } from "../../model-selection.js"; -import { SUBAGENT_ENDED_REASON_COMPLETE } from "../../subagent-lifecycle-events.js"; -import { createSubagentRegistryLifecycleController } from "../../subagent-registry-lifecycle.js"; -import type { RegisterSubagentRunParams } from "../../subagent-registry-run-manager.js"; -import type { SubagentRunRecord } from "../../subagent-registry.types.js"; +import { SUBAGENT_ENDED_REASON_COMPLETE } from "../registry/subagent-lifecycle-events.js"; +import { createSubagentRegistryLifecycleController } from "../registry/subagent-registry-lifecycle.js"; +import type { RegisterSubagentRunParams } from "../registry/subagent-registry-run-manager.js"; +import type { SubagentRunRecord } from "../registry/subagent-registry.types.js"; type SessionBindingAdapterCapabilities = NonNullable; type BoundaryLifecycleControllerParams = Parameters< @@ -249,8 +249,8 @@ vi.mock("./acp-spawn-parent-stream.js", () => ({ startAcpSpawnParentStreamRelay: hoisted.startAcpSpawnParentStreamRelayMock, })); -vi.mock("../../subagent-registry.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../registry/subagent-registry.js", async (importOriginal) => ({ + ...(await importOriginal()), countActiveRunsForSession: hoisted.countActiveRunsForSessionMock, getSubagentRunByChildSessionKey: hoisted.getSubagentRunByChildSessionKeyMock, // ACP registration deliberately moved behind the shared spawn pipeline. diff --git a/src/agents/subagents/spawn/acp-spawn.ts b/src/agents/subagents/spawn/acp-spawn.ts index a42a2da85084..cfa846eaebde 100644 --- a/src/agents/subagents/spawn/acp-spawn.ts +++ b/src/agents/subagents/spawn/acp-spawn.ts @@ -60,10 +60,6 @@ import { type PreparedSpawnThreadBinding, } from "../../spawn-plan.js"; import { resolveSpawnedWorkspaceInheritance } from "../../spawned-context.js"; -import { - isSubagentEnvelopeSession, - resolveSubagentCapabilityStore, -} from "../../subagent-capabilities.js"; import { countUntrackedActiveAcpRunsForOwner } from "./acp-spawn-admission.js"; import { resolveAcpSpawnBootstrapDeliveryPlan, @@ -92,6 +88,10 @@ import { resolveConfiguredAcpSubagentTargetIds, resolveTargetAcpAgentId, } from "./acp-spawn-target.js"; +import { + isSubagentEnvelopeSession, + resolveSubagentCapabilityStore, +} from "./subagent-capabilities.js"; import { resolveSubagentSpawnOwnership } from "./subagent-spawn-ownership.js"; import { resolveConfiguredSubagentRunTimeoutSeconds } from "./subagent-spawn-plan.js"; diff --git a/src/agents/subagent-attachments.ts b/src/agents/subagents/spawn/subagent-attachments.ts similarity index 98% rename from src/agents/subagent-attachments.ts rename to src/agents/subagents/spawn/subagent-attachments.ts index 1992a84aeed5..c242b892d6aa 100644 --- a/src/agents/subagent-attachments.ts +++ b/src/agents/subagents/spawn/subagent-attachments.ts @@ -7,9 +7,9 @@ import crypto from "node:crypto"; import { promises as fs } from "node:fs"; import path from "node:path"; import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { privateFileStore } from "../infra/private-file-store.js"; -import { resolveAgentWorkspaceDir } from "./agent-scope.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { privateFileStore } from "../../../infra/private-file-store.js"; +import { resolveAgentWorkspaceDir } from "../../agent-scope.js"; function decodeStrictBase64(value: string, maxDecodedBytes: number): Buffer | null { const maxEncodedBytes = Math.ceil(maxDecodedBytes / 3) * 4; diff --git a/src/agents/subagent-capabilities.test.ts b/src/agents/subagents/spawn/subagent-capabilities.test.ts similarity index 100% rename from src/agents/subagent-capabilities.test.ts rename to src/agents/subagents/spawn/subagent-capabilities.test.ts diff --git a/src/agents/subagent-capabilities.ts b/src/agents/subagents/spawn/subagent-capabilities.ts similarity index 98% rename from src/agents/subagent-capabilities.ts rename to src/agents/subagents/spawn/subagent-capabilities.ts index acecf4fb7906..bd314304ffc0 100644 --- a/src/agents/subagent-capabilities.ts +++ b/src/agents/subagents/spawn/subagent-capabilities.ts @@ -11,18 +11,18 @@ import { normalizeOptionalLowercaseString, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js"; -import { resolveStorePath } from "../config/sessions.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; +import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../../../config/agent-limits.js"; +import { resolveStorePath } from "../../../config/sessions.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import { isAcpSessionKey, isSubagentSessionKey, parseAgentSessionKey, -} from "../routing/session-key.js"; +} from "../../../routing/session-key.js"; import { normalizeInheritedToolAllowlist, normalizeInheritedToolDenylist, -} from "./inherited-tool-deny.js"; +} from "../../inherited-tool-deny.js"; import { findSubagentSessionEntryById, getSubagentDepthFromSessionStore, diff --git a/src/agents/subagent-depth.test.ts b/src/agents/subagents/spawn/subagent-depth.test.ts similarity index 96% rename from src/agents/subagent-depth.test.ts rename to src/agents/subagents/spawn/subagent-depth.test.ts index e0ec7b576e2d..f7eac2f07650 100644 --- a/src/agents/subagent-depth.test.ts +++ b/src/agents/subagents/spawn/subagent-depth.test.ts @@ -5,10 +5,10 @@ import os from "node:os"; import path from "node:path"; import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion"; import { describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { replaceSessionEntry } from "../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../../config/config.js"; +import { replaceSessionEntry } from "../../../config/sessions/session-accessor.js"; +import { resolveAgentTimeoutMs } from "../../timeout.js"; import { getSubagentDepthFromSessionStore } from "./subagent-depth.js"; -import { resolveAgentTimeoutMs } from "./timeout.js"; describe("getSubagentDepthFromSessionStore", () => { it("uses spawnDepth from the session store when available", () => { diff --git a/src/agents/subagent-depth.ts b/src/agents/subagents/spawn/subagent-depth.ts similarity index 91% rename from src/agents/subagent-depth.ts rename to src/agents/subagents/spawn/subagent-depth.ts index c3786db9641d..cb1799a35df6 100644 --- a/src/agents/subagent-depth.ts +++ b/src/agents/subagents/spawn/subagent-depth.ts @@ -4,12 +4,12 @@ * Reads persisted session store state to recover spawn depth and parent lineage across restarts. */ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { resolveStorePath } from "../config/sessions/paths.js"; -import { listSessionEntriesReadOnly } from "../config/sessions/session-accessor.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js"; -import { getSubagentDepth, parseAgentSessionKey } from "../sessions/session-key-utils.js"; -import { resolveDefaultAgentId } from "./agent-scope.js"; +import { resolveStorePath } from "../../../config/sessions/paths.js"; +import { listSessionEntriesReadOnly } from "../../../config/sessions/session-accessor.js"; +import type { OpenClawConfig } from "../../../config/types.openclaw.js"; +import { parseStrictNonNegativeInteger } from "../../../infra/parse-finite-number.js"; +import { getSubagentDepth, parseAgentSessionKey } from "../../../sessions/session-key-utils.js"; +import { resolveDefaultAgentId } from "../../agent-scope.js"; type SessionDepthEntry = { sessionId?: unknown; diff --git a/src/agents/subagent-initial-user-message.test.ts b/src/agents/subagents/spawn/subagent-initial-user-message.test.ts similarity index 100% rename from src/agents/subagent-initial-user-message.test.ts rename to src/agents/subagents/spawn/subagent-initial-user-message.test.ts diff --git a/src/agents/subagent-initial-user-message.ts b/src/agents/subagents/spawn/subagent-initial-user-message.ts similarity index 100% rename from src/agents/subagent-initial-user-message.ts rename to src/agents/subagents/spawn/subagent-initial-user-message.ts diff --git a/src/agents/subagent-launch-authorization.ts b/src/agents/subagents/spawn/subagent-launch-authorization.ts similarity index 100% rename from src/agents/subagent-launch-authorization.ts rename to src/agents/subagents/spawn/subagent-launch-authorization.ts diff --git a/src/agents/subagents/spawn/subagent-spawn-child-plan.ts b/src/agents/subagents/spawn/subagent-spawn-child-plan.ts index fb6a097b0286..694cba9a74ea 100644 --- a/src/agents/subagents/spawn/subagent-spawn-child-plan.ts +++ b/src/agents/subagents/spawn/subagent-spawn-child-plan.ts @@ -13,7 +13,7 @@ import { mapToolContextToSpawnedRunMetadata, resolveSpawnedWorkspaceInheritance, } from "../../spawned-context.js"; -import type { SubagentLaunchAuthorization } from "../../subagent-launch-authorization.js"; +import type { SubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; import type { SpawnSubagentContext, SpawnSubagentParams, diff --git a/src/agents/subagents/spawn/subagent-spawn-cleanup.ts b/src/agents/subagents/spawn/subagent-spawn-cleanup.ts index d911f3b5ad6a..7dece3b90466 100644 --- a/src/agents/subagents/spawn/subagent-spawn-cleanup.ts +++ b/src/agents/subagents/spawn/subagent-spawn-cleanup.ts @@ -1,7 +1,7 @@ import { promises as fs } from "node:fs"; import type { callGateway } from "../../../gateway/call.js"; import { isFastTestRuntimeEnv } from "../../../infra/env.js"; -import { deleteSubagentSessionForCleanup } from "../../subagent-session-cleanup.js"; +import { deleteSubagentSessionForCleanup } from "../registry/subagent-session-cleanup.js"; import { callSubagentGateway } from "./subagent-spawn-gateway.js"; const SUBAGENT_CONTROL_GATEWAY_TIMEOUT_MS = 60_000; diff --git a/src/agents/subagents/spawn/subagent-spawn-gateway.ts b/src/agents/subagents/spawn/subagent-spawn-gateway.ts index 8be364008ff1..760b5611bb20 100644 --- a/src/agents/subagents/spawn/subagent-spawn-gateway.ts +++ b/src/agents/subagents/spawn/subagent-spawn-gateway.ts @@ -1,6 +1,6 @@ -import type { SubagentLaunchAuthorization } from "../../subagent-launch-authorization.js"; -import { applySubagentLaunchAuthorization } from "../../subagent-launch-authorization.js"; -import { resolveSubagentRunTimerDelayMs } from "../../subagent-run-timeout.js"; +import { resolveSubagentRunTimerDelayMs } from "../registry/subagent-run-timeout.js"; +import type { SubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; +import { applySubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; import { getSubagentSpawnDeps } from "./subagent-spawn-deps.js"; import { ADMIN_SCOPE, diff --git a/src/agents/subagents/spawn/subagent-spawn-launch-request.ts b/src/agents/subagents/spawn/subagent-spawn-launch-request.ts index 64e8787ce85b..fc8db683e4c8 100644 --- a/src/agents/subagents/spawn/subagent-spawn-launch-request.ts +++ b/src/agents/subagents/spawn/subagent-spawn-launch-request.ts @@ -1,8 +1,8 @@ import { stringifyRouteThreadId } from "../../../plugin-sdk/channel-route.js"; import type { BootstrapContextMode } from "../../bootstrap-files.js"; import { normalizeSpawnedRunMetadata } from "../../spawned-context.js"; -import { buildSubagentInitialUserMessage } from "../../subagent-initial-user-message.js"; -import type { SubagentLaunchAuthorization } from "../../subagent-launch-authorization.js"; +import { buildSubagentInitialUserMessage } from "./subagent-initial-user-message.js"; +import type { SubagentLaunchAuthorization } from "./subagent-launch-authorization.js"; import { resolveSubagentAgentGatewayTimeoutMs } from "./subagent-spawn-gateway.js"; import { AGENT_LANE_SUBAGENT } from "./subagent-spawn.runtime.js"; import type { SpawnSubagentMode } from "./subagent-spawn.types.js"; diff --git a/src/agents/subagents/spawn/subagent-spawn-request.ts b/src/agents/subagents/spawn/subagent-spawn-request.ts index d403b4e2cbe7..7b6cf630c6a3 100644 --- a/src/agents/subagents/spawn/subagent-spawn-request.ts +++ b/src/agents/subagents/spawn/subagent-spawn-request.ts @@ -10,8 +10,7 @@ import { import { listAgentIds } from "../../agent-scope-config.js"; import { reserveChildAdmissionSlot } from "../../child-admission.js"; import { resolveSpawnAdmission, resolveSpawnMode } from "../../spawn-plan.js"; -import { listSwarmRunsForGroup } from "../../subagent-registry.js"; -import { normalizeSubagentTaskName } from "../../subagent-task-name.js"; +import { listSwarmRunsForGroup } from "../registry/subagent-registry.js"; import { resolveSwarmConfig } from "../swarm/swarm-config.js"; import { validateStructuredOutputSchema } from "../swarm/swarm-output-schema.js"; import { reserveSwarmRun } from "../swarm/swarm-scheduler.js"; @@ -26,6 +25,7 @@ import { resolveSubagentSpawnOwnership } from "./subagent-spawn-ownership.js"; import { resolveConfiguredSubagentRunTimeoutSeconds } from "./subagent-spawn-plan.js"; import { loadSubagentConfig } from "./subagent-spawn-session-patch.js"; import { resolveInternalSessionKey, resolveMainSessionAlias } from "./subagent-spawn.runtime.js"; +import { normalizeSubagentTaskName } from "./subagent-task-name.js"; type ResolvedSubagentSpawnRequest = { request: { diff --git a/src/agents/subagents/spawn/subagent-spawn.in-process-gateway.test.ts b/src/agents/subagents/spawn/subagent-spawn.in-process-gateway.test.ts index 17d9a0de101a..d84f52ec084b 100644 --- a/src/agents/subagents/spawn/subagent-spawn.in-process-gateway.test.ts +++ b/src/agents/subagents/spawn/subagent-spawn.in-process-gateway.test.ts @@ -25,12 +25,12 @@ import { tryBeginGatewayRootWorkAdmission, } from "../../../process/gateway-work-admission.js"; import { captureEnv, setTestEnvValue } from "../../../test-utils/env.js"; -import { subagentRuns } from "../../subagent-registry-memory.js"; -import { markSubagentRunTerminated } from "../../subagent-registry.js"; +import { subagentRuns } from "../registry/subagent-registry-memory.js"; +import { markSubagentRunTerminated } from "../registry/subagent-registry.js"; import { resetSubagentRegistryForTests, testing as subagentRegistryTesting, -} from "../../subagent-registry.test-helpers.js"; +} from "../registry/subagent-registry.test-helpers.js"; import { testing as swarmSchedulerTesting } from "../swarm/swarm-scheduler.test-support.js"; import { spawnSubagentDirect } from "./subagent-spawn.js"; import { testing as subagentSpawnTesting } from "./subagent-spawn.test-support.js"; diff --git a/src/agents/subagents/spawn/subagent-spawn.mode-session-diagnostics.test.ts b/src/agents/subagents/spawn/subagent-spawn.mode-session-diagnostics.test.ts index 2538a8f8bed4..13a395e38dff 100644 --- a/src/agents/subagents/spawn/subagent-spawn.mode-session-diagnostics.test.ts +++ b/src/agents/subagents/spawn/subagent-spawn.mode-session-diagnostics.test.ts @@ -10,7 +10,7 @@ import { describe('spawnSubagentDirect mode="session" diagnostics (#67400)', () => { const callGatewayMock = vi.fn(); let spawnSubagentDirect: typeof import("./subagent-spawn.js").spawnSubagentDirect; - let resetSubagentRegistryForTests: typeof import("../../subagent-registry.test-helpers.js").resetSubagentRegistryForTests; + let resetSubagentRegistryForTests: typeof import("../registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; beforeEach(async () => { callGatewayMock.mockReset(); @@ -68,7 +68,7 @@ describe('spawnSubagentDirect mode="session" diagnostics (#67400)', () => { describe('spawnSubagentDirect mode="session" with thread binding-capable channels (#67400)', () => { const callGatewayMock = vi.fn(); let spawnSubagentDirect: typeof import("./subagent-spawn.js").spawnSubagentDirect; - let resetSubagentRegistryForTests: typeof import("../../subagent-registry.test-helpers.js").resetSubagentRegistryForTests; + let resetSubagentRegistryForTests: typeof import("../registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; beforeEach(async () => { callGatewayMock.mockReset(); diff --git a/src/agents/subagents/spawn/subagent-spawn.model-session.test.ts b/src/agents/subagents/spawn/subagent-spawn.model-session.test.ts index 69d94663effd..73c81f27a6b8 100644 --- a/src/agents/subagents/spawn/subagent-spawn.model-session.test.ts +++ b/src/agents/subagents/spawn/subagent-spawn.model-session.test.ts @@ -13,7 +13,7 @@ import { const callGatewayMock = vi.fn(); const updateSessionStoreMock = vi.fn(); -let resetSubagentRegistryForTests: typeof import("../../subagent-registry.test-helpers.js").resetSubagentRegistryForTests; +let resetSubagentRegistryForTests: typeof import("../registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; let spawnSubagentDirect: typeof import("./subagent-spawn.js").spawnSubagentDirect; describe("spawnSubagentDirect runtime model persistence", () => { diff --git a/src/agents/subagents/spawn/subagent-spawn.runtime.ts b/src/agents/subagents/spawn/subagent-spawn.runtime.ts index 0e851eec084f..70cdd2c3c4c5 100644 --- a/src/agents/subagents/spawn/subagent-spawn.runtime.ts +++ b/src/agents/subagents/spawn/subagent-spawn.runtime.ts @@ -32,7 +32,7 @@ export { resolveAgentConfig } from "../../agent-scope.js"; export { AGENT_LANE_SUBAGENT } from "../../lanes.js"; export { loadPreparedModelCatalog } from "../../prepared-model-catalog.js"; export { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js"; -export { buildSubagentSystemPrompt } from "../../subagent-system-prompt.js"; +export { buildSubagentSystemPrompt } from "./subagent-system-prompt.js"; export { resolveInternalSessionKey, resolveMainSessionAlias, diff --git a/src/agents/subagents/spawn/subagent-spawn.test-helpers.ts b/src/agents/subagents/spawn/subagent-spawn.test-helpers.ts index a9ef3ebb0241..a9071e693ce4 100644 --- a/src/agents/subagents/spawn/subagent-spawn.test-helpers.ts +++ b/src/agents/subagents/spawn/subagent-spawn.test-helpers.ts @@ -383,11 +383,11 @@ export async function loadSubagentSpawnModuleForTest(params: { ...createDefaultSessionHelperMocks(), })); - vi.doMock("../../subagent-depth.js", () => ({ + vi.doMock("./subagent-depth.js", () => ({ getSubagentDepthFromSessionStore: params.getSubagentDepthFromSessionStore ?? (() => 0), })); - vi.doMock("../../subagent-registry.js", () => ({ + vi.doMock("../registry/subagent-registry.js", () => ({ completeCollectorLaunchCleanup: params.completeCollectorLaunchCleanupMock ?? vi.fn(), countActiveRunsForSession: params.countActiveRunsForSession ?? (() => 0), listSwarmRunsForGroup: params.listSwarmRunsForGroup ?? vi.fn(() => []), diff --git a/src/agents/subagents/spawn/subagent-spawn.test.ts b/src/agents/subagents/spawn/subagent-spawn.test.ts index 44e18db65fce..52dca40ae055 100644 --- a/src/agents/subagents/spawn/subagent-spawn.test.ts +++ b/src/agents/subagents/spawn/subagent-spawn.test.ts @@ -33,7 +33,7 @@ const hoisted = vi.hoisted(() => ({ configOverride: {} as Record, })); -let resetSubagentRegistryForTests: typeof import("../../subagent-registry.test-helpers.js").resetSubagentRegistryForTests; +let resetSubagentRegistryForTests: typeof import("../registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; let spawnSubagentDirect: typeof import("./subagent-spawn.js").spawnSubagentDirect; function createConfigOverride(overrides?: Record) { diff --git a/src/agents/subagents/spawn/subagent-spawn.ts b/src/agents/subagents/spawn/subagent-spawn.ts index 178e3cbfdd06..d7402e35b477 100644 --- a/src/agents/subagents/spawn/subagent-spawn.ts +++ b/src/agents/subagents/spawn/subagent-spawn.ts @@ -21,16 +21,16 @@ import { type SpawnBackendAdapter, summarizeSpawnError, } from "../../spawn-pipeline.js"; -import { - materializeSubagentAttachments, - type SubagentAttachmentReceiptFile, -} from "../../subagent-attachments.js"; import { completeCollectorLaunchCleanup, settleFailedQueuedSubagentLaunch, startQueuedSubagentRun, -} from "../../subagent-registry.js"; +} from "../registry/subagent-registry.js"; import { activateSwarmRun, removeQueuedSwarmRun } from "../swarm/swarm-scheduler.js"; +import { + materializeSubagentAttachments, + type SubagentAttachmentReceiptFile, +} from "./subagent-attachments.js"; import { resolveSubagentSpawnAcceptedNote } from "./subagent-spawn-accepted-note.js"; import { resolveSubagentChildPlan } from "./subagent-spawn-child-plan.js"; import { diff --git a/src/agents/subagents/spawn/subagent-spawn.workspace.test.ts b/src/agents/subagents/spawn/subagent-spawn.workspace.test.ts index 3edf17a9010b..f0acdecf8615 100644 --- a/src/agents/subagents/spawn/subagent-spawn.workspace.test.ts +++ b/src/agents/subagents/spawn/subagent-spawn.workspace.test.ts @@ -63,7 +63,7 @@ const hoisted = vi.hoisted(() => ({ })); let spawnSubagentDirect: typeof import("./subagent-spawn.js").spawnSubagentDirect; -let resetSubagentRegistryForTests: typeof import("../../subagent-registry.test-helpers.js").resetSubagentRegistryForTests; +let resetSubagentRegistryForTests: typeof import("../registry/subagent-registry.test-helpers.js").resetSubagentRegistryForTests; function createConfigOverride(overrides?: Record) { return createSubagentSpawnTestConfig("/tmp/workspace-main", { diff --git a/src/agents/subagent-system-prompt.ts b/src/agents/subagents/spawn/subagent-system-prompt.ts similarity index 96% rename from src/agents/subagent-system-prompt.ts rename to src/agents/subagents/spawn/subagent-system-prompt.ts index cb6ceada877d..51e7d1e9fcf1 100644 --- a/src/agents/subagent-system-prompt.ts +++ b/src/agents/subagents/spawn/subagent-system-prompt.ts @@ -4,8 +4,8 @@ * Produces role, completion, delegation, ACP, and native-command guidance for spawned child sessions. */ import { normalizeUniqueStringEntries } from "@openclaw/normalization-core/string-normalization"; -import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js"; -import type { DeliveryContext } from "../utils/delivery-context.types.js"; +import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../../../config/agent-limits.js"; +import type { DeliveryContext } from "../../../utils/delivery-context.types.js"; export function buildSubagentSystemPrompt(params: { requesterSessionKey?: string; diff --git a/src/agents/subagent-target-policy.test.ts b/src/agents/subagents/spawn/subagent-target-policy.test.ts similarity index 100% rename from src/agents/subagent-target-policy.test.ts rename to src/agents/subagents/spawn/subagent-target-policy.test.ts diff --git a/src/agents/subagent-target-policy.ts b/src/agents/subagents/spawn/subagent-target-policy.ts similarity index 98% rename from src/agents/subagent-target-policy.ts rename to src/agents/subagents/spawn/subagent-target-policy.ts index 4b5b17235eed..18da8045f33e 100644 --- a/src/agents/subagent-target-policy.ts +++ b/src/agents/subagents/spawn/subagent-target-policy.ts @@ -6,7 +6,7 @@ import { normalizeUniqueStringEntries, sortUniqueStrings, } from "@openclaw/normalization-core/string-normalization"; -import { normalizeAgentId } from "../routing/session-key.js"; +import { normalizeAgentId } from "../../../routing/session-key.js"; type SubagentTargetPolicyResult = { ok: true } | { ok: false; allowedText: string; error: string }; diff --git a/src/agents/subagent-task-name.ts b/src/agents/subagents/spawn/subagent-task-name.ts similarity index 100% rename from src/agents/subagent-task-name.ts rename to src/agents/subagents/spawn/subagent-task-name.ts diff --git a/src/agents/subagents/swarm/swarm-collector.ts b/src/agents/subagents/swarm/swarm-collector.ts index 2e66ae0e5913..cce0d1366bf5 100644 --- a/src/agents/subagents/swarm/swarm-collector.ts +++ b/src/agents/subagents/swarm/swarm-collector.ts @@ -1,10 +1,13 @@ import type { OpenClawConfig } from "../../../config/types.openclaw.js"; -import { ensureCompletionState } from "../../subagent-delivery-state.js"; -import { SUBAGENT_ENDED_REASON_KILLED } from "../../subagent-lifecycle-events.js"; -import { updateSubagentArchiveAtMs } from "../../subagent-registry-helpers.js"; -import type { SubagentRunRecord, SwarmCollectorStatus } from "../../subagent-registry.types.js"; -import { loadSubagentSessionEntry } from "../../subagent-session-reconciliation.js"; import { consumeSwarmStructuredOutput } from "../../tools/structured-output-tool.js"; +import { ensureCompletionState } from "../registry/subagent-delivery-state.js"; +import { SUBAGENT_ENDED_REASON_KILLED } from "../registry/subagent-lifecycle-events.js"; +import { updateSubagentArchiveAtMs } from "../registry/subagent-registry-helpers.js"; +import type { + SubagentRunRecord, + SwarmCollectorStatus, +} from "../registry/subagent-registry.types.js"; +import { loadSubagentSessionEntry } from "../registry/subagent-session-reconciliation.js"; function resolveStatus( entry: SubagentRunRecord, diff --git a/src/agents/system-prompt.test.ts b/src/agents/system-prompt.test.ts index 5f7895577391..47f0c9369369 100644 --- a/src/agents/system-prompt.test.ts +++ b/src/agents/system-prompt.test.ts @@ -8,7 +8,7 @@ import { listDeliverableMessageChannels } from "../utils/message-channel.js"; import { resolveOwnerPromptNumbers } from "./owner-display.js"; import { resolveAgentPromptSurfaceForSessionKey } from "./prompt-surface.js"; import { buildSkillWorkshopPromptSection } from "./skill-workshop-prompt.js"; -import { buildSubagentSystemPrompt } from "./subagent-system-prompt.js"; +import { buildSubagentSystemPrompt } from "./subagents/spawn/subagent-system-prompt.js"; import { buildAgentSystemPrompt } from "./system-prompt.js"; describe("buildAgentSystemPrompt", () => { diff --git a/src/agents/tools/agents-list-tool.ts b/src/agents/tools/agents-list-tool.ts index ff6ea30ffa40..88cf1e3b1e8a 100644 --- a/src/agents/tools/agents-list-tool.ts +++ b/src/agents/tools/agents-list-tool.ts @@ -10,7 +10,7 @@ import { resolveModelAgentRuntimeMetadata } from "../agent-runtime-metadata.js"; import { listAgentEntries, listAgentIds, resolveDefaultAgentId } from "../agent-scope-config.js"; import { resolveAgentConfig, resolveAgentEffectiveModelPrimary } from "../agent-scope.js"; import { resolveDefaultModelForAgent } from "../model-selection.js"; -import { resolveSubagentAllowedTargetIds } from "../subagent-target-policy.js"; +import { resolveSubagentAllowedTargetIds } from "../subagents/spawn/subagent-target-policy.js"; import type { AnyAgentTool } from "./common.js"; import { jsonResult } from "./common.js"; import { resolveInternalSessionKey, resolveMainSessionAlias } from "./sessions-helpers.js"; diff --git a/src/agents/tools/agents-wait-tool.test.ts b/src/agents/tools/agents-wait-tool.test.ts index 76b4f978daca..2dae62a205c0 100644 --- a/src/agents/tools/agents-wait-tool.test.ts +++ b/src/agents/tools/agents-wait-tool.test.ts @@ -1,10 +1,10 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { SubagentRunRecord } from "../subagent-registry.types.js"; +import type { SubagentRunRecord } from "../subagents/registry/subagent-registry.types.js"; const records = new Map(); const registryEvents = vi.hoisted(() => ({ listeners: new Set<() => void>() })); -vi.mock("../subagent-registry.js", () => ({ +vi.mock("../subagents/registry/subagent-registry.js", () => ({ getSubagentRunsByRunIds: (runIds: readonly string[]) => ({ entries: new Map( runIds.flatMap((runId) => { @@ -20,7 +20,7 @@ vi.mock("../subagent-registry.js", () => ({ }), })); -vi.mock("../subagent-registry-state.js", () => ({ +vi.mock("../subagents/registry/subagent-registry-state.js", () => ({ onSubagentRegistryPersisted: (listener: () => void) => { registryEvents.listeners.add(listener); return () => registryEvents.listeners.delete(listener); diff --git a/src/agents/tools/agents-wait-tool.ts b/src/agents/tools/agents-wait-tool.ts index 62c04ccc573d..deb4ce6cc723 100644 --- a/src/agents/tools/agents-wait-tool.ts +++ b/src/agents/tools/agents-wait-tool.ts @@ -1,10 +1,10 @@ import { Type } from "typebox"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { createAbortError } from "../../infra/abort-signal.js"; -import { resolveSubagentCompletionResultText } from "../subagent-completion-result.js"; -import { onSubagentRegistryPersisted } from "../subagent-registry-state.js"; -import { getSubagentRunsByRunIds } from "../subagent-registry.js"; -import type { SubagentRunRecord } from "../subagent-registry.types.js"; +import { resolveSubagentCompletionResultText } from "../subagents/completion/subagent-completion-result.js"; +import { onSubagentRegistryPersisted } from "../subagents/registry/subagent-registry-state.js"; +import { getSubagentRunsByRunIds } from "../subagents/registry/subagent-registry.js"; +import type { SubagentRunRecord } from "../subagents/registry/subagent-registry.types.js"; import { resolveSwarmConfig } from "../subagents/swarm/swarm-config.js"; import type { AnyAgentTool } from "./common.js"; import { jsonResult, ToolInputError } from "./common.js"; diff --git a/src/agents/tools/image-generate-tool.test.ts b/src/agents/tools/image-generate-tool.test.ts index 13f8c494b40b..9dabcb3bd0c8 100644 --- a/src/agents/tools/image-generate-tool.test.ts +++ b/src/agents/tools/image-generate-tool.test.ts @@ -32,7 +32,7 @@ const subagentAnnounceDeliveryMocks = vi.hoisted(() => ({ vi.mock("../../tasks/runtime-internal.js", () => taskRuntimeInternalMocks); vi.mock("../../tasks/detached-task-runtime.js", () => taskRuntimeMocks); -vi.mock("../subagent-announce-delivery.js", () => subagentAnnounceDeliveryMocks); +vi.mock("../subagents/announce/subagent-announce-delivery.js", () => subagentAnnounceDeliveryMocks); vi.mock("../../config/sessions/session-accessor.js", async (importOriginal) => ({ ...(await importOriginal()), loadSessionEntryReadOnly: sessionAccessorMocks.loadSessionEntryReadOnly, diff --git a/src/agents/tools/media-generate-background-shared.test.ts b/src/agents/tools/media-generate-background-shared.test.ts index 491aba549b03..43f83b1e1879 100644 --- a/src/agents/tools/media-generate-background-shared.test.ts +++ b/src/agents/tools/media-generate-background-shared.test.ts @@ -37,7 +37,7 @@ const sessionMocks = vi.hoisted(() => ({ loadSessionEntry: vi.fn<() => SessionEntry | undefined>(() => undefined), })); -vi.mock("../subagent-announce-delivery.js", () => subagentAnnounceDeliveryMocks); +vi.mock("../subagents/announce/subagent-announce-delivery.js", () => subagentAnnounceDeliveryMocks); vi.mock("../../config/sessions/session-accessor.js", async () => ({ ...(await vi.importActual( "../../config/sessions/session-accessor.js", diff --git a/src/agents/tools/media-generate-background-shared.ts b/src/agents/tools/media-generate-background-shared.ts index a0bb588e68c8..e7c4027e8e3c 100644 --- a/src/agents/tools/media-generate-background-shared.ts +++ b/src/agents/tools/media-generate-background-shared.ts @@ -38,8 +38,8 @@ import { MEDIA_GENERATION_DELIVERING_COMPLETION_PROGRESS } from "../media-genera import { deliverSubagentAnnouncement, loadRequesterSessionEntry, -} from "../subagent-announce-delivery.js"; -import { resolveAnnounceOrigin } from "../subagent-announce-origin.js"; +} from "../subagents/announce/subagent-announce-delivery.js"; +import { resolveAnnounceOrigin } from "../subagents/announce/subagent-announce-origin.js"; const log = createSubsystemLogger("agents/tools/media-generate-background-shared"); const MEDIA_GENERATION_TASK_KEEPALIVE_INTERVAL_MS = 60_000; diff --git a/src/agents/tools/media-generate-background.test.ts b/src/agents/tools/media-generate-background.test.ts index 34823d0c384c..bb9797387acc 100644 --- a/src/agents/tools/media-generate-background.test.ts +++ b/src/agents/tools/media-generate-background.test.ts @@ -21,7 +21,7 @@ import { vi.mock("../../tasks/detached-task-runtime.js", () => taskExecutorMocks); vi.mock("../../tasks/task-registry-delivery-runtime.js", () => taskDeliveryRuntimeMocks); -vi.mock("../subagent-announce-delivery.js", () => announceDeliveryMocks); +vi.mock("../subagents/announce/subagent-announce-delivery.js", () => announceDeliveryMocks); const { createImageGenerationTaskRun, diff --git a/src/agents/tools/sessions-send-tool.ts b/src/agents/tools/sessions-send-tool.ts index c7a1c2e7d76f..f5222b8b65d7 100644 --- a/src/agents/tools/sessions-send-tool.ts +++ b/src/agents/tools/sessions-send-tool.ts @@ -53,7 +53,7 @@ import { readLatestAssistantReplySnapshot, waitForAgentRunAndReadUpdatedAssistantReply, } from "../run-wait.js"; -import { loadSessionEntryByKey } from "../subagent-announce-delivery.js"; +import { loadSessionEntryByKey } from "../subagents/announce/subagent-announce-delivery.js"; import { describeSessionsSendTool, SESSIONS_SEND_TOOL_DISPLAY_SUMMARY, diff --git a/src/agents/tools/sessions-spawn-tool.test.ts b/src/agents/tools/sessions-spawn-tool.test.ts index 0747646273e3..1fb485fa23fb 100644 --- a/src/agents/tools/sessions-spawn-tool.test.ts +++ b/src/agents/tools/sessions-spawn-tool.test.ts @@ -42,7 +42,7 @@ vi.mock("../subagents/spawn/acp-spawn.js", () => ({ spawnAcpDirect: (...args: unknown[]) => hoisted.spawnAcpDirectMock(...args), })); -vi.mock("../subagent-registry.js", () => ({ +vi.mock("../subagents/registry/subagent-registry.js", () => ({ registerSubagentRun: (...args: unknown[]) => hoisted.registerSubagentRunMock(...args), getSubagentDeliveryBacklogPressure: () => hoisted.getSubagentDeliveryBacklogPressureMock(), })); diff --git a/src/agents/tools/sessions-spawn-tool.ts b/src/agents/tools/sessions-spawn-tool.ts index 6d4909cd0c80..d5fdac655b01 100644 --- a/src/agents/tools/sessions-spawn-tool.ts +++ b/src/agents/tools/sessions-spawn-tool.ts @@ -22,14 +22,14 @@ import { } from "../inherited-tool-deny.js"; import { optionalStringEnum } from "../schema/typebox.js"; import type { SpawnedToolContext } from "../spawned-context.js"; -import { resolveAcpSessionsSpawnImageAttachments } from "../subagent-attachments.js"; -import { getSubagentDeliveryBacklogPressure } from "../subagent-registry.js"; -import { normalizeSubagentTaskName } from "../subagent-task-name.js"; +import { getSubagentDeliveryBacklogPressure } from "../subagents/registry/subagent-registry.js"; +import { resolveAcpSessionsSpawnImageAttachments } from "../subagents/spawn/subagent-attachments.js"; import { SUBAGENT_SPAWN_CONTEXT_MODES, SUBAGENT_SPAWN_MODES, spawnSubagentDirect, } from "../subagents/spawn/subagent-spawn.js"; +import { normalizeSubagentTaskName } from "../subagents/spawn/subagent-task-name.js"; import { SWARM_CODE_MODE_IDEMPOTENCY_KEY, SWARM_CODE_MODE_REQUEST_FINGERPRINT, diff --git a/src/agents/tools/sessions-spawn-visible.ts b/src/agents/tools/sessions-spawn-visible.ts index 18ce16df0fd7..25ba92d849a8 100644 --- a/src/agents/tools/sessions-spawn-visible.ts +++ b/src/agents/tools/sessions-spawn-visible.ts @@ -18,11 +18,14 @@ import { reserveChildAdmissionSlot } from "../child-admission.js"; import { resolveSubagentSpawnModelSelection } from "../model-selection.js"; import { resolveSandboxRuntimeStatus } from "../sandbox/runtime-status.js"; import { resolveSpawnedWorkspaceInheritance } from "../spawned-context.js"; -import { getSubagentDepthFromSessionStore } from "../subagent-depth.js"; -import { countActiveRunsForSession, registerSubagentRun } from "../subagent-registry.js"; -import { resolveSubagentTargetPolicy } from "../subagent-target-policy.js"; +import { + countActiveRunsForSession, + registerSubagentRun, +} from "../subagents/registry/subagent-registry.js"; +import { getSubagentDepthFromSessionStore } from "../subagents/spawn/subagent-depth.js"; import { resolveSubagentSpawnOwnership } from "../subagents/spawn/subagent-spawn-ownership.js"; import { resolveConfiguredSubagentRunTimeoutSeconds } from "../subagents/spawn/subagent-spawn-plan.js"; +import { resolveSubagentTargetPolicy } from "../subagents/spawn/subagent-target-policy.js"; import { normalizeToolModelOverride, readStringParam, ToolInputError } from "./common.js"; import { callInProcessGatewayTool, diff --git a/src/agents/tools/structured-output-tool.test-support.ts b/src/agents/tools/structured-output-tool.test-support.ts index 620a1a8d2171..ed4c07a384f0 100644 --- a/src/agents/tools/structured-output-tool.test-support.ts +++ b/src/agents/tools/structured-output-tool.test-support.ts @@ -1,4 +1,4 @@ -import type { SwarmStructuredOutputState } from "../subagent-registry.types.js"; +import type { SwarmStructuredOutputState } from "../subagents/registry/subagent-registry.types.js"; import "./structured-output-tool.js"; type StructuredOutputToolTestApi = { diff --git a/src/agents/tools/structured-output-tool.ts b/src/agents/tools/structured-output-tool.ts index 1a25d4d93d43..35b30c9b4782 100644 --- a/src/agents/tools/structured-output-tool.ts +++ b/src/agents/tools/structured-output-tool.ts @@ -1,7 +1,7 @@ import { Type } from "typebox"; import { validateJsonSchemaValue } from "../../plugins/schema-validator.js"; import type { JsonSchemaObject } from "../../shared/json-schema.types.js"; -import type { SwarmStructuredOutputState } from "../subagent-registry.types.js"; +import type { SwarmStructuredOutputState } from "../subagents/registry/subagent-registry.types.js"; import type { AnyAgentTool } from "./common.js"; import { jsonResult, ToolInputError } from "./common.js"; diff --git a/src/agents/tools/subagents-tool.test.ts b/src/agents/tools/subagents-tool.test.ts index 5c1190881095..5f7f4063f092 100644 --- a/src/agents/tools/subagents-tool.test.ts +++ b/src/agents/tools/subagents-tool.test.ts @@ -2,12 +2,12 @@ import { describe, expect, it, vi } from "vitest"; import type { TaskRecord, TaskRuntime, TaskStatus } from "../../tasks/task-registry.types.js"; import { TASK_STATUS_DETAIL_MAX_CHARS } from "../../tasks/task-status.js"; -import { SUBAGENT_ENDED_REASON_KILLED } from "../subagent-lifecycle-events.js"; +import { SUBAGENT_ENDED_REASON_KILLED } from "../subagents/registry/subagent-lifecycle-events.js"; import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../subagent-registry.test-helpers.js"; -import type { SubagentRunRecord } from "../subagent-registry.types.js"; +} from "../subagents/registry/subagent-registry.test-helpers.js"; +import type { SubagentRunRecord } from "../subagents/registry/subagent-registry.types.js"; import { createSubagentsTool } from "./subagents-tool.js"; function task(params: { diff --git a/src/agents/tools/subagents-tool.ts b/src/agents/tools/subagents-tool.ts index 3304204ac000..bf2fc9768837 100644 --- a/src/agents/tools/subagents-tool.ts +++ b/src/agents/tools/subagents-tool.ts @@ -16,8 +16,8 @@ import { listControlledSubagentRuns, MAX_RECENT_MINUTES, resolveSubagentController, -} from "../subagent-control.js"; -import { buildSubagentList } from "../subagent-list.js"; +} from "../subagents/registry/subagent-control.js"; +import { buildSubagentList } from "../subagents/registry/subagent-list.js"; import type { AnyAgentTool } from "./common.js"; import { jsonResult, readPositiveIntegerParam, readStringParam } from "./common.js"; diff --git a/src/agents/tools/swarm-tools.integration.test.ts b/src/agents/tools/swarm-tools.integration.test.ts index 8666e444c1b0..7fd3e352a4f8 100644 --- a/src/agents/tools/swarm-tools.integration.test.ts +++ b/src/agents/tools/swarm-tools.integration.test.ts @@ -6,8 +6,8 @@ import { createOpenClawTools } from "../openclaw-tools.js"; import { resetSubagentRegistryForTests, testing as registryTesting, -} from "../subagent-registry.test-helpers.js"; -import "../subagent-registry.mocks.shared.js"; +} from "../subagents/registry/subagent-registry.test-helpers.js"; +import "../subagents/registry/subagent-registry.mocks.shared.js"; import { testing as spawnTesting } from "../subagents/spawn/subagent-spawn.test-support.js"; import { testing as swarmSchedulerTesting } from "../subagents/swarm/swarm-scheduler.test-support.js"; import { createAgentsWaitTool } from "./agents-wait-tool.js"; diff --git a/src/agents/web-search-tool-policy.ts b/src/agents/web-search-tool-policy.ts index 4cdecf173145..5276eebe2139 100644 --- a/src/agents/web-search-tool-policy.ts +++ b/src/agents/web-search-tool-policy.ts @@ -5,7 +5,7 @@ import { resolveRequesterToolPolicies } from "./requester-tool-policy.js"; import type { SandboxToolPolicy } from "./sandbox.js"; import type { ScheduledToolPolicyContext } from "./scheduled-tool-policy.js"; import { resolveSenderToolPolicy } from "./sender-tool-policy.js"; -import type { TrustedSubagentCompletionHandoff } from "./subagent-announce-handoff.js"; +import type { TrustedSubagentCompletionHandoff } from "./subagents/announce/subagent-announce-handoff.js"; import { isRuntimeToolAllowed, isToolAllowedByPolicies } from "./tool-policy-match.js"; import { mergeAlsoAllowPolicy, resolveToolProfilePolicy } from "./tool-policy.js"; diff --git a/src/auto-reply/reply/abort.test-support.ts b/src/auto-reply/reply/abort.test-support.ts index 84720b1aaaac..bf37560dd0b7 100644 --- a/src/auto-reply/reply/abort.test-support.ts +++ b/src/auto-reply/reply/abort.test-support.ts @@ -6,9 +6,9 @@ type AbortTestDeps = { resolveActiveEmbeddedRunSessionId: typeof import("../../agents/embedded-agent-runner/runs.js").resolveActiveEmbeddedRunSessionId; markSessionAbortTarget: typeof import("../../config/sessions/session-accessor.js").markSessionAbortTarget; resolveSessionAbortTarget: typeof import("../../config/sessions/session-accessor.js").resolveSessionAbortTarget; - getLatestSubagentRunByChildSessionKey: typeof import("../../agents/subagent-registry.js").getLatestSubagentRunByChildSessionKey; - listSubagentRunsForController: typeof import("../../agents/subagent-registry.js").listSubagentRunsForController; - killControlledSubagentRun: typeof import("../../agents/subagent-control.js").killControlledSubagentRun; + getLatestSubagentRunByChildSessionKey: typeof import("../../agents/subagents/registry/subagent-registry.js").getLatestSubagentRunByChildSessionKey; + listSubagentRunsForController: typeof import("../../agents/subagents/registry/subagent-registry.js").listSubagentRunsForController; + killControlledSubagentRun: typeof import("../../agents/subagents/registry/subagent-control.js").killControlledSubagentRun; }; type AbortTestApi = { diff --git a/src/auto-reply/reply/abort.test.ts b/src/auto-reply/reply/abort.test.ts index 862687af35a3..acb83d88a5b2 100644 --- a/src/auto-reply/reply/abort.test.ts +++ b/src/auto-reply/reply/abort.test.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { expectDefined } from "@openclaw/normalization-core"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { resolveSessionAgentId } from "../../agents/agent-scope.js"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.js"; import type { OpenClawConfig } from "../../config/config.js"; import { resolveStorePath } from "../../config/sessions.js"; import { @@ -76,7 +76,7 @@ const { subagentRegistryMocks, subagentRegistryDeps } = vi.hoisted(() => { (childSessionKey: string) => SubagentRunFixture | null >(() => null); const markSubagentRunTerminated = vi.fn< - typeof import("../../agents/subagent-registry.js").markSubagentRunTerminated + typeof import("../../agents/subagents/registry/subagent-registry.js").markSubagentRunTerminated >(() => 1); return { subagentRegistryMocks: { @@ -95,7 +95,7 @@ const { subagentRegistryMocks, subagentRegistryDeps } = vi.hoisted(() => { }; }); -vi.mock("../../agents/subagent-registry.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry.js", () => ({ getLatestSubagentRunByChildSessionKey: subagentRegistryDeps.getLatestSubagentRunByChildSessionKey, listSubagentRunsForRequester: subagentRegistryDeps.listSubagentRunsForRequester, listSubagentRunsForController: subagentRegistryDeps.listSubagentRunsForRequester, diff --git a/src/auto-reply/reply/abort.ts b/src/auto-reply/reply/abort.ts index 7c82cb1d30eb..1e6377886253 100644 --- a/src/auto-reply/reply/abort.ts +++ b/src/auto-reply/reply/abort.ts @@ -9,12 +9,12 @@ import { abortEmbeddedAgentRun, resolveActiveEmbeddedRunSessionId, } from "../../agents/embedded-agent-runner/runs.js"; -import { killControlledSubagentRun } from "../../agents/subagent-control.js"; +import { killControlledSubagentRun } from "../../agents/subagents/registry/subagent-control.js"; import { getLatestSubagentRunByChildSessionKey, listSubagentRunsForController, -} from "../../agents/subagent-registry.js"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.js"; +} from "../../agents/subagents/registry/subagent-registry.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.js"; import { resolveInternalSessionKey, resolveMainSessionAlias, diff --git a/src/auto-reply/reply/agent-runner-session-reset.ts b/src/auto-reply/reply/agent-runner-session-reset.ts index 285114ef347b..9a2c44d9786e 100644 --- a/src/auto-reply/reply/agent-runner-session-reset.ts +++ b/src/auto-reply/reply/agent-runner-session-reset.ts @@ -2,7 +2,7 @@ import { clearBootstrapSnapshotOnSessionBoundary } from "../../agents/bootstrap- import { clearAllCliSessions } from "../../agents/cli-session.js"; import { resetRegisteredAgentHarnessSessions } from "../../agents/harness/registry.js"; // Handles session reset requests produced during agent runner execution. -import { transitionMainSessionRecovery } from "../../agents/main-session-recovery-state.js"; +import { transitionMainSessionRecovery } from "../../agents/main-session-recovery/main-session-recovery-state.js"; import type { InternalSessionEntry as SessionEntry } from "../../config/sessions.js"; import { persistSessionResetLifecycle } from "../../config/sessions/session-accessor.js"; import { generateSecureUuid } from "../../infra/secure-random.js"; diff --git a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts index 5cf6574da0f7..17ffb664bec2 100644 --- a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts +++ b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts @@ -225,8 +225,9 @@ vi.mock("../../acp/control-plane/manager.js", () => ({ }), })); -vi.mock("../../agents/subagent-registry.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../../agents/subagents/registry/subagent-registry.js", async (importOriginal) => { + const actual = + await importOriginal(); return { ...actual, getSwarmRunByLaunchReplayKey: () => undefined, diff --git a/src/auto-reply/reply/commands-status-subagents.ts b/src/auto-reply/reply/commands-status-subagents.ts index 2dbd86845fa2..9d26c04817b8 100644 --- a/src/auto-reply/reply/commands-status-subagents.ts +++ b/src/auto-reply/reply/commands-status-subagents.ts @@ -1,5 +1,5 @@ // Formats subagent status rows for the status command response. -import type { SubagentRunRecord } from "../../agents/subagent-registry.types.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.types.js"; import { formatDurationCompact } from "../../infra/format-time/format-duration.ts"; import { formatRunLabel, sortSubagentRuns } from "./subagents-utils.js"; diff --git a/src/auto-reply/reply/commands-status.test.ts b/src/auto-reply/reply/commands-status.test.ts index 831faa4a5be2..49aa70ecb599 100644 --- a/src/auto-reply/reply/commands-status.test.ts +++ b/src/auto-reply/reply/commands-status.test.ts @@ -12,7 +12,7 @@ import type { AgentHarness } from "../../agents/harness/types.js"; import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../../agents/subagent-registry.test-helpers.js"; +} from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; import type { OpenClawConfig } from "../../config/config.js"; import { persistSessionTranscriptTurn, diff --git a/src/auto-reply/reply/commands-subagents-control.runtime.ts b/src/auto-reply/reply/commands-subagents-control.runtime.ts index c95e6a08d154..e6251e7c85b8 100644 --- a/src/auto-reply/reply/commands-subagents-control.runtime.ts +++ b/src/auto-reply/reply/commands-subagents-control.runtime.ts @@ -5,4 +5,4 @@ export { killControlledSubagentRun, sendControlledSubagentMessage, steerControlledSubagentRun, -} from "../../agents/subagent-control.js"; +} from "../../agents/subagents/registry/subagent-control.js"; diff --git a/src/auto-reply/reply/commands-subagents-dispatch.ts b/src/auto-reply/reply/commands-subagents-dispatch.ts index 8fa6fda24a93..7a27f149f334 100644 --- a/src/auto-reply/reply/commands-subagents-dispatch.ts +++ b/src/auto-reply/reply/commands-subagents-dispatch.ts @@ -1,5 +1,5 @@ // Dispatches subagent command actions after parsing the subcommand target. -import type { SubagentRunRecord } from "../../agents/subagent-registry.types.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.types.js"; import type { HandleCommandsParams } from "./commands-types.js"; export { diff --git a/src/auto-reply/reply/commands-subagents-focus.test.ts b/src/auto-reply/reply/commands-subagents-focus.test.ts index 94b57fa579b3..df0bb6ca64f1 100644 --- a/src/auto-reply/reply/commands-subagents-focus.test.ts +++ b/src/auto-reply/reply/commands-subagents-focus.test.ts @@ -105,7 +105,7 @@ vi.mock("../../infra/outbound/session-binding-service.js", () => ({ getSessionBindingService: () => buildFocusSessionBindingService(), })); -vi.mock("../../agents/subagent-capabilities.js", () => ({ +vi.mock("../../agents/subagents/spawn/subagent-capabilities.js", () => ({ resolveStoredSubagentCapabilities: (sessionKey: string, options: unknown) => hoisted.resolveStoredSubagentCapabilitiesMock(sessionKey, options), })); diff --git a/src/auto-reply/reply/commands-subagents.test.ts b/src/auto-reply/reply/commands-subagents.test.ts index a1e854164a65..03f8180739f5 100644 --- a/src/auto-reply/reply/commands-subagents.test.ts +++ b/src/auto-reply/reply/commands-subagents.test.ts @@ -7,18 +7,18 @@ import os from "node:os"; import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { SUBAGENT_ENDED_REASON_KILLED } from "../../agents/subagent-lifecycle-events.js"; -import { subagentRuns } from "../../agents/subagent-registry-memory.js"; +import { SUBAGENT_ENDED_REASON_KILLED } from "../../agents/subagents/registry/subagent-lifecycle-events.js"; +import { subagentRuns } from "../../agents/subagents/registry/subagent-registry-memory.js"; import { countPendingDescendantRunsFromRuns, listRunsForControllerFromRuns, -} from "../../agents/subagent-registry-queries.js"; -import { getSubagentRunsSnapshotForRead } from "../../agents/subagent-registry-state.js"; +} from "../../agents/subagents/registry/subagent-registry-queries.js"; +import { getSubagentRunsSnapshotForRead } from "../../agents/subagents/registry/subagent-registry-state.js"; import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../../agents/subagent-registry.test-helpers.js"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.types.js"; +} from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.types.js"; import type { OpenClawConfig } from "../../config/config.js"; import { failTaskRunByRunId } from "../../tasks/task-executor.js"; import { createTaskRecord } from "../../tasks/task-registry.js"; diff --git a/src/auto-reply/reply/commands-subagents/action-agents.ts b/src/auto-reply/reply/commands-subagents/action-agents.ts index 0b3b7279a07d..b9c1238a78ef 100644 --- a/src/auto-reply/reply/commands-subagents/action-agents.ts +++ b/src/auto-reply/reply/commands-subagents/action-agents.ts @@ -1,8 +1,8 @@ // Lists available agents for subagent spawn and focus commands. import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { subagentRuns } from "../../../agents/subagent-registry-memory.js"; -import { buildSubagentRunReadIndexFromRuns } from "../../../agents/subagent-registry-queries.js"; -import { getSubagentRunsSnapshotForRead } from "../../../agents/subagent-registry-state.js"; +import { subagentRuns } from "../../../agents/subagents/registry/subagent-registry-memory.js"; +import { buildSubagentRunReadIndexFromRuns } from "../../../agents/subagents/registry/subagent-registry-queries.js"; +import { getSubagentRunsSnapshotForRead } from "../../../agents/subagents/registry/subagent-registry-state.js"; import { getChannelPlugin, normalizeChannelId } from "../../../channels/plugins/index.js"; import { getSessionBindingService } from "../../../infra/outbound/session-binding-service.js"; import { resolveChannelAccountId, resolveCommandSurfaceChannel } from "../channel-context.js"; diff --git a/src/auto-reply/reply/commands-subagents/action-info.ts b/src/auto-reply/reply/commands-subagents/action-info.ts index 93ad5192fc64..38612ec08521 100644 --- a/src/auto-reply/reply/commands-subagents/action-info.ts +++ b/src/auto-reply/reply/commands-subagents/action-info.ts @@ -1,9 +1,9 @@ // Formats detailed subagent run information for the info action. import { timestampMsToIsoString } from "@openclaw/normalization-core/number-coercion"; -import { subagentRuns } from "../../../agents/subagent-registry-memory.js"; -import { countPendingDescendantRunsFromRuns } from "../../../agents/subagent-registry-queries.js"; -import { getSubagentRunsSnapshotForRead } from "../../../agents/subagent-registry-state.js"; -import { resolveSubagentDisplayStatus } from "../../../agents/subagent-session-metrics.js"; +import { subagentRuns } from "../../../agents/subagents/registry/subagent-registry-memory.js"; +import { countPendingDescendantRunsFromRuns } from "../../../agents/subagents/registry/subagent-registry-queries.js"; +import { getSubagentRunsSnapshotForRead } from "../../../agents/subagents/registry/subagent-registry-state.js"; +import { resolveSubagentDisplayStatus } from "../../../agents/subagents/registry/subagent-session-metrics.js"; import { resolveStorePath } from "../../../config/sessions/paths.js"; import { loadSessionEntryReadOnly } from "../../../config/sessions/session-accessor.js"; import { formatDurationCompact } from "../../../infra/format-time/format-duration.js"; diff --git a/src/auto-reply/reply/commands-subagents/action-list.ts b/src/auto-reply/reply/commands-subagents/action-list.ts index 7bf313ba4eed..8644fdadeb9b 100644 --- a/src/auto-reply/reply/commands-subagents/action-list.ts +++ b/src/auto-reply/reply/commands-subagents/action-list.ts @@ -1,5 +1,5 @@ // Lists subagent runs with focus and status information. -import { buildSubagentList } from "../../../agents/subagent-list.js"; +import { buildSubagentList } from "../../../agents/subagents/registry/subagent-list.js"; import type { CommandHandlerResult } from "../commands-types.js"; import { type SubagentsCommandContext, RECENT_WINDOW_MINUTES, stopWithText } from "./shared.js"; diff --git a/src/auto-reply/reply/commands-subagents/shared.ts b/src/auto-reply/reply/commands-subagents/shared.ts index f51f45f663fe..8309acac1e43 100644 --- a/src/auto-reply/reply/commands-subagents/shared.ts +++ b/src/auto-reply/reply/commands-subagents/shared.ts @@ -3,12 +3,12 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import { resolveStoredSubagentCapabilities } from "../../../agents/subagent-capabilities.js"; -import type { ResolvedSubagentController } from "../../../agents/subagent-control.js"; -import { subagentRuns } from "../../../agents/subagent-registry-memory.js"; -import { buildSubagentRunReadIndexFromRuns } from "../../../agents/subagent-registry-queries.js"; -import { getSubagentRunsSnapshotForRead } from "../../../agents/subagent-registry-state.js"; -import type { SubagentRunRecord } from "../../../agents/subagent-registry.types.js"; +import type { ResolvedSubagentController } from "../../../agents/subagents/registry/subagent-control.js"; +import { subagentRuns } from "../../../agents/subagents/registry/subagent-registry-memory.js"; +import { buildSubagentRunReadIndexFromRuns } from "../../../agents/subagents/registry/subagent-registry-queries.js"; +import { getSubagentRunsSnapshotForRead } from "../../../agents/subagents/registry/subagent-registry-state.js"; +import type { SubagentRunRecord } from "../../../agents/subagents/registry/subagent-registry.types.js"; +import { resolveStoredSubagentCapabilities } from "../../../agents/subagents/spawn/subagent-capabilities.js"; import { resolveInternalSessionKey, resolveMainSessionAlias, diff --git a/src/auto-reply/reply/dispatch-from-config.prepare-context.ts b/src/auto-reply/reply/dispatch-from-config.prepare-context.ts index 1612ba7ff537..45a37144f1df 100644 --- a/src/auto-reply/reply/dispatch-from-config.prepare-context.ts +++ b/src/auto-reply/reply/dispatch-from-config.prepare-context.ts @@ -12,7 +12,7 @@ import { import { isSubagentEnvelopeSession, resolveSubagentCapabilityStore, -} from "../../agents/subagent-capabilities.js"; +} from "../../agents/subagents/spawn/subagent-capabilities.js"; import { isToolAllowedByPolicies } from "../../agents/tool-policy-match.js"; import { mergeAlsoAllowPolicy, resolveToolProfilePolicy } from "../../agents/tool-policy.js"; import { resolveConversationBindingRecord } from "../../bindings/records.js"; diff --git a/src/auto-reply/reply/reply-plumbing.test.ts b/src/auto-reply/reply/reply-plumbing.test.ts index de7957c5e34a..dd137f9d7a0a 100644 --- a/src/auto-reply/reply/reply-plumbing.test.ts +++ b/src/auto-reply/reply/reply-plumbing.test.ts @@ -2,7 +2,7 @@ import { expectDefined } from "@openclaw/normalization-core"; import { afterEach, describe, expect, it } from "vitest"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.js"; import type { ChannelPlugin } from "../../channels/plugins/types.public.js"; import type { OpenClawConfig } from "../../config/config.js"; import { formatDurationCompact } from "../../infra/format-time/format-duration.js"; diff --git a/src/auto-reply/reply/reply-turn-admission.test.ts b/src/auto-reply/reply/reply-turn-admission.test.ts index b8a263222ce2..9de3ac2d789c 100644 --- a/src/auto-reply/reply/reply-turn-admission.test.ts +++ b/src/auto-reply/reply/reply-turn-admission.test.ts @@ -36,25 +36,35 @@ const recoveryOwnerReleaseMocks = vi.hoisted(() => ({ schedulePendingTarget: vi.fn(), })); -vi.mock("../../agents/main-session-recovery-store.js", async (importOriginal) => { - const actual = - await importOriginal(); - return { - ...actual, - releaseMainSessionRecoveryOwner: async ( - lease: Parameters[0], - options: Parameters[1], - ) => { - await recoveryOwnerReleaseMocks.beforeRelease(); - return await actual.releaseMainSessionRecoveryOwner(lease, options); - }, - }; -}); +vi.mock( + "../../agents/main-session-recovery/main-session-recovery-store.js", + async (importOriginal) => { + const actual = + await importOriginal< + typeof import("../../agents/main-session-recovery/main-session-recovery-store.js") + >(); + return { + ...actual, + releaseMainSessionRecoveryOwner: async ( + lease: Parameters[0], + options: Parameters[1], + ) => { + await recoveryOwnerReleaseMocks.beforeRelease(); + return await actual.releaseMainSessionRecoveryOwner(lease, options); + }, + }; + }, +); -vi.mock("../../agents/main-session-recovery-owner-release.js", async (importOriginal) => ({ - ...(await importOriginal()), - scheduleMainSessionRecoveryPendingTarget: recoveryOwnerReleaseMocks.schedulePendingTarget, -})); +vi.mock( + "../../agents/main-session-recovery/main-session-recovery-owner-release.js", + async (importOriginal) => ({ + ...(await importOriginal< + typeof import("../../agents/main-session-recovery/main-session-recovery-owner-release.js") + >()), + scheduleMainSessionRecoveryPendingTarget: recoveryOwnerReleaseMocks.schedulePendingTarget, + }), +); const tempDirs = useAutoCleanupTempDirTracker(afterEach); diff --git a/src/auto-reply/reply/reply-turn-admission.ts b/src/auto-reply/reply/reply-turn-admission.ts index e1d5ecda7aab..ba5fd4de1d33 100644 --- a/src/auto-reply/reply/reply-turn-admission.ts +++ b/src/auto-reply/reply/reply-turn-admission.ts @@ -1,11 +1,11 @@ -import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery-owner-release.js"; -import { isMainRestartRecoveryCandidate } from "../../agents/main-session-recovery-state.js"; +import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery/main-session-recovery-owner-release.js"; +import { isMainRestartRecoveryCandidate } from "../../agents/main-session-recovery/main-session-recovery-state.js"; import { claimMainSessionRecoveryOwner, releaseMainSessionRecoveryOwner, type MainSessionRecoveryPendingTarget, type MainSessionRecoveryOwnerLease, -} from "../../agents/main-session-recovery-store.js"; +} from "../../agents/main-session-recovery/main-session-recovery-store.js"; // Decides whether an inbound turn may start, queue, or abort a reply run. import { resolveSessionWorkStartError } from "../../config/sessions/lifecycle.js"; import { loadSessionEntry } from "../../config/sessions/session-accessor.js"; diff --git a/src/auto-reply/reply/restart-recovery-claim.test.ts b/src/auto-reply/reply/restart-recovery-claim.test.ts index d6610c04ced5..45af63781e26 100644 --- a/src/auto-reply/reply/restart-recovery-claim.test.ts +++ b/src/auto-reply/reply/restart-recovery-claim.test.ts @@ -4,7 +4,7 @@ import { useAutoCleanupTempDirTracker } from "../../../test/helpers/temp-dir.js" import { claimMainSessionRecoveryOwner, releaseMainSessionRecoveryOwner, -} from "../../agents/main-session-recovery-store.js"; +} from "../../agents/main-session-recovery/main-session-recovery-store.js"; import { loadSessionEntry, replaceSessionEntry, diff --git a/src/auto-reply/reply/session-parent-fork-prepare.ts b/src/auto-reply/reply/session-parent-fork-prepare.ts index 730231614951..a71b516172f9 100644 --- a/src/auto-reply/reply/session-parent-fork-prepare.ts +++ b/src/auto-reply/reply/session-parent-fork-prepare.ts @@ -1,5 +1,5 @@ // Prepares parent-context fork metadata for guarded reply session initialization. -import { buildMainSessionRecoveryClearPatch } from "../../agents/main-session-recovery-clear.js"; +import { buildMainSessionRecoveryClearPatch } from "../../agents/main-session-recovery/main-session-recovery-clear.js"; import type { InternalSessionEntry, SessionEntry } from "../../config/sessions.js"; import { forkSessionFromParent, resolveParentForkDecision } from "./session-fork.js"; diff --git a/src/auto-reply/reply/subagents-utils.test.ts b/src/auto-reply/reply/subagents-utils.test.ts index 476472d928cf..46a51854f6ff 100644 --- a/src/auto-reply/reply/subagents-utils.test.ts +++ b/src/auto-reply/reply/subagents-utils.test.ts @@ -1,6 +1,6 @@ // Tests subagent utility helpers for label, routing, and transcript handling. import { afterEach, describe, expect, it, vi } from "vitest"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.js"; import { resolveSubagentLabel, resolveSubagentTargetFromRuns, diff --git a/src/auto-reply/reply/subagents-utils.ts b/src/auto-reply/reply/subagents-utils.ts index 28610af5fa0a..c30f71ec53a9 100644 --- a/src/auto-reply/reply/subagents-utils.ts +++ b/src/auto-reply/reply/subagents-utils.ts @@ -3,7 +3,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.js"; import { sanitizeTaskStatusText } from "../../tasks/task-status.js"; import { truncateUtf16Safe } from "../../utils.js"; diff --git a/src/cli/gateway-cli/lifecycle-import-boundary.test.ts b/src/cli/gateway-cli/lifecycle-import-boundary.test.ts index bb89f9d2ce54..17cdac795e1e 100644 --- a/src/cli/gateway-cli/lifecycle-import-boundary.test.ts +++ b/src/cli/gateway-cli/lifecycle-import-boundary.test.ts @@ -22,8 +22,12 @@ describe("gateway lifecycle hub import boundaries", () => { // main-session-restart-recovery.ts also re-exports its -runtime sibling, // which the primed hub never calls. - expect(hub).toContain('from "../../agents/main-session-restart-recovery-marking.js"'); - expect(hub).not.toContain('from "../../agents/main-session-restart-recovery.js"'); + expect(hub).toContain( + 'from "../../agents/main-session-recovery/main-session-restart-recovery-marking.js"', + ); + expect(hub).not.toContain( + 'from "../../agents/main-session-recovery/main-session-restart-recovery.js"', + ); }); it("still primes the hub eagerly so signal handlers survive dist chunk rotation", () => { diff --git a/src/cli/gateway-cli/lifecycle.runtime.ts b/src/cli/gateway-cli/lifecycle.runtime.ts index 2e65f85c63a6..16696e6b16c3 100644 --- a/src/cli/gateway-cli/lifecycle.runtime.ts +++ b/src/cli/gateway-cli/lifecycle.runtime.ts @@ -9,7 +9,7 @@ export { listActiveEmbeddedRunSessionKeys, waitForActiveEmbeddedRuns, } from "../../agents/embedded-agent-runner/runs.js"; -export { markRestartAbortedMainSessions } from "../../agents/main-session-restart-recovery-marking.js"; +export { markRestartAbortedMainSessions } from "../../agents/main-session-recovery/main-session-restart-recovery-marking.js"; export { getRuntimeConfig } from "../../config/config.js"; export { respawnGatewayProcessForUpdate, diff --git a/src/cli/gateway-cli/run-loop.test.ts b/src/cli/gateway-cli/run-loop.test.ts index 43221ffaf777..de742299710a 100644 --- a/src/cli/gateway-cli/run-loop.test.ts +++ b/src/cli/gateway-cli/run-loop.test.ts @@ -233,7 +233,7 @@ vi.mock("../../agents/embedded-agent-runner/runs.js", () => ({ waitForActiveEmbeddedRuns: (timeoutMs?: number) => waitForActiveEmbeddedRuns(timeoutMs), })); -vi.mock("../../agents/main-session-restart-recovery-marking.js", () => ({ +vi.mock("../../agents/main-session-recovery/main-session-restart-recovery-marking.js", () => ({ markRestartAbortedMainSessions: (params: unknown) => markRestartAbortedMainSessions(params), })); diff --git a/src/commands/agent-command.test-mocks.ts b/src/commands/agent-command.test-mocks.ts index f907053eff5e..bd1b62f0cd8a 100644 --- a/src/commands/agent-command.test-mocks.ts +++ b/src/commands/agent-command.test-mocks.ts @@ -281,7 +281,7 @@ vi.mock("../agents/model-selection.js", () => { }; }); -vi.mock("../agents/subagent-announce.js", () => ({ +vi.mock("../agents/subagents/announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: vi.fn(), })); diff --git a/src/commands/doctor-main-session-recovery.ts b/src/commands/doctor-main-session-recovery.ts index 524d8d907e88..c4125e410bca 100644 --- a/src/commands/doctor-main-session-recovery.ts +++ b/src/commands/doctor-main-session-recovery.ts @@ -1,5 +1,5 @@ import { uniqueStrings } from "@openclaw/normalization-core/string-normalization"; -import { transitionMainSessionRecovery } from "../agents/main-session-recovery-state.js"; +import { transitionMainSessionRecovery } from "../agents/main-session-recovery/main-session-recovery-state.js"; import type { InternalSessionEntry } from "../config/sessions.js"; import { applySessionEntryReplacements, diff --git a/src/commands/doctor-state-integrity.ts b/src/commands/doctor-state-integrity.ts index c48c2911b46c..54fbc70aa615 100644 --- a/src/commands/doctor-state-integrity.ts +++ b/src/commands/doctor-state-integrity.ts @@ -16,7 +16,7 @@ import { clearWedgedSubagentRecoveryAbort, formatSubagentRecoveryWedgedReason, isSubagentRecoveryWedgedEntry, -} from "../agents/subagent-recovery-state.js"; +} from "../agents/subagents/registry/subagent-recovery-state.js"; import { formatCliCommand } from "../cli/command-format.js"; import { resolveOAuthDir, resolveStateDir } from "../config/paths.js"; import { diff --git a/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts b/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts index efc8b7c51e41..8e9f10cc0f53 100644 --- a/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts +++ b/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts @@ -5,7 +5,7 @@ import os from "node:os"; import path from "node:path"; import { performance } from "node:perf_hooks"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { recordAcpParentStreamEvents } from "../../agents/acp-parent-stream-store.sqlite.js"; +import { recordAcpParentStreamEvents } from "../../agents/subagents/spawn/acp-parent-stream-store.sqlite.js"; import { executeSqliteQuerySync, getNodeSqliteKysely } from "../../infra/kysely-sync.js"; import type { DB as OpenClawAgentKyselyDatabase } from "../../state/openclaw-agent-db.generated.js"; import { diff --git a/src/cron/isolated-agent.direct-delivery-core-channels.test.ts b/src/cron/isolated-agent.direct-delivery-core-channels.test.ts index 5351c50b25d7..1e42a84b48d1 100644 --- a/src/cron/isolated-agent.direct-delivery-core-channels.test.ts +++ b/src/cron/isolated-agent.direct-delivery-core-channels.test.ts @@ -1,7 +1,7 @@ // Direct delivery tests cover isolated agent delivery through core channel targets. import "./isolated-agent.mocks.js"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { runSubagentAnnounceFlow } from "../agents/subagent-announce.js"; +import { runSubagentAnnounceFlow } from "../agents/subagents/announce/subagent-announce.js"; import type { ChannelOutboundAdapter, ChannelOutboundContext, diff --git a/src/cron/isolated-agent.mocks.ts b/src/cron/isolated-agent.mocks.ts index a24b99858c9b..6b033786c0f9 100644 --- a/src/cron/isolated-agent.mocks.ts +++ b/src/cron/isolated-agent.mocks.ts @@ -65,7 +65,7 @@ vi.mock("../agents/runtime-plugins.js", () => ({ loadAgentRuntimePluginRegistryHandle: vi.fn(), })); -vi.mock("../agents/subagent-announce.js", () => ({ +vi.mock("../agents/subagents/announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: vi.fn(), })); diff --git a/src/cron/isolated-agent.test-setup.ts b/src/cron/isolated-agent.test-setup.ts index 5d55053f80a0..a4822a98a872 100644 --- a/src/cron/isolated-agent.test-setup.ts +++ b/src/cron/isolated-agent.test-setup.ts @@ -3,7 +3,7 @@ import { expectDefined } from "@openclaw/normalization-core"; import { vi } from "vitest"; import { runEmbeddedAgent } from "../agents/embedded-agent.js"; import { loadPreparedModelCatalog } from "../agents/prepared-model-catalog.js"; -import { runSubagentAnnounceFlow } from "../agents/subagent-announce.js"; +import { runSubagentAnnounceFlow } from "../agents/subagents/announce/subagent-announce.js"; import type { ChannelOutboundAdapter, ChannelOutboundContext, diff --git a/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts b/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts index d6db580ba9b2..b11795dea841 100644 --- a/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts +++ b/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts @@ -82,7 +82,7 @@ vi.mock("../../config/sessions/main-session.js", () => ({ resolveMainSessionKey: vi.fn(() => "global"), })); -vi.mock("../../agents/subagent-registry-read.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry-read.js", () => ({ countActiveDescendantRuns: countActiveDescendantRunsMock, })); @@ -153,7 +153,7 @@ vi.mock("./subagent-followup.runtime.js", () => ({ import { retireSessionMcpRuntime } from "../../agents/agent-bundle-mcp-tools.js"; // Import after mocks -import { countActiveDescendantRuns } from "../../agents/subagent-registry-read.js"; +import { countActiveDescendantRuns } from "../../agents/subagents/registry/subagent-registry-read.js"; import { appendAssistantMessageToSessionTranscript } from "../../config/sessions/transcript.runtime.js"; import { callGateway } from "../../gateway/call.runtime.js"; import { PlatformMessageNotDispatchedError } from "../../infra/outbound/deliver-types.js"; diff --git a/src/cron/isolated-agent/delivery-dispatch.named-agent.test.ts b/src/cron/isolated-agent/delivery-dispatch.named-agent.test.ts index f013d357c44b..21e5d4d2152d 100644 --- a/src/cron/isolated-agent/delivery-dispatch.named-agent.test.ts +++ b/src/cron/isolated-agent/delivery-dispatch.named-agent.test.ts @@ -2,10 +2,10 @@ import { describe, expect, it, vi } from "vitest"; // Mock the announce flow dependencies to test the fallback behavior. -vi.mock("../../agents/subagent-announce.js", () => ({ +vi.mock("../../agents/subagents/announce/subagent-announce.js", () => ({ runSubagentAnnounceFlow: vi.fn(), })); -vi.mock("../../agents/subagent-registry-read.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry-read.js", () => ({ countActiveDescendantRuns: vi.fn().mockReturnValue(0), })); diff --git a/src/cron/isolated-agent/delivery-subagent-registry.runtime.ts b/src/cron/isolated-agent/delivery-subagent-registry.runtime.ts index ffdca326890e..5c3b45686506 100644 --- a/src/cron/isolated-agent/delivery-subagent-registry.runtime.ts +++ b/src/cron/isolated-agent/delivery-subagent-registry.runtime.ts @@ -1,2 +1,2 @@ // Runtime subagent registry seam for isolated-agent delivery gating. -export { countActiveDescendantRuns } from "../../agents/subagent-registry-read.js"; +export { countActiveDescendantRuns } from "../../agents/subagents/registry/subagent-registry-read.js"; diff --git a/src/cron/isolated-agent/run-subagent-registry.runtime.ts b/src/cron/isolated-agent/run-subagent-registry.runtime.ts index 34d7ef80abec..fbd3f862d5f8 100644 --- a/src/cron/isolated-agent/run-subagent-registry.runtime.ts +++ b/src/cron/isolated-agent/run-subagent-registry.runtime.ts @@ -2,4 +2,4 @@ export { countActiveDescendantRuns, listDescendantRunsForRequester, -} from "../../agents/subagent-registry.js"; +} from "../../agents/subagents/registry/subagent-registry.js"; diff --git a/src/cron/isolated-agent/subagent-followup.test.ts b/src/cron/isolated-agent/subagent-followup.test.ts index 3be6de83396b..67b3399a18b2 100644 --- a/src/cron/isolated-agent/subagent-followup.test.ts +++ b/src/cron/isolated-agent/subagent-followup.test.ts @@ -1,6 +1,6 @@ // Subagent followup tests cover followup handling after isolated cron agent runs. import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import type { SubagentRunRecord } from "../../agents/subagent-registry.types.js"; +import type { SubagentRunRecord } from "../../agents/subagents/registry/subagent-registry.types.js"; // vi.hoisted runs before module imports, ensuring FAST_TEST_MODE is picked up. vi.hoisted(() => { @@ -13,7 +13,7 @@ import { waitForDescendantSubagentSummary, } from "./subagent-followup.js"; -vi.mock("../../agents/subagent-registry-read.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry-read.js", () => ({ listDescendantRunsForRequester: vi.fn().mockReturnValue([]), })); @@ -31,7 +31,8 @@ vi.mock("../../gateway/call.js", () => ({ callGateway: vi.fn().mockResolvedValue({ status: "ok" }), })); -const { listDescendantRunsForRequester } = await import("../../agents/subagent-registry-read.js"); +const { listDescendantRunsForRequester } = + await import("../../agents/subagents/registry/subagent-registry-read.js"); const { readLatestAssistantReply } = await import("../../agents/run-wait.js"); const { callGateway } = await import("../../gateway/call.js"); diff --git a/src/cron/isolated-agent/subagent-followup.ts b/src/cron/isolated-agent/subagent-followup.ts index 70abee6a9292..95032ba17ecb 100644 --- a/src/cron/isolated-agent/subagent-followup.ts +++ b/src/cron/isolated-agent/subagent-followup.ts @@ -1,6 +1,6 @@ /** Reads or waits for descendant subagent summaries after isolated cron orchestration. */ import { readLatestAssistantReply, waitForAgentRunsToDrain } from "../../agents/run-wait.js"; -import { listDescendantRunsForRequester } from "../../agents/subagent-registry-read.js"; +import { listDescendantRunsForRequester } from "../../agents/subagents/registry/subagent-registry-read.js"; import { stripHeartbeatToken } from "../../auto-reply/heartbeat.js"; import { HEARTBEAT_TOKEN, diff --git a/src/gateway/agent-turn/agent-request-preflight.test.ts b/src/gateway/agent-turn/agent-request-preflight.test.ts index 1210d48df7fa..6c9d6322f421 100644 --- a/src/gateway/agent-turn/agent-request-preflight.test.ts +++ b/src/gateway/agent-turn/agent-request-preflight.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { subagentRuns } from "../../agents/subagent-registry-memory.js"; +import { subagentRuns } from "../../agents/subagents/registry/subagent-registry-memory.js"; import * as sessionAccessor from "../../config/sessions/session-accessor.js"; import { prepareAgentRequestPreflight } from "./agent-request-preflight.js"; import { createAgentTurnService } from "./agent-turn-service.js"; diff --git a/src/gateway/agent-turn/agent-request-preflight.ts b/src/gateway/agent-turn/agent-request-preflight.ts index d253847551d6..d76a74d0b133 100644 --- a/src/gateway/agent-turn/agent-request-preflight.ts +++ b/src/gateway/agent-turn/agent-request-preflight.ts @@ -7,7 +7,7 @@ import { normalizeSpawnedRunMetadata } from "../../agents/spawned-context.js"; import { findAuthorizedSwarmCollectorRequest, findSwarmCollectorSession, -} from "../../agents/subagent-registry-memory.js"; +} from "../../agents/subagents/registry/subagent-registry-memory.js"; import { resolveSwarmConfig } from "../../agents/subagents/swarm/swarm-config.js"; import { validateStructuredOutputSchema } from "../../agents/subagents/swarm/swarm-output-schema.js"; import { resolveAgentIdFromSessionKey, resolveStorePath } from "../../config/sessions.js"; diff --git a/src/gateway/agent-turn/agent-run-admission-phase.ts b/src/gateway/agent-turn/agent-run-admission-phase.ts index 3032955f1d28..44b5493da3dd 100644 --- a/src/gateway/agent-turn/agent-run-admission-phase.ts +++ b/src/gateway/agent-turn/agent-run-admission-phase.ts @@ -8,13 +8,13 @@ import { import { commitMainSessionRecovery, type MainSessionRecoveryPendingTarget, -} from "../../agents/main-session-recovery-store.js"; +} from "../../agents/main-session-recovery/main-session-recovery-store.js"; import { resolvePersistedOverrideModelRef } from "../../agents/model-selection.js"; import { resolveProviderIdForAuth } from "../../agents/provider-auth-aliases.js"; import { resolveExactSubagentCompletionEvent, type TrustedSubagentCompletionHandoff, -} from "../../agents/subagent-announce-handoff.js"; +} from "../../agents/subagents/announce/subagent-announce-handoff.js"; import { resolveEffectiveAgentRuntime } from "../../agents/thinking-runtime.js"; import { resolveAgentTimeoutMs } from "../../agents/timeout.js"; import type { SessionEntry } from "../../config/sessions.js"; diff --git a/src/gateway/agent-turn/agent-run-dispatch.ts b/src/gateway/agent-turn/agent-run-dispatch.ts index c4a0214ff02d..f7a6296d7a68 100644 --- a/src/gateway/agent-turn/agent-run-dispatch.ts +++ b/src/gateway/agent-turn/agent-run-dispatch.ts @@ -6,7 +6,7 @@ import { } from "../../agents/agent-run-terminal-outcome.js"; import { runWithCronCreatorAuthority } from "../../agents/cron-creator-authority-context.js"; import { isTimeoutError } from "../../agents/failover-error.js"; -import type { MainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery-store.js"; +import type { MainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery/main-session-recovery-store.js"; import { isAgentRunRestartAbortReason } from "../../agents/run-termination.js"; import { normalizeAgentRunTimeoutPhase } from "../../agents/run-timeout-attribution.js"; import { agentCommandFromGatewayIngress } from "../../commands/agent.js"; diff --git a/src/gateway/agent-turn/agent-run-execution-phase.ts b/src/gateway/agent-turn/agent-run-execution-phase.ts index 904fa9828109..f2f6e2fc8d58 100644 --- a/src/gateway/agent-turn/agent-run-execution-phase.ts +++ b/src/gateway/agent-turn/agent-run-execution-phase.ts @@ -12,13 +12,13 @@ import { type ExecApprovalContinuationPromptRange, } from "../../agents/bash-tools.exec-approval-output.js"; import { runAgentHarnessBeforeMessageWriteHook } from "../../agents/harness/hook-helpers.js"; -import { repairMainSessionRecoveryMutation } from "../../agents/main-session-recovery-lifecycle.js"; -import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery-owner-release.js"; +import { repairMainSessionRecoveryMutation } from "../../agents/main-session-recovery/main-session-recovery-lifecycle.js"; +import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery/main-session-recovery-owner-release.js"; import { releaseMainSessionRecoveryOwner, type MainSessionRecoveryPendingTarget, type MainSessionRecoveryOwnerLease, -} from "../../agents/main-session-recovery-store.js"; +} from "../../agents/main-session-recovery/main-session-recovery-store.js"; import { resolveScheduledToolPolicyContext } from "../../agents/scheduled-tool-policy.js"; import { resolveIngressWorkspaceOverrideForSessionRun } from "../../agents/spawned-context.js"; import { isExecutionIdentityCollectionEnabled } from "../../audit/audit-config.js"; diff --git a/src/gateway/agent-turn/agent-session-persist.ts b/src/gateway/agent-turn/agent-session-persist.ts index cf05ae90af96..a81ce41c72c7 100644 --- a/src/gateway/agent-turn/agent-session-persist.ts +++ b/src/gateway/agent-turn/agent-session-persist.ts @@ -1,9 +1,9 @@ import { randomUUID } from "node:crypto"; import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { ErrorCodes, errorShape } from "../../../packages/gateway-protocol/src/index.js"; -import { transitionMainSessionRecovery } from "../../agents/main-session-recovery-state.js"; -import type { MainSessionRecoveryOwnerLease } from "../../agents/main-session-recovery-store.js"; -import { MAX_RECOVERY_RETRIES } from "../../agents/main-session-restart-recovery-shared.js"; +import { transitionMainSessionRecovery } from "../../agents/main-session-recovery/main-session-recovery-state.js"; +import type { MainSessionRecoveryOwnerLease } from "../../agents/main-session-recovery/main-session-recovery-store.js"; +import { MAX_RECOVERY_RETRIES } from "../../agents/main-session-recovery/main-session-restart-recovery-shared.js"; import { mergeSessionEntry, resolveSessionLifecycleTimestamps, diff --git a/src/gateway/agent-turn/agent-turn-service.ts b/src/gateway/agent-turn/agent-turn-service.ts index 2e3778c57c09..23542d6a77dd 100644 --- a/src/gateway/agent-turn/agent-turn-service.ts +++ b/src/gateway/agent-turn/agent-turn-service.ts @@ -4,11 +4,11 @@ import { errorShape, type AgentWaitParams, } from "../../../packages/gateway-protocol/src/index.js"; -import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery-owner-release.js"; +import { scheduleMainSessionRecoveryPendingTarget } from "../../agents/main-session-recovery/main-session-recovery-owner-release.js"; import { releaseMainSessionRecoveryOwner, type MainSessionRecoveryOwnerLease, -} from "../../agents/main-session-recovery-store.js"; +} from "../../agents/main-session-recovery/main-session-recovery-store.js"; import { mergeSessionEntry, type SessionEntry } from "../../config/sessions.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { getAgentEventLifecycleGeneration } from "../../infra/agent-events.js"; diff --git a/src/gateway/approval-session-audience.test.ts b/src/gateway/approval-session-audience.test.ts index b1c0794d8997..b3839c568b84 100644 --- a/src/gateway/approval-session-audience.test.ts +++ b/src/gateway/approval-session-audience.test.ts @@ -28,7 +28,7 @@ const buildLatestSubagentRunReadIndexMock = vi.fn(() => ({ vi.mock("../config/io.js", () => ({ getRuntimeConfig: () => getRuntimeConfigMock(), })); -vi.mock("../agents/subagent-registry-read.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-registry-read.js", () => ({ buildLatestSubagentRunReadIndex: () => buildLatestSubagentRunReadIndexMock(), })); vi.mock("../config/sessions/session-accessor.js", () => ({ diff --git a/src/gateway/approval-session-audience.ts b/src/gateway/approval-session-audience.ts index 876ebc12ee2d..887ab3a13d16 100644 --- a/src/gateway/approval-session-audience.ts +++ b/src/gateway/approval-session-audience.ts @@ -1,5 +1,5 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; -import { buildLatestSubagentRunReadIndex } from "../agents/subagent-registry-read.js"; +import { buildLatestSubagentRunReadIndex } from "../agents/subagents/registry/subagent-registry-read.js"; import { getRuntimeConfig } from "../config/io.js"; import { loadSessionEntryReadOnly } from "../config/sessions/session-accessor.js"; import type { SessionEntry } from "../config/sessions/types.js"; diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index 2480e3b982c7..addfd90c0d69 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -3176,7 +3176,7 @@ async function verifyGatewayUltraSubagentHandoff(params: { thinkingLevel: string; }): Promise { const { listSubagentRunsForRequester } = - await import("../agents/subagent-registry.test-helpers.js"); + await import("../agents/subagents/registry/subagent-registry.test-helpers.js"); const existingRunIds = new Set( listSubagentRunsForRequester(params.sessionKey).map((entry) => entry.runId), ); diff --git a/src/gateway/server-lifecycle.ts b/src/gateway/server-lifecycle.ts index a0dda859debb..d3c9430c893c 100644 --- a/src/gateway/server-lifecycle.ts +++ b/src/gateway/server-lifecycle.ts @@ -443,7 +443,7 @@ export async function prepareGatewayLifecycle(params: { return; } const { markRestartAbortedMainSessions } = - await import("../agents/main-session-restart-recovery.js"); + await import("../agents/main-session-recovery/main-session-restart-recovery.js"); await markRestartAbortedMainSessions({ cfg: getRuntimeConfig(), sessionKeys, diff --git a/src/gateway/server-methods/agent-session-patch.ts b/src/gateway/server-methods/agent-session-patch.ts index 1f8bf678765d..43a17646647c 100644 --- a/src/gateway/server-methods/agent-session-patch.ts +++ b/src/gateway/server-methods/agent-session-patch.ts @@ -1,7 +1,7 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { resolveTrustedGroupId } from "../../agents/agent-tools.policy.js"; import { clearAllCliSessions } from "../../agents/cli-session.js"; -import { buildMainSessionRecoveryClearPatch } from "../../agents/main-session-recovery-clear.js"; +import { buildMainSessionRecoveryClearPatch } from "../../agents/main-session-recovery/main-session-recovery-clear.js"; import { evaluateSessionFreshness, hasTerminalMainSessionTranscriptNewerThanRegistrySync, diff --git a/src/gateway/server-methods/agent-task-tracking.ts b/src/gateway/server-methods/agent-task-tracking.ts index bd8c3d557034..96f0f7071cb6 100644 --- a/src/gateway/server-methods/agent-task-tracking.ts +++ b/src/gateway/server-methods/agent-task-tracking.ts @@ -169,7 +169,7 @@ export async function registerPluginSubagentRunFromGateway(params: { }); const requesterSessionKey = params.requester?.sessionKey ?? ownerSessionKey; const { adoptPausedSubagentRunForFollowUp, registerSubagentRun } = - await import("../../agents/subagent-registry.js"); + await import("../../agents/subagents/registry/subagent-registry.js"); // A follow-up aimed at a session paused by sessions_yield continues that run. // Registering a sibling row here would reassign the requester to this agent's // own main session and leave the original requester waiting behind a row that diff --git a/src/gateway/server-methods/agent.sessions-and-models.test-utils.ts b/src/gateway/server-methods/agent.sessions-and-models.test-utils.ts index 223a7c80cbf0..a02578af5b52 100644 --- a/src/gateway/server-methods/agent.sessions-and-models.test-utils.ts +++ b/src/gateway/server-methods/agent.sessions-and-models.test-utils.ts @@ -9,7 +9,7 @@ import { getSubagentRunByChildSessionKey, listSubagentRunsForRequester, resetSubagentRegistryForTests, -} from "../../agents/subagent-registry.test-helpers.js"; +} from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js"; import { findTaskByRunId, diff --git a/src/gateway/server-methods/agent.test-harness.ts b/src/gateway/server-methods/agent.test-harness.ts index 6f417b90a032..010bfa3c4442 100644 --- a/src/gateway/server-methods/agent.test-harness.ts +++ b/src/gateway/server-methods/agent.test-harness.ts @@ -4,8 +4,8 @@ import { expectDefined } from "@openclaw/normalization-core"; import { expect, vi } from "vitest"; import type { readAcpSessionMeta } from "../../acp/runtime/session-meta.js"; import type { AgentInternalEvent } from "../../agents/internal-events.js"; -import { setSubagentRegistryDepsForTest } from "../../agents/subagent-registry-deps.js"; -import { resetSubagentRegistryForTests } from "../../agents/subagent-registry.test-helpers.js"; +import { setSubagentRegistryDepsForTest } from "../../agents/subagents/registry/subagent-registry-deps.js"; +import { resetSubagentRegistryForTests } from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; import type { SessionEntry } from "../../config/sessions.js"; import type { SessionTranscriptStats } from "../../config/sessions/session-accessor.js"; import { resetDiagnosticEventsForTest } from "../../infra/diagnostic-events.js"; @@ -227,12 +227,14 @@ vi.mock("../../infra/agent-run-registry.js", () => ({ // Only the lookup this harness asserts on is stubbed; the rest of the read // surface stays real so registry paths reached through the gateway (paused-run // adoption, descendant queries) observe the runs these tests seed. -vi.mock("../../agents/subagent-registry-read.js", async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock("../../agents/subagents/registry/subagent-registry-read.js", async (importOriginal) => ({ + ...(await importOriginal< + typeof import("../../agents/subagents/registry/subagent-registry-read.js") + >()), getLatestSubagentRunByChildSessionKey: mocks.getLatestSubagentRunByChildSessionKey, })); -vi.mock("../../agents/subagent-registry-runtime.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry-runtime.js", () => ({ replaceSubagentRunAfterSteer: mocks.replaceSubagentRunAfterSteer, })); diff --git a/src/gateway/server-methods/chat-restart-recovery.ts b/src/gateway/server-methods/chat-restart-recovery.ts index 8c50aef3f06b..d74801507528 100644 --- a/src/gateway/server-methods/chat-restart-recovery.ts +++ b/src/gateway/server-methods/chat-restart-recovery.ts @@ -168,7 +168,7 @@ export async function resolveDurableChatClaim(params: { } try { const { retryRestartAbortedMainSessionRecovery } = - await import("../../agents/main-session-restart-recovery.js"); + await import("../../agents/main-session-recovery/main-session-restart-recovery.js"); await retryRestartAbortedMainSessionRecovery({ canonicalSessionKey: params.canonicalSessionKey, cfg: params.cfg, diff --git a/src/gateway/server-methods/sessions-read-cache.test.ts b/src/gateway/server-methods/sessions-read-cache.test.ts index fc454721d671..c43f1b51af03 100644 --- a/src/gateway/server-methods/sessions-read-cache.test.ts +++ b/src/gateway/server-methods/sessions-read-cache.test.ts @@ -3,7 +3,7 @@ import type { SessionsListParams } from "../../../packages/gateway-protocol/src/ import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../../agents/subagent-registry.test-helpers.js"; +} from "../../agents/subagents/registry/subagent-registry.test-helpers.js"; import { createReplyOperation } from "../../auto-reply/reply/reply-run-registry.js"; import { loadSessionEntry, diff --git a/src/gateway/server-methods/sessions.send-followup-status.test.ts b/src/gateway/server-methods/sessions.send-followup-status.test.ts index d729a8aaa563..a0b6999fa915 100644 --- a/src/gateway/server-methods/sessions.send-followup-status.test.ts +++ b/src/gateway/server-methods/sessions.send-followup-status.test.ts @@ -65,10 +65,10 @@ vi.mock("../session-transcript-readers.js", async () => { }; }); -vi.mock("../../agents/subagent-registry-read.js", async () => { - const actual = await vi.importActual( - "../../agents/subagent-registry-read.js", - ); +vi.mock("../../agents/subagents/registry/subagent-registry-read.js", async () => { + const actual = await vi.importActual< + typeof import("../../agents/subagents/registry/subagent-registry-read.js") + >("../../agents/subagents/registry/subagent-registry-read.js"); return { ...actual, getLatestSubagentRunByChildSessionKey: (...args: unknown[]) => @@ -76,7 +76,7 @@ vi.mock("../../agents/subagent-registry-read.js", async () => { }; }); -vi.mock("../../agents/subagent-registry-runtime.js", () => ({ +vi.mock("../../agents/subagents/registry/subagent-registry-runtime.js", () => ({ replaceSubagentRunAfterSteer: (...args: unknown[]) => replaceSubagentRunAfterSteerMock(...args), })); diff --git a/src/gateway/server-methods/tasks.ts b/src/gateway/server-methods/tasks.ts index 741cae833f0e..47a487a915d7 100644 --- a/src/gateway/server-methods/tasks.ts +++ b/src/gateway/server-methods/tasks.ts @@ -15,7 +15,7 @@ import { resolveDefaultAgentId } from "../../agents/agent-scope.js"; import { dismissSubagentCompletionDelivery, retrySubagentCompletionDelivery, -} from "../../agents/subagent-completion-delivery.js"; +} from "../../agents/subagents/completion/subagent-completion-delivery.js"; import { canonicalizeMainSessionAlias } from "../../config/sessions.js"; import { parseAgentSessionKey } from "../../routing/session-key.js"; import { getTaskById, listTaskRecordPage } from "../../tasks/runtime-internal.js"; diff --git a/src/gateway/server-plugins.ts b/src/gateway/server-plugins.ts index f7b43259f4f6..813674b7ddfd 100644 --- a/src/gateway/server-plugins.ts +++ b/src/gateway/server-plugins.ts @@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto"; import { performance } from "node:perf_hooks"; import { uniqueStrings } from "@openclaw/normalization-core/string-normalization"; -import type { SubagentCompletionToolHandoffRegistration } from "../agents/subagent-announce-handoff.js"; +import type { SubagentCompletionToolHandoffRegistration } from "../agents/subagents/announce/subagent-announce-handoff.js"; import type { AmbientEnvTriggerPolicy } from "../channels/config-presence.js"; import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; diff --git a/src/gateway/server-reload-handlers.test.ts b/src/gateway/server-reload-handlers.test.ts index 7879d2fda174..10697fe868b9 100644 --- a/src/gateway/server-reload-handlers.test.ts +++ b/src/gateway/server-reload-handlers.test.ts @@ -301,7 +301,7 @@ vi.mock("../agents/embedded-agent-runner/run-state.js", () => ({ listActiveEmbeddedRunSessionKeys: () => hoisted.activeEmbeddedRunSessionKeys, })); -vi.mock("../agents/main-session-restart-recovery.js", () => ({ +vi.mock("../agents/main-session-recovery/main-session-restart-recovery.js", () => ({ markRestartAbortedMainSessions: hoisted.markRestartAbortedMainSessions, })); diff --git a/src/gateway/server-restart-sentinel.test.ts b/src/gateway/server-restart-sentinel.test.ts index 18348feef06f..1234d37ac074 100644 --- a/src/gateway/server-restart-sentinel.test.ts +++ b/src/gateway/server-restart-sentinel.test.ts @@ -169,10 +169,15 @@ const mocks = vi.hoisted(() => { vi.unmock("./server-restart-sentinel.js"); vi.resetModules(); -vi.mock("../agents/subagent-completion-delivery.js", async (importOriginal) => ({ - ...(await importOriginal()), - settleCorrelatedSubagentDelivery: mocks.settleCorrelatedSubagentDelivery, -})); +vi.mock( + "../agents/subagents/completion/subagent-completion-delivery.js", + async (importOriginal) => ({ + ...(await importOriginal< + typeof import("../agents/subagents/completion/subagent-completion-delivery.js") + >()), + settleCorrelatedSubagentDelivery: mocks.settleCorrelatedSubagentDelivery, + }), +); vi.mock("../agents/agent-scope.js", async () => { const actual = await vi.importActual( diff --git a/src/gateway/server-restart-sentinel.ts b/src/gateway/server-restart-sentinel.ts index 2cc9ed7c5307..db7e675a13e1 100644 --- a/src/gateway/server-restart-sentinel.ts +++ b/src/gateway/server-restart-sentinel.ts @@ -4,7 +4,7 @@ import { resolveSessionAgentId } from "../agents/agent-scope.js"; import { resolveCorrelatedSubagentDelivery, settleCorrelatedSubagentDelivery, -} from "../agents/subagent-completion-delivery.js"; +} from "../agents/subagents/completion/subagent-completion-delivery.js"; import { REPLY_RUN_STILL_SHUTTING_DOWN_TEXT } from "../auto-reply/reply/get-reply-run-queue.js"; import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js"; import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js"; diff --git a/src/gateway/server-startup-plugins.test.ts b/src/gateway/server-startup-plugins.test.ts index 3ddf7f965b3a..ca372219c568 100644 --- a/src/gateway/server-startup-plugins.test.ts +++ b/src/gateway/server-startup-plugins.test.ts @@ -119,7 +119,7 @@ vi.mock("../agents/agent-scope.js", () => ({ resolveDefaultAgentId: () => "default", })); -vi.mock("../agents/subagent-registry.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-registry.js", () => ({ initSubagentRegistry: () => initSubagentRegistry(), })); diff --git a/src/gateway/server-startup-plugins.ts b/src/gateway/server-startup-plugins.ts index fd312d83f58d..0f38c2223aae 100644 --- a/src/gateway/server-startup-plugins.ts +++ b/src/gateway/server-startup-plugins.ts @@ -1,6 +1,6 @@ // Gateway plugin startup bootstrap and adjacent startup maintenance. import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; -import { initSubagentRegistry } from "../agents/subagent-registry.js"; +import { initSubagentRegistry } from "../agents/subagents/registry/subagent-registry.js"; import type { AmbientEnvTriggerPolicy } from "../channels/config-presence.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { diff --git a/src/gateway/server-startup-post-attach.test.ts b/src/gateway/server-startup-post-attach.test.ts index 8d08c084566a..fcbd43186c2f 100644 --- a/src/gateway/server-startup-post-attach.test.ts +++ b/src/gateway/server-startup-post-attach.test.ts @@ -119,15 +119,15 @@ vi.mock("../agents/session-dirs.js", () => ({ resolveAgentSessionDirs: vi.fn(async () => []), })); -vi.mock("../agents/subagent-registry.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-registry.js", () => ({ scheduleSubagentRegistrySweep: hoisted.scheduleSubagentRegistrySweep, })); -vi.mock("../agents/main-session-restart-recovery-marking.js", () => ({ +vi.mock("../agents/main-session-recovery/main-session-restart-recovery-marking.js", () => ({ markStartupOrphanedMainSessionsForRecovery: hoisted.markStartupOrphanedMainSessionsForRecovery, })); -vi.mock("../agents/main-session-restart-recovery.js", () => ({ +vi.mock("../agents/main-session-recovery/main-session-restart-recovery.js", () => ({ scheduleRestartAbortedMainSessionRecovery: hoisted.scheduleRestartAbortedMainSessionRecovery, })); diff --git a/src/gateway/server-startup-post-attach.ts b/src/gateway/server-startup-post-attach.ts index b192ca88285c..e131b3f69dd0 100644 --- a/src/gateway/server-startup-post-attach.ts +++ b/src/gateway/server-startup-post-attach.ts @@ -54,11 +54,11 @@ const SKIP_STARTUP_MODEL_PREWARM_ENV = "OPENCLAW_SKIP_STARTUP_MODEL_PREWARM"; type Awaitable = T | Promise; const loadMainSessionRestartRecoveryModule = createLazyRuntimeModule( - () => import("../agents/main-session-restart-recovery.js"), + () => import("../agents/main-session-recovery/main-session-restart-recovery.js"), ); // Startup only needs orphan marking; keep resume and delivery runtime out of the pre-channel path. const loadMainSessionRestartRecoveryMarkingModule = createLazyRuntimeModule( - () => import("../agents/main-session-restart-recovery-marking.js"), + () => import("../agents/main-session-recovery/main-session-restart-recovery-marking.js"), ); const loadAgentDefaultsModule = createLazyRuntimeModule(() => import("../agents/defaults.js")); @@ -1310,7 +1310,8 @@ export async function startGatewayPostAttachRuntime( params.log.warn(`main-session restart recovery failed to schedule: ${String(err)}`); } try { - const { scheduleSubagentRegistrySweep } = await import("../agents/subagent-registry.js"); + const { scheduleSubagentRegistrySweep } = + await import("../agents/subagents/registry/subagent-registry.js"); scheduleSubagentRegistrySweep(); } catch (err) { params.log.warn(`subagent restart recovery failed to schedule: ${String(err)}`); diff --git a/src/gateway/server-startup-web-fetch-bind.test.ts b/src/gateway/server-startup-web-fetch-bind.test.ts index e2ccd19abbb9..1bf8c1d2bbf2 100644 --- a/src/gateway/server-startup-web-fetch-bind.test.ts +++ b/src/gateway/server-startup-web-fetch-bind.test.ts @@ -33,7 +33,7 @@ vi.mock("./server-chat-metadata-lifecycle.js", () => ({ })), })); -vi.mock("../agents/main-session-restart-recovery-marking.js", () => ({ +vi.mock("../agents/main-session-recovery/main-session-restart-recovery-marking.js", () => ({ markStartupOrphanedMainSessionsForRecovery: vi.fn(async () => ({ marked: 0, skipped: 0 })), })); diff --git a/src/gateway/server.chat.gateway-server-chat-b.test.ts b/src/gateway/server.chat.gateway-server-chat-b.test.ts index 0f35ca6d71ce..098d6cabe744 100644 --- a/src/gateway/server.chat.gateway-server-chat-b.test.ts +++ b/src/gateway/server.chat.gateway-server-chat-b.test.ts @@ -67,7 +67,7 @@ import { const restartRecoveryMocks = vi.hoisted(() => ({ retryRestartAbortedMainSessionRecovery: vi.fn< - typeof import("../agents/main-session-restart-recovery.js").retryRestartAbortedMainSessionRecovery + typeof import("../agents/main-session-recovery/main-session-restart-recovery.js").retryRestartAbortedMainSessionRecovery >(async () => ({ recovered: 0, failed: 1, @@ -75,15 +75,20 @@ const restartRecoveryMocks = vi.hoisted(() => ({ })), })); -vi.mock("../agents/main-session-restart-recovery.js", async (importOriginal) => { - const actual = - await importOriginal(); - return { - ...actual, - retryRestartAbortedMainSessionRecovery: - restartRecoveryMocks.retryRestartAbortedMainSessionRecovery, - }; -}); +vi.mock( + "../agents/main-session-recovery/main-session-restart-recovery.js", + async (importOriginal) => { + const actual = + await importOriginal< + typeof import("../agents/main-session-recovery/main-session-restart-recovery.js") + >(); + return { + ...actual, + retryRestartAbortedMainSessionRecovery: + restartRecoveryMocks.retryRestartAbortedMainSessionRecovery, + }; + }, +); installGatewayTestHooks({ scope: "suite" }); const FAST_WAIT_OPTS = { timeout: 2_000, interval: 1 } as const; diff --git a/src/gateway/session-create-fork-entry.ts b/src/gateway/session-create-fork-entry.ts index d29facd91278..96f83313b3e8 100644 --- a/src/gateway/session-create-fork-entry.ts +++ b/src/gateway/session-create-fork-entry.ts @@ -1,4 +1,4 @@ -import { buildMainSessionRecoveryClearPatch } from "../agents/main-session-recovery-clear.js"; +import { buildMainSessionRecoveryClearPatch } from "../agents/main-session-recovery/main-session-recovery-clear.js"; import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; export function buildForkedGatewaySessionEntry( diff --git a/src/gateway/session-kill-http.test.ts b/src/gateway/session-kill-http.test.ts index 1d38f505c330..4515456ecb23 100644 --- a/src/gateway/session-kill-http.test.ts +++ b/src/gateway/session-kill-http.test.ts @@ -41,7 +41,7 @@ vi.mock("./session-utils.js", () => ({ loadSessionEntry: loadSessionEntryMock, })); -vi.mock("../agents/subagent-control.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-control.js", () => ({ killSubagentRunAdmin: killSubagentRunAdminMock, })); diff --git a/src/gateway/session-kill-http.ts b/src/gateway/session-kill-http.ts index a36ce2e8ac9d..2402380c958a 100644 --- a/src/gateway/session-kill-http.ts +++ b/src/gateway/session-kill-http.ts @@ -1,7 +1,7 @@ // Gateway HTTP session kill handler. // Stops subagent runs through the admin-scoped HTTP control surface. import type { IncomingMessage, ServerResponse } from "node:http"; -import { killSubagentRunAdmin } from "../agents/subagent-control.js"; +import { killSubagentRunAdmin } from "../agents/subagents/registry/subagent-control.js"; import { getRuntimeConfig } from "../config/io.js"; import type { AuthRateLimiter } from "./auth-rate-limit.js"; import type { ResolvedGatewayAuth } from "./auth.js"; diff --git a/src/gateway/session-lifecycle-state.ts b/src/gateway/session-lifecycle-state.ts index 14cb773443d2..17227f105f88 100644 --- a/src/gateway/session-lifecycle-state.ts +++ b/src/gateway/session-lifecycle-state.ts @@ -13,7 +13,7 @@ import { sanitizeUserFacingText } from "../agents/embedded-agent-helpers/sanitiz import { isMainSessionRecoveryLifecycleEvent, projectMainSessionRecoveryLifecycle, -} from "../agents/main-session-recovery-lifecycle.js"; +} from "../agents/main-session-recovery/main-session-recovery-lifecycle.js"; import type { InternalSessionEntry as SessionEntry } from "../config/sessions.js"; import { updateSessionEntry } from "../config/sessions/session-accessor.js"; import { getAgentEventLifecycleGeneration, type AgentEventPayload } from "../infra/agent-events.js"; diff --git a/src/gateway/session-message-events.test.ts b/src/gateway/session-message-events.test.ts index 38da25b8f169..664fce6925b5 100644 --- a/src/gateway/session-message-events.test.ts +++ b/src/gateway/session-message-events.test.ts @@ -14,9 +14,9 @@ import { GATEWAY_CLIENT_MODES, } from "../../packages/gateway-protocol/src/client-info.js"; import { SESSION_VIEWER_PRESENCE_MAX_KEYS } from "../../packages/gateway-protocol/src/schema/sessions-viewer-presence.js"; -import { SUBAGENT_ENDED_REASON_ERROR } from "../agents/subagent-lifecycle-events.js"; -import { createSubagentRegistryLifecycleController } from "../agents/subagent-registry-lifecycle.js"; -import type { SubagentRunRecord } from "../agents/subagent-registry.types.js"; +import { SUBAGENT_ENDED_REASON_ERROR } from "../agents/subagents/registry/subagent-lifecycle-events.js"; +import { createSubagentRegistryLifecycleController } from "../agents/subagents/registry/subagent-registry-lifecycle.js"; +import type { SubagentRunRecord } from "../agents/subagents/registry/subagent-registry.types.js"; import { formatSqliteSessionFileMarker } from "../config/sessions/legacy-sqlite-marker.js"; import { loadTranscriptEvents, diff --git a/src/gateway/session-subagent-reactivation.test.ts b/src/gateway/session-subagent-reactivation.test.ts index 47911ba6c8fd..994fdf26ad29 100644 --- a/src/gateway/session-subagent-reactivation.test.ts +++ b/src/gateway/session-subagent-reactivation.test.ts @@ -6,10 +6,10 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const getLatestSubagentRunByChildSessionKeyMock = vi.fn(); const replaceSubagentRunAfterSteerMock = vi.fn(); -vi.mock("../agents/subagent-registry-read.js", async () => { - const actual = await vi.importActual( - "../agents/subagent-registry-read.js", - ); +vi.mock("../agents/subagents/registry/subagent-registry-read.js", async () => { + const actual = await vi.importActual< + typeof import("../agents/subagents/registry/subagent-registry-read.js") + >("../agents/subagents/registry/subagent-registry-read.js"); return { ...actual, getLatestSubagentRunByChildSessionKey: (...args: unknown[]) => @@ -17,7 +17,7 @@ vi.mock("../agents/subagent-registry-read.js", async () => { }; }); -vi.mock("../agents/subagent-registry-runtime.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-registry-runtime.js", () => ({ replaceSubagentRunAfterSteer: (...args: unknown[]) => replaceSubagentRunAfterSteerMock(...args), })); diff --git a/src/gateway/session-subagent-reactivation.ts b/src/gateway/session-subagent-reactivation.ts index fb4ed7e37ccf..51ea6dc5a63f 100644 --- a/src/gateway/session-subagent-reactivation.ts +++ b/src/gateway/session-subagent-reactivation.ts @@ -1,12 +1,12 @@ // Subagent session reactivation helper. // Replaces completed subagent run records when a user steers the child session. -import { getLatestSubagentRunByChildSessionKey } from "../agents/subagent-registry-read.js"; +import { getLatestSubagentRunByChildSessionKey } from "../agents/subagents/registry/subagent-registry-read.js"; // Completed subagent sessions can be reactivated after a user steer by replacing // the previous completed run id with the next run id through a lazy runtime // import. Active subagent runs are never replaced here. async function loadSessionSubagentReactivationRuntime() { - return import("../agents/subagent-registry-runtime.js"); + return import("../agents/subagents/registry/subagent-registry-runtime.js"); } /** diff --git a/src/gateway/session-utils-contracts.ts b/src/gateway/session-utils-contracts.ts index 0dd9b1e0ae46..ea3057ebb2ad 100644 --- a/src/gateway/session-utils-contracts.ts +++ b/src/gateway/session-utils-contracts.ts @@ -3,8 +3,8 @@ import { normalizeOptionalString, } from "@openclaw/normalization-core/string-coerce"; import type { resolveSessionModelRef } from "../agents/session-model-ref.js"; -import type { SubagentRunReadIndex } from "../agents/subagent-registry-queries.js"; -import type { SubagentRunReadRecord } from "../agents/subagent-registry.types.js"; +import type { SubagentRunReadIndex } from "../agents/subagents/registry/subagent-registry-queries.js"; +import type { SubagentRunReadRecord } from "../agents/subagents/registry/subagent-registry.types.js"; import type { ThinkLevel, listThinkingLevelOptions } from "../auto-reply/thinking.js"; import type { SessionAcpMeta, SessionEntry } from "../config/sessions.js"; import type { ModelCostConfig } from "../utils/usage-format.js"; diff --git a/src/gateway/session-utils-core.ts b/src/gateway/session-utils-core.ts index a494cf9edf48..99c67d7d78c6 100644 --- a/src/gateway/session-utils-core.ts +++ b/src/gateway/session-utils-core.ts @@ -3,11 +3,11 @@ import { countActiveDescendantRuns, getSessionDisplaySubagentRunByChildSessionKey, listSubagentRunsForController, -} from "../agents/subagent-registry-read.js"; +} from "../agents/subagents/registry/subagent-registry-read.js"; import { RECENT_ENDED_SUBAGENT_CHILD_SESSION_MS, shouldKeepSubagentRunChildLink, -} from "../agents/subagent-run-liveness.js"; +} from "../agents/subagents/registry/subagent-run-liveness.js"; import { stripInboundMetadata } from "../auto-reply/reply/strip-inbound-meta.js"; import { isTerminalSessionStatus, type SessionEntry } from "../config/sessions.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; diff --git a/src/gateway/session-utils-list.ts b/src/gateway/session-utils-list.ts index 5340e6f83707..98f128cacd39 100644 --- a/src/gateway/session-utils-list.ts +++ b/src/gateway/session-utils-list.ts @@ -10,8 +10,8 @@ import type { ModelCatalogEntry } from "../agents/model-catalog.js"; import { countActiveDescendantRuns, getSessionDisplaySubagentRunByChildSessionKey, -} from "../agents/subagent-registry-read.js"; -import { shouldKeepSubagentRunChildLink } from "../agents/subagent-run-liveness.js"; +} from "../agents/subagents/registry/subagent-registry-read.js"; +import { shouldKeepSubagentRunChildLink } from "../agents/subagents/registry/subagent-run-liveness.js"; import type { SessionEntry } from "../config/sessions.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { withPinnedActivePluginRegistryWorkspaceDir } from "../plugins/runtime-workspace-state.js"; diff --git a/src/gateway/session-utils-projection.ts b/src/gateway/session-utils-projection.ts index fa519e9004b8..6233fddc2f2c 100644 --- a/src/gateway/session-utils-projection.ts +++ b/src/gateway/session-utils-projection.ts @@ -3,7 +3,7 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { resolveContextTokensForModel } from "../agents/context.js"; import { normalizeStoredOverrideModel } from "../agents/model-selection.js"; import { resolveSessionModelRef } from "../agents/session-model-ref.js"; -import { buildSubagentSessionListReadIndex } from "../agents/subagent-registry-read.js"; +import { buildSubagentSessionListReadIndex } from "../agents/subagents/registry/subagent-registry-read.js"; import { resolveStorePath, type SessionEntry } from "../config/sessions.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { normalizeAgentId, parseAgentSessionKey } from "../routing/session-key.js"; diff --git a/src/gateway/session-utils-row.ts b/src/gateway/session-utils-row.ts index 67c445f6b611..8d3fd0d1f884 100644 --- a/src/gateway/session-utils-row.ts +++ b/src/gateway/session-utils-row.ts @@ -12,7 +12,7 @@ import { getSubagentSessionStartedAt, isSubagentRunLive, resolveSubagentSessionStatus, -} from "../agents/subagent-registry-read.js"; +} from "../agents/subagents/registry/subagent-registry-read.js"; import { resolveQueueSettingsCore } from "../auto-reply/reply/queue/settings.js"; import { resolveEffectiveResponseUsage } from "../auto-reply/thinking.js"; import { diff --git a/src/gateway/session-utils-search.ts b/src/gateway/session-utils-search.ts index d667e503e37a..4bc4ddfefda9 100644 --- a/src/gateway/session-utils-search.ts +++ b/src/gateway/session-utils-search.ts @@ -6,7 +6,7 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { DEFAULT_MODEL } from "../agents/defaults.js"; import type { ModelCatalogEntry } from "../agents/model-catalog.js"; import { resolveSessionModelIdentityRef } from "../agents/session-model-ref.js"; -import { getSessionDisplaySubagentRunByChildSessionKey } from "../agents/subagent-registry-read.js"; +import { getSessionDisplaySubagentRunByChildSessionKey } from "../agents/subagents/registry/subagent-registry-read.js"; import { buildGroupDisplayName, type InternalSessionEntry, diff --git a/src/gateway/session-utils.search.test.ts b/src/gateway/session-utils.search.test.ts index cce35ad2324a..d094895a84eb 100644 --- a/src/gateway/session-utils.search.test.ts +++ b/src/gateway/session-utils.search.test.ts @@ -9,7 +9,7 @@ import { ANTHROPIC_CONTEXT_1M_TOKENS } from "../agents/context-resolution.js"; import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../agents/subagent-registry.test-helpers.js"; +} from "../agents/subagents/registry/subagent-registry.test-helpers.js"; import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { diff --git a/src/gateway/session-utils.single-row-cache.test.ts b/src/gateway/session-utils.single-row-cache.test.ts index 74351167b2a4..8ffe393a4777 100644 --- a/src/gateway/session-utils.single-row-cache.test.ts +++ b/src/gateway/session-utils.single-row-cache.test.ts @@ -66,7 +66,7 @@ const subagentRegistryReadMock = vi.hoisted(() => { }; }); -vi.mock("../agents/subagent-registry-read.js", () => subagentRegistryReadMock); +vi.mock("../agents/subagents/registry/subagent-registry-read.js", () => subagentRegistryReadMock); import { listSessionsFromStore, diff --git a/src/gateway/session-utils.subagent.test.ts b/src/gateway/session-utils.subagent.test.ts index 4d638df68584..a0b582594da9 100644 --- a/src/gateway/session-utils.subagent.test.ts +++ b/src/gateway/session-utils.subagent.test.ts @@ -6,13 +6,13 @@ import os from "node:os"; import path from "node:path"; import { expectDefined } from "@openclaw/normalization-core"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import { canonicalSubagentRunFixtures } from "../agents/subagent-registry.persistence.test-support.js"; -import type { SubagentRunFixture } from "../agents/subagent-registry.persistence.test-support.js"; -import { saveSubagentRegistryToSqlite } from "../agents/subagent-registry.store.sqlite.js"; +import { canonicalSubagentRunFixtures } from "../agents/subagents/registry/subagent-registry.persistence.test-support.js"; +import type { SubagentRunFixture } from "../agents/subagents/registry/subagent-registry.persistence.test-support.js"; +import { saveSubagentRegistryToSqlite } from "../agents/subagents/registry/subagent-registry.store.sqlite.js"; import { addSubagentRunForTests, resetSubagentRegistryForTests, -} from "../agents/subagent-registry.test-helpers.js"; +} from "../agents/subagents/registry/subagent-registry.test-helpers.js"; import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { canPrewarmCombinedSessionStoresForGateway } from "../config/sessions/combined-store-gateway.js"; diff --git a/src/gateway/subagent-completion-tool-handoff.ts b/src/gateway/subagent-completion-tool-handoff.ts index ccbfab083357..768cd51360b3 100644 --- a/src/gateway/subagent-completion-tool-handoff.ts +++ b/src/gateway/subagent-completion-tool-handoff.ts @@ -7,7 +7,7 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe import type { SubagentCompletionToolHandoffRegistration, TrustedSubagentCompletionHandoff, -} from "../agents/subagent-announce-handoff.js"; +} from "../agents/subagents/announce/subagent-announce-handoff.js"; import { resolveGlobalMap } from "../shared/global-singleton.js"; const SUBAGENT_COMPLETION_TOOL_HANDOFF_TTL_MS = 5 * 60 * 1000; diff --git a/src/infra/heartbeat-runner-execution.ts b/src/infra/heartbeat-runner-execution.ts index 03d5c29f9738..dbd888635fef 100644 --- a/src/infra/heartbeat-runner-execution.ts +++ b/src/infra/heartbeat-runner-execution.ts @@ -4,7 +4,7 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; import { appendCronStyleCurrentTimeLine } from "../agents/current-time.js"; import { resolveEmbeddedSessionLane } from "../agents/embedded-agent-runner/lanes.js"; import { listActiveEmbeddedRunSessionKeys } from "../agents/embedded-agent-runner/run-state.js"; -import { transitionMainSessionRecovery } from "../agents/main-session-recovery-state.js"; +import { transitionMainSessionRecovery } from "../agents/main-session-recovery/main-session-recovery-state.js"; import { resolveHeartbeatReplyPayload, resolveHeartbeatTerminalToolFailure, diff --git a/src/infra/state-migrations.subagent-registry.test.ts b/src/infra/state-migrations.subagent-registry.test.ts index 16729ebe333f..842a45b42fab 100644 --- a/src/infra/state-migrations.subagent-registry.test.ts +++ b/src/infra/state-migrations.subagent-registry.test.ts @@ -5,7 +5,7 @@ import fsp from "node:fs/promises"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; -import type { SubagentRunRecord } from "../agents/subagent-registry.types.js"; +import type { SubagentRunRecord } from "../agents/subagents/registry/subagent-registry.types.js"; import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js"; import { closeOpenClawStateDatabaseForTest, diff --git a/src/plugin-sdk/agent-harness-task-runtime.test.ts b/src/plugin-sdk/agent-harness-task-runtime.test.ts index 11c237781f19..ed1b3c6deaec 100644 --- a/src/plugin-sdk/agent-harness-task-runtime.test.ts +++ b/src/plugin-sdk/agent-harness-task-runtime.test.ts @@ -2,7 +2,7 @@ * Tests agent harness task runtime scope, persistence, and completion delivery. */ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { deliverSubagentAnnouncement } from "../agents/subagent-announce-delivery.js"; +import { deliverSubagentAnnouncement } from "../agents/subagents/announce/subagent-announce-delivery.js"; import { createAgentHarnessTaskRuntimeScope } from "../tasks/agent-harness-task-runtime-scope.js"; import { createRunningTaskRun, finalizeTaskRunByRunId } from "../tasks/detached-task-runtime.js"; import { listTaskRecords } from "../tasks/runtime-internal.js"; @@ -12,8 +12,11 @@ import { isDurableAgentHarnessCompletionDelivery, } from "./agent-harness-task-runtime.js"; -vi.mock("../agents/subagent-announce-delivery.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../agents/subagents/announce/subagent-announce-delivery.js", async (importOriginal) => { + const actual = + await importOriginal< + typeof import("../agents/subagents/announce/subagent-announce-delivery.js") + >(); return { ...actual, deliverSubagentAnnouncement: vi.fn(async () => ({ delivered: true, path: "steered" })), diff --git a/src/plugin-sdk/agent-harness-task-runtime.ts b/src/plugin-sdk/agent-harness-task-runtime.ts index 69e0c8f3b85d..afac6cfb787c 100644 --- a/src/plugin-sdk/agent-harness-task-runtime.ts +++ b/src/plugin-sdk/agent-harness-task-runtime.ts @@ -15,11 +15,11 @@ import { deliverSubagentAnnouncement, isInternalAnnounceRequesterSession, loadRequesterSessionEntry, -} from "../agents/subagent-announce-delivery.js"; +} from "../agents/subagents/announce/subagent-announce-delivery.js"; import { resolveAnnounceOrigin, resolveSubagentCompletionOrigin, -} from "../agents/subagent-announce-origin.js"; +} from "../agents/subagents/announce/subagent-announce-origin.js"; import { assertAgentHarnessTaskRuntimeScope, type AgentHarnessTaskRuntimeScope, diff --git a/src/plugin-sdk/session-store-runtime-internal.ts b/src/plugin-sdk/session-store-runtime-internal.ts index 4a6ba54800c6..af035fd695c9 100644 --- a/src/plugin-sdk/session-store-runtime-internal.ts +++ b/src/plugin-sdk/session-store-runtime-internal.ts @@ -1,4 +1,4 @@ -import { MAIN_SESSION_RECOVERY_CLEAR_PATCH } from "../agents/main-session-recovery-clear.js"; +import { MAIN_SESSION_RECOVERY_CLEAR_PATCH } from "../agents/main-session-recovery/main-session-recovery-clear.js"; import type { SessionAccessScope } from "../config/sessions/session-accessor.js"; import type { InternalSessionEntry, SessionEntry } from "../config/sessions/types.js"; diff --git a/src/status/status-subagents.runtime.ts b/src/status/status-subagents.runtime.ts index 023ae888273a..15122ea1e512 100644 --- a/src/status/status-subagents.runtime.ts +++ b/src/status/status-subagents.runtime.ts @@ -1,4 +1,4 @@ // Lazy subagent-status facade. Keeps subagent registries out of the base status // import path until the command actually needs to render descendant runs. -export { buildControlledSubagentRunsReadContext } from "../agents/subagent-control.js"; +export { buildControlledSubagentRunsReadContext } from "../agents/subagents/registry/subagent-control.js"; export { buildSubagentsStatusLine } from "../auto-reply/reply/commands-status-subagents.js"; diff --git a/src/tasks/task-executor.test.ts b/src/tasks/task-executor.test.ts index fbdeb5afb21d..4001c4404e1a 100644 --- a/src/tasks/task-executor.test.ts +++ b/src/tasks/task-executor.test.ts @@ -99,7 +99,7 @@ vi.mock("../acp/control-plane/manager.js", () => ({ }), })); -vi.mock("../agents/subagent-control.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-control.js", () => ({ killSubagentRunAdmin: (params: unknown) => hoisted.killSubagentRunAdminMock(params), })); diff --git a/src/tasks/task-registry-control.runtime.ts b/src/tasks/task-registry-control.runtime.ts index f8147492d76d..bbe429468015 100644 --- a/src/tasks/task-registry-control.runtime.ts +++ b/src/tasks/task-registry-control.runtime.ts @@ -1,5 +1,5 @@ // Runtime control seam for cancelling runtime-owned work from task APIs. export { getAcpSessionManager } from "../acp/control-plane/manager.js"; export { cancelBackgroundExecSession } from "../agents/bash-process-control.js"; -export { killSubagentRunAdmin } from "../agents/subagent-control.js"; +export { killSubagentRunAdmin } from "../agents/subagents/registry/subagent-control.js"; export { cancelActiveCronTaskRun } from "../cron/service/active-run-cancellation.js"; diff --git a/src/tasks/task-registry.maintenance.ts b/src/tasks/task-registry.maintenance.ts index 8eb84e717c3b..9ced46864a42 100644 --- a/src/tasks/task-registry.maintenance.ts +++ b/src/tasks/task-registry.maintenance.ts @@ -11,7 +11,7 @@ import { isBackgroundExecSessionActive } from "../agents/bash-process-control.js import { formatSubagentRecoveryWedgedReason, isSubagentRecoveryWedgedEntry, -} from "../agents/subagent-recovery-state.js"; +} from "../agents/subagents/registry/subagent-recovery-state.js"; import { resolveStorePath } from "../config/sessions.js"; import type { SessionEntry } from "../config/sessions.js"; import { diff --git a/src/tasks/task-registry.test.ts b/src/tasks/task-registry.test.ts index 2a8b4c4b88db..bf1685ec039b 100644 --- a/src/tasks/task-registry.test.ts +++ b/src/tasks/task-registry.test.ts @@ -139,7 +139,7 @@ vi.mock("../acp/control-plane/manager.js", () => ({ }), })); -vi.mock("../agents/subagent-control.js", () => ({ +vi.mock("../agents/subagents/registry/subagent-control.js", () => ({ killSubagentRunAdmin: (params: unknown) => hoisted.killSubagentRunAdminMock(params), })); diff --git a/test/scripts/audit-seams.test.ts b/test/scripts/audit-seams.test.ts index c5ccbff98369..8dcd31e61afa 100644 --- a/test/scripts/audit-seams.test.ts +++ b/test/scripts/audit-seams.test.ts @@ -77,7 +77,7 @@ describe("audit-seams subagent seam classification", () => { it("detects subagent lifecycle registry and announce delivery seams", () => { const source = ` import { resolveContextEngine } from "../context-engine/registry.js"; - import { captureSubagentCompletionReply, runSubagentAnnounceFlow } from "./subagent-announce.js"; + import { captureSubagentCompletionReply, runSubagentAnnounceFlow } from "../announce/subagent-announce.js"; import { emitSubagentEndedHookOnce } from "./subagent-registry-completion.js"; import { persistSubagentRunsToDisk } from "./subagent-registry-state.js"; @@ -90,10 +90,9 @@ describe("audit-seams subagent seam classification", () => { } `; - expect(describeSeamKinds("src/agents/subagent-registry.ts", source)).toEqual([ - "subagent-announce-delivery", - "subagent-lifecycle-registry", - ]); + expect(describeSeamKinds("src/agents/subagents/registry/subagent-registry.ts", source)).toEqual( + ["subagent-announce-delivery", "subagent-lifecycle-registry"], + ); }); it("detects the shared delivery-context announce seam", () => { @@ -105,9 +104,9 @@ describe("audit-seams subagent seam classification", () => { } `; - expect(describeSeamKinds("src/agents/subagent-announce-origin.ts", source)).toEqual([ - "subagent-announce-delivery", - ]); + expect( + describeSeamKinds("src/agents/subagents/announce/subagent-announce-origin.ts", source), + ).toEqual(["subagent-announce-delivery"]); }); it("detects parent-stream seams for ACP spawn relays", () => { diff --git a/test/scripts/check-deadcode-exports.test.ts b/test/scripts/check-deadcode-exports.test.ts index 02621ce2f932..2901ebf81b52 100644 --- a/test/scripts/check-deadcode-exports.test.ts +++ b/test/scripts/check-deadcode-exports.test.ts @@ -221,7 +221,7 @@ describe("check-deadcode-exports", () => { it("models non-imported runtime and build entrypoints explicitly", () => { expect(knipConfig.workspaces["."].entry).toEqual( expect.arrayContaining([ - "src/agents/subagent-registry.runtime.ts!", + "src/agents/subagents/registry/subagent-registry.runtime.ts!", "src/mcp/plugin-tools-serve.ts!", "src/plugins/build-smoke-entry.ts!", "src/config/doc-baseline.ts!", diff --git a/test/scripts/check-session-accessor-boundary.test.ts b/test/scripts/check-session-accessor-boundary.test.ts index ab6da9eebe57..50becf3ffc41 100644 --- a/test/scripts/check-session-accessor-boundary.test.ts +++ b/test/scripts/check-session-accessor-boundary.test.ts @@ -66,8 +66,8 @@ describe("session accessor boundary guard", () => { "src/agents/embedded-agent-runner/transcript-rewrite.ts", "src/agents/embedded-agent-runner/transcript-runtime-state.ts", "src/agents/live-model-switch.ts", - "src/agents/subagent-control.ts", - "src/agents/subagent-registry-helpers.ts", + "src/agents/subagents/registry/subagent-control.ts", + "src/agents/subagents/registry/subagent-registry-helpers.ts", "src/auto-reply/reply/abort.ts", "src/auto-reply/reply/agent-runner-helpers.ts", "src/auto-reply/reply/agent-runner.ts", @@ -167,13 +167,13 @@ describe("session accessor boundary guard", () => { "src/agents/embedded-agent-runner/run/attempt.ts", "src/agents/embedded-agent-subscribe.handlers.compaction.runtime.ts", "src/agents/live-model-switch.ts", - "src/agents/main-session-restart-recovery-checkpoint.ts", - "src/agents/main-session-restart-recovery-marking.ts", - "src/agents/main-session-restart-recovery-store.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-checkpoint.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-marking.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-store.ts", "src/agents/session-suspension.ts", "src/auto-reply/reply/abort.ts", - "src/agents/subagent-control.ts", - "src/agents/subagent-registry-helpers.ts", + "src/agents/subagents/registry/subagent-control.ts", + "src/agents/subagents/registry/subagent-registry-helpers.ts", "src/agents/tools/session-status-tool.ts", "src/auto-reply/reply/abort-cutoff.runtime.ts", "src/auto-reply/reply/agent-runner-cli-dispatch.ts", diff --git a/test/scripts/check-session-transcript-reader-boundary.test.ts b/test/scripts/check-session-transcript-reader-boundary.test.ts index 691e4a520dd7..07322cb19ecd 100644 --- a/test/scripts/check-session-transcript-reader-boundary.test.ts +++ b/test/scripts/check-session-transcript-reader-boundary.test.ts @@ -8,12 +8,12 @@ describe("session transcript reader boundary guard", () => { it("ratchets only the files migrated by the transcript reader slice", () => { expect(migratedSessionTranscriptReaderFiles).toEqual( new Set([ - "src/agents/main-session-restart-recovery-store.ts", - "src/agents/subagent-announce-output.test.ts", - "src/agents/subagent-announce-output.ts", - "src/agents/subagent-announce.runtime.ts", - "src/agents/subagent-registry-restart-recovery.test.ts", - "src/agents/subagent-registry-restart-recovery.ts", + "src/agents/main-session-recovery/main-session-restart-recovery-store.ts", + "src/agents/subagents/announce/subagent-announce-output.test.ts", + "src/agents/subagents/announce/subagent-announce-output.ts", + "src/agents/subagents/announce/subagent-announce.runtime.ts", + "src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts", + "src/agents/subagents/registry/subagent-registry-restart-recovery.ts", "src/agents/tools/embedded-gateway-stub.runtime.ts", "src/agents/tools/embedded-gateway-stub.test.ts", "src/agents/tools/embedded-gateway-stub.ts", diff --git a/test/scripts/ci-node-test-plan.test.ts b/test/scripts/ci-node-test-plan.test.ts index 144f52bbc6d8..a78c41152cde 100644 --- a/test/scripts/ci-node-test-plan.test.ts +++ b/test/scripts/ci-node-test-plan.test.ts @@ -1110,14 +1110,19 @@ describe("scripts/lib/ci-node-test-plan.mts", () => { ); }); - it("covers every flat agents-core test exactly once across split shards", () => { + it("covers flat agents-core and explicitly nested isolated tests exactly once", () => { const actual = createNodeTestShards() .filter((shard) => shard.shardName.startsWith("agentic-agents-core-")) .flatMap((shard) => shard.includePatterns ?? []) .toSorted((a, b) => a.localeCompare(b)); - const expected = listTestFiles("src/agents") - .filter((file) => !relative("src/agents", file).replaceAll("\\", "/").includes("/")) - .toSorted((a, b) => a.localeCompare(b)); + const expected = [ + ...listTestFiles("src/agents").filter( + (file) => !relative("src/agents", file).replaceAll("\\", "/").includes("/"), + ), + ...agentVitestProjectOwners.coreIsolated.include.filter((file) => + relative("src/agents", file).replaceAll("\\", "/").includes("/"), + ), + ].toSorted((a, b) => a.localeCompare(b)); expect(actual).toEqual(expected); expect(new Set(actual).size).toBe(actual.length); diff --git a/test/vitest/vitest.agents-paths.mjs b/test/vitest/vitest.agents-paths.mjs index a155fc43627b..51294f9225b3 100644 --- a/test/vitest/vitest.agents-paths.mjs +++ b/test/vitest/vitest.agents-paths.mjs @@ -14,8 +14,8 @@ const coreIsolatedFiles = [ "src/agents/model-selection.plugin-runtime.test.ts", "src/agents/models-config.runtime-source-snapshot.test.ts", "src/agents/openai-transport-stream.streaming.test.ts", - "src/agents/subagent-registry.announce-loop-guard.test.ts", - "src/agents/subagent-registry-restart-recovery.test.ts", + "src/agents/subagents/registry/subagent-registry.announce-loop-guard.test.ts", + "src/agents/subagents/registry/subagent-registry-restart-recovery.test.ts", ]; const incompleteTurnFiles = [`${embeddedRoot}/run.incomplete-turn.test.ts`]; const overflowCompactionFiles = [`${embeddedRoot}/run.overflow-compaction.test.ts`]; @@ -91,7 +91,7 @@ export const agentVitestProjectOwners = { root: agentsRoot, dir: agentsRoot, include: [`${agentsRoot}/*/**/*.test.ts`], - exclude: [`${embeddedRoot}/**`, `${agentsRoot}/tools/**`], + exclude: [...coreIsolatedFiles, `${embeddedRoot}/**`, `${agentsRoot}/tools/**`], }, tools: { kind: "agentTools", diff --git a/tsdown.config.ts b/tsdown.config.ts index 4ee8cb9b3e46..db8d0f763529 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -310,7 +310,7 @@ function buildCoreDistEntries(): Record { "plugins/hook-runner-global": "src/plugins/hook-runner-global.ts", "plugins/memory-state": "src/plugins/memory-state.ts", "plugins/synthetic-auth.runtime": "src/plugins/synthetic-auth.runtime.ts", - "subagent-registry.runtime": "src/agents/subagent-registry.runtime.ts", + "subagent-registry.runtime": "src/agents/subagents/registry/subagent-registry.runtime.ts", "task-registry-control.runtime": "src/tasks/task-registry-control.runtime.ts", "link-understanding/apply.runtime": "src/link-understanding/apply.runtime.ts", "media-understanding/apply.runtime": "src/media-understanding/apply.runtime.ts",