@selesai/code 0.5.19 → 0.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { SUBAGENT_WATCHDOG_WARNING_TYPE } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
type MessageLike = {
|
|
4
|
+
role?: string;
|
|
5
|
+
content?: unknown;
|
|
6
|
+
customType?: string;
|
|
7
|
+
toolName?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
input?: unknown;
|
|
10
|
+
args?: unknown;
|
|
11
|
+
arguments?: unknown;
|
|
12
|
+
error?: unknown;
|
|
13
|
+
isError?: boolean;
|
|
14
|
+
details?: unknown;
|
|
15
|
+
stopReason?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface WatchdogTurnDeltaInput {
|
|
19
|
+
userPrompt?: string;
|
|
20
|
+
includeUserPrompt?: boolean;
|
|
21
|
+
messages?: unknown[];
|
|
22
|
+
events?: unknown[];
|
|
23
|
+
finalAssistantStop?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function textFromContent(content: unknown): string {
|
|
27
|
+
if (typeof content === "string") return content;
|
|
28
|
+
if (Array.isArray(content)) {
|
|
29
|
+
return content.map((block) => {
|
|
30
|
+
if (typeof block === "string") return block;
|
|
31
|
+
if (block && typeof block === "object") {
|
|
32
|
+
const item = block as { type?: string; text?: unknown; thinking?: unknown; content?: unknown; name?: unknown; input?: unknown; args?: unknown; arguments?: unknown };
|
|
33
|
+
if (item.type === "text" && typeof item.text === "string") return item.text;
|
|
34
|
+
if (item.type === "thinking" && typeof item.thinking === "string") return ["Thinking:", item.thinking].join("\n");
|
|
35
|
+
if (item.type === "toolCall") return formatToolCall(item.name, item.input ?? item.args ?? item.arguments);
|
|
36
|
+
if (typeof item.content === "string") return item.content;
|
|
37
|
+
}
|
|
38
|
+
return "";
|
|
39
|
+
}).filter(Boolean).join("\n");
|
|
40
|
+
}
|
|
41
|
+
if (content === undefined || content === null) return "";
|
|
42
|
+
return formatValue(content);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function formatValue(value: unknown, indent = ""): string {
|
|
46
|
+
if (typeof value === "string") return value;
|
|
47
|
+
if (value === undefined) return "undefined";
|
|
48
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
return value.map((item, index) => `${indent}- ${formatValue(item, `${indent} `)}`).join("\n");
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === "object") {
|
|
53
|
+
const lines: string[] = [];
|
|
54
|
+
for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
|
|
55
|
+
if (typeof item === "string" && item.includes("\n")) lines.push(`${indent}${key}:\n${item}`);
|
|
56
|
+
else lines.push(`${indent}${key}: ${formatValue(item, `${indent} `)}`);
|
|
57
|
+
}
|
|
58
|
+
return lines.join("\n");
|
|
59
|
+
}
|
|
60
|
+
return String(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function redactEditWriteInput(input: unknown): unknown {
|
|
64
|
+
if (Array.isArray(input)) return input.map(redactEditWriteInput);
|
|
65
|
+
if (!input || typeof input !== "object") return input;
|
|
66
|
+
const sanitized: Record<string, unknown> = {};
|
|
67
|
+
for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
|
|
68
|
+
sanitized[key] = ["oldText", "newText", "content"].includes(key) && typeof value === "string"
|
|
69
|
+
? `[omitted ${value.length} chars; use tool result diff]`
|
|
70
|
+
: redactEditWriteInput(value);
|
|
71
|
+
}
|
|
72
|
+
return sanitized;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function formatToolArguments(name: string, input: unknown): string {
|
|
76
|
+
if (name === "edit" || name === "write") return formatValue(redactEditWriteInput(input));
|
|
77
|
+
return formatValue(input);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatToolCall(name: unknown, input: unknown): string {
|
|
81
|
+
const toolName = typeof name === "string" && name ? name : "tool";
|
|
82
|
+
return [`Tool call: ${toolName}`, "Arguments:", formatToolArguments(toolName, input ?? {})].join("\n");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function formatToolResult(name: string, content: unknown, details: unknown, error: unknown, isError: boolean | undefined): string {
|
|
86
|
+
const failed = isError === true || Boolean(error);
|
|
87
|
+
const lines = [`Tool result: ${name}`];
|
|
88
|
+
if (failed) lines.push(`Error: ${error ? (typeof error === "string" ? error : formatValue(error)) : "tool reported an error"}`);
|
|
89
|
+
if (!failed && details && typeof details === "object" && "diff" in details && typeof (details as { diff?: unknown }).diff === "string") {
|
|
90
|
+
lines.push("Diff:", (details as { diff: string }).diff);
|
|
91
|
+
} else {
|
|
92
|
+
const body = textFromContent(content);
|
|
93
|
+
if (body) lines.push(failed ? "Output:" : "Result:", body);
|
|
94
|
+
}
|
|
95
|
+
return lines.join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function messagesFromEvent(event: unknown): unknown[] {
|
|
99
|
+
if (!event || typeof event !== "object") return [];
|
|
100
|
+
const input = event as Record<string, unknown>;
|
|
101
|
+
if (input.type === "turn_end" || input.event === "turn_end") {
|
|
102
|
+
return [input.message, ...(Array.isArray(input.toolResults) ? input.toolResults : [])].filter(Boolean);
|
|
103
|
+
}
|
|
104
|
+
if (input.message) return [input.message];
|
|
105
|
+
if (input.type === "tool_execution_start" || input.event === "tool_execution_start") {
|
|
106
|
+
return [{ role: "toolCall", name: input.toolName ?? input.name, input: input.args ?? input.input }];
|
|
107
|
+
}
|
|
108
|
+
if (input.type === "tool_execution_end" || input.event === "tool_execution_end") {
|
|
109
|
+
const result = input.result && typeof input.result === "object" && !Array.isArray(input.result) ? input.result as Record<string, unknown> : undefined;
|
|
110
|
+
return [{
|
|
111
|
+
role: "toolResult",
|
|
112
|
+
toolName: input.toolName ?? input.name,
|
|
113
|
+
content: result?.content ?? input.content ?? input.result,
|
|
114
|
+
details: result?.details ?? input.details,
|
|
115
|
+
error: input.error,
|
|
116
|
+
isError: input.isError,
|
|
117
|
+
}];
|
|
118
|
+
}
|
|
119
|
+
if (input.type === "tool_result" || input.event === "tool_result") {
|
|
120
|
+
return [{ role: "toolResult", toolName: input.toolName ?? input.name, content: input.content, details: input.details, error: input.error, isError: input.isError }];
|
|
121
|
+
}
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function formatWatchdogReviewMessage(message: unknown): string | undefined {
|
|
126
|
+
if (!message || typeof message !== "object") return undefined;
|
|
127
|
+
const input = message as MessageLike;
|
|
128
|
+
if (input.role === "custom" && input.customType === SUBAGENT_WATCHDOG_WARNING_TYPE) return undefined;
|
|
129
|
+
if (input.role === "assistant") {
|
|
130
|
+
const text = textFromContent(input.content);
|
|
131
|
+
const lines = text ? ["Assistant:", text] : ["Assistant: (no text)"];
|
|
132
|
+
if (input.stopReason === "stop") lines.push("Assistant stop: stop");
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
135
|
+
if (input.role === "toolCall") return formatToolCall(input.name ?? input.toolName, input.input ?? input.args ?? input.arguments);
|
|
136
|
+
if (input.role === "toolResult" || input.role === "tool") {
|
|
137
|
+
return formatToolResult(input.toolName ?? input.name ?? "tool", input.content, input.details, input.error, input.isError);
|
|
138
|
+
}
|
|
139
|
+
if (input.role === "user") {
|
|
140
|
+
const text = textFromContent(input.content);
|
|
141
|
+
return text ? ["User:", text].join("\n") : undefined;
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function formatWatchdogTurnDelta(input: WatchdogTurnDeltaInput): string {
|
|
147
|
+
const sections: string[] = [];
|
|
148
|
+
if (input.includeUserPrompt && input.userPrompt?.trim()) sections.push(["User prompt:", input.userPrompt].join("\n"));
|
|
149
|
+
for (const message of input.messages ?? []) {
|
|
150
|
+
const section = formatWatchdogReviewMessage(message);
|
|
151
|
+
if (section) sections.push(section);
|
|
152
|
+
}
|
|
153
|
+
for (const event of input.events ?? []) {
|
|
154
|
+
for (const message of messagesFromEvent(event)) {
|
|
155
|
+
const section = formatWatchdogReviewMessage(message);
|
|
156
|
+
if (section) sections.push(section);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (input.finalAssistantStop) sections.push("Final assistant stop: stop without tool call");
|
|
160
|
+
return sections.join("\n\n---\n\n");
|
|
161
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export const SUBAGENT_WATCHDOG_WARNING_TYPE = "subagent_watchdog_warning";
|
|
2
|
+
|
|
3
|
+
export const WATCHDOG_WARNING_SEVERITIES = ["concern", "blocker"] as const;
|
|
4
|
+
export type WatchdogSeverity = typeof WATCHDOG_WARNING_SEVERITIES[number];
|
|
5
|
+
|
|
6
|
+
export const WATCHDOG_WARNING_CATEGORIES = [
|
|
7
|
+
"correctness",
|
|
8
|
+
"missed-constraint",
|
|
9
|
+
"test-gap",
|
|
10
|
+
"unsafe-change",
|
|
11
|
+
"scope-drift",
|
|
12
|
+
"stale-fact",
|
|
13
|
+
"loop-risk",
|
|
14
|
+
"other",
|
|
15
|
+
] as const;
|
|
16
|
+
export type WatchdogCategory = typeof WATCHDOG_WARNING_CATEGORIES[number];
|
|
17
|
+
|
|
18
|
+
export const WATCHDOG_WARNING_CONFIDENCES = ["medium", "high"] as const;
|
|
19
|
+
export type WatchdogConfidence = typeof WATCHDOG_WARNING_CONFIDENCES[number];
|
|
20
|
+
|
|
21
|
+
export const WATCHDOG_WARNING_SOURCES = ["main", "child", "async-completion", "lsp"] as const;
|
|
22
|
+
export type WatchdogWarningSource = typeof WATCHDOG_WARNING_SOURCES[number];
|
|
23
|
+
|
|
24
|
+
export const WATCHDOG_LSP_DIAGNOSTIC_SEVERITIES = ["error", "warning", "info", "hint"] as const;
|
|
25
|
+
export type WatchdogLspDiagnosticSeverity = typeof WATCHDOG_LSP_DIAGNOSTIC_SEVERITIES[number];
|
|
26
|
+
|
|
27
|
+
export const WATCHDOG_LSP_STATUSES = ["disabled", "ok", "skipped", "unavailable", "timeout", "failed"] as const;
|
|
28
|
+
export type WatchdogLspStatus = typeof WATCHDOG_LSP_STATUSES[number];
|
|
29
|
+
|
|
30
|
+
export const WATCHDOG_RUNTIME_STATUSES = ["idle", "queued", "reviewing", "waiting-at-agent-end", "stale", "failed"] as const;
|
|
31
|
+
export type WatchdogRuntimeStatus = typeof WATCHDOG_RUNTIME_STATUSES[number];
|
|
32
|
+
|
|
33
|
+
export const WATCHDOG_WARNING_STATES = [
|
|
34
|
+
"candidate",
|
|
35
|
+
"confirmed",
|
|
36
|
+
"displayed",
|
|
37
|
+
"stale",
|
|
38
|
+
"failed",
|
|
39
|
+
"resolved",
|
|
40
|
+
"stalemate",
|
|
41
|
+
"suppressed",
|
|
42
|
+
] as const;
|
|
43
|
+
export type WatchdogWarningState = typeof WATCHDOG_WARNING_STATES[number];
|
|
44
|
+
|
|
45
|
+
export const WATCHDOG_LATE_WARNING_POLICIES = ["show-stale-no-autofollow"] as const;
|
|
46
|
+
export type WatchdogLateWarningPolicy = typeof WATCHDOG_LATE_WARNING_POLICIES[number];
|
|
47
|
+
|
|
48
|
+
export const WATCHDOG_DELIVERY_MODES = ["held"] as const;
|
|
49
|
+
export type WatchdogDeliveryMode = typeof WATCHDOG_DELIVERY_MODES[number];
|
|
50
|
+
|
|
51
|
+
export type WatchdogSyncBacklog = "off" | number;
|
|
52
|
+
|
|
53
|
+
export interface WatchdogWarning {
|
|
54
|
+
severity: WatchdogSeverity;
|
|
55
|
+
summary: string;
|
|
56
|
+
evidence: string;
|
|
57
|
+
recommendedAction: string;
|
|
58
|
+
category?: WatchdogCategory;
|
|
59
|
+
confidence?: WatchdogConfidence;
|
|
60
|
+
source?: WatchdogWarningSource;
|
|
61
|
+
agent?: string;
|
|
62
|
+
runId?: string;
|
|
63
|
+
stale?: boolean;
|
|
64
|
+
autoFollowAttempt?: number;
|
|
65
|
+
state?: WatchdogWarningState;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface WatchdogWarningDetails extends WatchdogWarning {
|
|
69
|
+
category: WatchdogCategory;
|
|
70
|
+
source: WatchdogWarningSource;
|
|
71
|
+
identity?: string;
|
|
72
|
+
displayedAt?: string;
|
|
73
|
+
error?: string;
|
|
74
|
+
stalemateRepeats?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface WatchdogWarningMessage {
|
|
78
|
+
customType: typeof SUBAGENT_WATCHDOG_WARNING_TYPE;
|
|
79
|
+
content: string;
|
|
80
|
+
display: boolean;
|
|
81
|
+
details: WatchdogWarningDetails;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface WatchdogAutoFollowConfig {
|
|
85
|
+
blockers: boolean;
|
|
86
|
+
maxAttempts: number | null;
|
|
87
|
+
stalemateRepeats: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface WatchdogGuidanceConfig {
|
|
91
|
+
watchdogMd: boolean;
|
|
92
|
+
systemPromptPath: string | null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface WatchdogEndpointConfig {
|
|
96
|
+
enabled: boolean;
|
|
97
|
+
model?: string;
|
|
98
|
+
thinking?: string | false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface WatchdogChildOverrideConfig {
|
|
102
|
+
enabled?: boolean;
|
|
103
|
+
model?: string;
|
|
104
|
+
thinking?: string | false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface WatchdogChildrenConfig extends WatchdogEndpointConfig {
|
|
108
|
+
watchdogTailTimeoutMs: number;
|
|
109
|
+
autoFollow: WatchdogAutoFollowConfig;
|
|
110
|
+
overrides: Record<string, WatchdogChildOverrideConfig>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface WatchdogAsyncCompletionConfig {
|
|
114
|
+
enabled: boolean;
|
|
115
|
+
autoFollowBlockers: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface WatchdogLspConfig {
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
timeoutMs: number;
|
|
121
|
+
maxFiles: number;
|
|
122
|
+
maxDiagnostics: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface WatchdogLspDiagnostic {
|
|
126
|
+
path: string;
|
|
127
|
+
line: number;
|
|
128
|
+
column: number;
|
|
129
|
+
severity: WatchdogLspDiagnosticSeverity;
|
|
130
|
+
source: string;
|
|
131
|
+
code?: string;
|
|
132
|
+
message: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface WatchdogLspResult {
|
|
136
|
+
status: WatchdogLspStatus;
|
|
137
|
+
provider?: string;
|
|
138
|
+
checkedPaths: string[];
|
|
139
|
+
skippedPaths: string[];
|
|
140
|
+
diagnostics: WatchdogLspDiagnostic[];
|
|
141
|
+
message?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface WatchdogLspRuntimeSnapshot extends WatchdogLspResult {
|
|
145
|
+
enabled: boolean;
|
|
146
|
+
diagnosticCount: number;
|
|
147
|
+
freshDiagnosticCount: number;
|
|
148
|
+
updatedAt?: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface ResolvedWatchdogConfig {
|
|
152
|
+
enabled: boolean;
|
|
153
|
+
delivery: WatchdogDeliveryMode;
|
|
154
|
+
showDuringRun: boolean;
|
|
155
|
+
syncBacklog: WatchdogSyncBacklog;
|
|
156
|
+
agentEndTimeoutMs: number;
|
|
157
|
+
lateWarningPolicy: WatchdogLateWarningPolicy;
|
|
158
|
+
severityThreshold: WatchdogSeverity;
|
|
159
|
+
maxWarnings: number | null;
|
|
160
|
+
guidance: WatchdogGuidanceConfig;
|
|
161
|
+
autoFollow: WatchdogAutoFollowConfig;
|
|
162
|
+
main: WatchdogEndpointConfig;
|
|
163
|
+
children: WatchdogChildrenConfig;
|
|
164
|
+
asyncCompletion: WatchdogAsyncCompletionConfig;
|
|
165
|
+
lsp: WatchdogLspConfig;
|
|
166
|
+
compactAtPercent: number;
|
|
167
|
+
reviewRetryDelayMs: number;
|
|
168
|
+
maxReviewFailures: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface WatchdogSettingsError {
|
|
172
|
+
scope: "user" | "project" | "session";
|
|
173
|
+
path?: string;
|
|
174
|
+
message: string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface WatchdogSettingsSource {
|
|
178
|
+
scope: "user" | "project" | "session";
|
|
179
|
+
path?: string;
|
|
180
|
+
exists: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface WatchdogSettingsResult {
|
|
184
|
+
ok: boolean;
|
|
185
|
+
config: ResolvedWatchdogConfig;
|
|
186
|
+
errors: WatchdogSettingsError[];
|
|
187
|
+
sources: WatchdogSettingsSource[];
|
|
188
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SUBAGENT_WATCHDOG_WARNING_TYPE,
|
|
3
|
+
type WatchdogWarning,
|
|
4
|
+
type WatchdogWarningDetails,
|
|
5
|
+
type WatchdogWarningMessage,
|
|
6
|
+
} from "./types.ts";
|
|
7
|
+
|
|
8
|
+
function escapeXmlText(value: string): string {
|
|
9
|
+
return value
|
|
10
|
+
.replace(/&/g, "&")
|
|
11
|
+
.replace(/</g, "<")
|
|
12
|
+
.replace(/>/g, ">");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function escapeXmlAttribute(value: string): string {
|
|
16
|
+
return escapeXmlText(value).replace(/"/g, """);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function tag(name: string, value: string | number | boolean | undefined): string | undefined {
|
|
20
|
+
if (value === undefined) return undefined;
|
|
21
|
+
return `<${name}>${escapeXmlText(String(value))}</${name}>`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function normalizeWatchdogWarningDetails(warning: WatchdogWarning, extras: Partial<WatchdogWarningDetails> = {}): WatchdogWarningDetails {
|
|
25
|
+
return {
|
|
26
|
+
...warning,
|
|
27
|
+
category: warning.category ?? extras.category ?? "other",
|
|
28
|
+
source: warning.source ?? extras.source ?? "main",
|
|
29
|
+
...extras,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function formatWatchdogWarningContent(warning: WatchdogWarning): string {
|
|
34
|
+
const details = normalizeWatchdogWarningDetails(warning);
|
|
35
|
+
const attrs = [
|
|
36
|
+
`severity="${escapeXmlAttribute(details.severity)}"`,
|
|
37
|
+
`category="${escapeXmlAttribute(details.category)}"`,
|
|
38
|
+
`source="${escapeXmlAttribute(details.source)}"`,
|
|
39
|
+
`guidance="weigh, don't blindly obey"`,
|
|
40
|
+
];
|
|
41
|
+
const optionalTags = [
|
|
42
|
+
tag("confidence", details.confidence),
|
|
43
|
+
tag("agent", details.agent),
|
|
44
|
+
tag("run_id", details.runId),
|
|
45
|
+
tag("state", details.state),
|
|
46
|
+
tag("stale", details.stale),
|
|
47
|
+
tag("auto_follow_attempt", details.autoFollowAttempt),
|
|
48
|
+
];
|
|
49
|
+
return [
|
|
50
|
+
`<subagent_watchdog ${attrs.join(" ")}>`,
|
|
51
|
+
`<summary>${escapeXmlText(details.summary)}</summary>`,
|
|
52
|
+
`<evidence>${escapeXmlText(details.evidence)}</evidence>`,
|
|
53
|
+
`<recommended_action>${escapeXmlText(details.recommendedAction)}</recommended_action>`,
|
|
54
|
+
...optionalTags.filter((line): line is string => Boolean(line)),
|
|
55
|
+
details.severity === "blocker"
|
|
56
|
+
? "<blocker_guidance>If this warning changes the outcome, produce a new self-contained final answer after addressing it.</blocker_guidance>"
|
|
57
|
+
: undefined,
|
|
58
|
+
"</subagent_watchdog>",
|
|
59
|
+
].filter((line): line is string => Boolean(line)).join("\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createWatchdogWarningMessage(
|
|
63
|
+
warning: WatchdogWarning,
|
|
64
|
+
options: { display?: boolean; details?: Partial<WatchdogWarningDetails> } = {},
|
|
65
|
+
): WatchdogWarningMessage {
|
|
66
|
+
const details = normalizeWatchdogWarningDetails(warning, options.details);
|
|
67
|
+
return {
|
|
68
|
+
customType: SUBAGENT_WATCHDOG_WARNING_TYPE,
|
|
69
|
+
content: formatWatchdogWarningContent(details),
|
|
70
|
+
display: options.display ?? true,
|
|
71
|
+
details,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -37,7 +37,7 @@ const ISOLATED_ENV_KEYS = [
|
|
|
37
37
|
"SELESAI_SUBAGENT_EXTRA_AGENT_DIRS",
|
|
38
38
|
"SELESAI_SUBAGENT_PARENT_SESSION",
|
|
39
39
|
"SELESAI_SUBAGENT_PI_BINARY",
|
|
40
|
-
"
|
|
40
|
+
"SELESAI_SUBAGENTS_SELESAI_CODING_AGENT_PACKAGE_ROOT",
|
|
41
41
|
] as const;
|
|
42
42
|
|
|
43
43
|
describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packages not available" : undefined }, () => {
|
|
@@ -48,6 +48,134 @@ describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packag
|
|
|
48
48
|
run = undefined;
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
it("loads requested extension tools in direct and chain children and diagnoses missing providers", async () => {
|
|
52
|
+
const { runRealSubagentSession, subagentCall, subagentToolResults } = await import("../support/real-session-runner.ts");
|
|
53
|
+
const extensionAgent = `---
|
|
54
|
+
name: extension-worker
|
|
55
|
+
description: Uses a child-only fixture tool
|
|
56
|
+
tools: read, fixture_search
|
|
57
|
+
subagentOnlyExtensions: ./fixture-extension.ts
|
|
58
|
+
completionGuard: false
|
|
59
|
+
---
|
|
60
|
+
Use the available tools.`;
|
|
61
|
+
const missingAgent = `---
|
|
62
|
+
name: missing-extension-worker
|
|
63
|
+
description: Requests an extension tool without loading its provider
|
|
64
|
+
tools: read, missing_search
|
|
65
|
+
completionGuard: false
|
|
66
|
+
---
|
|
67
|
+
Use the available tools.`;
|
|
68
|
+
const fixtureExtension = `export default function (pi) {
|
|
69
|
+
pi.registerTool({
|
|
70
|
+
name: "fixture_search",
|
|
71
|
+
label: "Fixture Search",
|
|
72
|
+
description: "Search the E2E fixture.",
|
|
73
|
+
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"], additionalProperties: false },
|
|
74
|
+
async execute() { return { content: [{ type: "text", text: "fixture result" }] }; },
|
|
75
|
+
});
|
|
76
|
+
}`;
|
|
77
|
+
|
|
78
|
+
run = await runRealSubagentSession({
|
|
79
|
+
prompt: "Run the direct, chain, and missing-provider child checks.",
|
|
80
|
+
childText: CHILD_MARKER,
|
|
81
|
+
reportChildTools: true,
|
|
82
|
+
projectFiles: {
|
|
83
|
+
".selesai/agents/extension-worker.md": extensionAgent,
|
|
84
|
+
".selesai/agents/missing-extension-worker.md": missingAgent,
|
|
85
|
+
"fixture-extension.ts": fixtureExtension,
|
|
86
|
+
},
|
|
87
|
+
respond(context) {
|
|
88
|
+
const resultCount = (context.messages as Array<{ role?: string; toolName?: string }>).filter((message) => message.role === "toolResult" && message.toolName === "subagent").length;
|
|
89
|
+
if (resultCount === 0) {
|
|
90
|
+
return subagentCall({ agent: "extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-direct-extension");
|
|
91
|
+
}
|
|
92
|
+
if (resultCount === 1) {
|
|
93
|
+
return subagentCall({ chain: [{ agent: "extension-worker", task: "Report active tools." }], async: false, clarify: false, agentScope: "project" }, "call-chain-extension");
|
|
94
|
+
}
|
|
95
|
+
if (resultCount === 2) {
|
|
96
|
+
return subagentCall({
|
|
97
|
+
chain: [{
|
|
98
|
+
agent: "extension-worker",
|
|
99
|
+
task: "Submit the required structured marker.",
|
|
100
|
+
outputSchema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: { marker: { type: "string" } },
|
|
103
|
+
required: ["marker"],
|
|
104
|
+
additionalProperties: false,
|
|
105
|
+
},
|
|
106
|
+
}],
|
|
107
|
+
async: false,
|
|
108
|
+
clarify: false,
|
|
109
|
+
agentScope: "project",
|
|
110
|
+
}, "call-structured-output");
|
|
111
|
+
}
|
|
112
|
+
if (resultCount === 3) {
|
|
113
|
+
return subagentCall({ agent: "missing-extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-missing-extension");
|
|
114
|
+
}
|
|
115
|
+
return "Child tool checks complete.";
|
|
116
|
+
},
|
|
117
|
+
timeoutMs: 60_000,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const results = subagentToolResults(run.parentSession);
|
|
121
|
+
const toolMessages = run.parentSession.messages.filter((message) => message.role === "toolResult" && (message as { toolName?: string }).toolName === "subagent");
|
|
122
|
+
const chainDetails = JSON.stringify((toolMessages[1] as { details?: unknown } | undefined)?.details);
|
|
123
|
+
const structuredDetails = JSON.stringify((toolMessages[2] as { details?: unknown } | undefined)?.details);
|
|
124
|
+
assert.equal(results.length, 4);
|
|
125
|
+
assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*fixture_search/);
|
|
126
|
+
assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*read/);
|
|
127
|
+
assert.match(chainDetails, /ACTIVE_TOOLS:[^\n]*fixture_search/);
|
|
128
|
+
assert.match(chainDetails, /ACTIVE_TOOLS:[^\n]*read/);
|
|
129
|
+
assert.match(structuredDetails, /STRUCTURED_OUTPUT_OK/);
|
|
130
|
+
assert.match(results[3] ?? "", /requested unavailable child tools: missing_search/);
|
|
131
|
+
assert.match(results[3] ?? "", /subagentOnlyExtensions/);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("accepts child tools registered by async before_agent_start hooks", async () => {
|
|
135
|
+
const { runRealSubagentSession, subagentCall, subagentToolResults } = await import("../support/real-session-runner.ts");
|
|
136
|
+
const asyncExtensionAgent = `---
|
|
137
|
+
name: async-extension-worker
|
|
138
|
+
description: Uses a child-only tool registered from before_agent_start
|
|
139
|
+
tools: read, fixture_async_search
|
|
140
|
+
subagentOnlyExtensions: ./fixture-async-extension.ts
|
|
141
|
+
completionGuard: false
|
|
142
|
+
---
|
|
143
|
+
Report active tools.`;
|
|
144
|
+
const fixtureAsyncExtension = `export default function (pi) {
|
|
145
|
+
pi.on("before_agent_start", async () => {
|
|
146
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
147
|
+
pi.registerTool({
|
|
148
|
+
name: "fixture_async_search",
|
|
149
|
+
label: "Fixture Async Search",
|
|
150
|
+
description: "Search the async E2E fixture.",
|
|
151
|
+
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"], additionalProperties: false },
|
|
152
|
+
async execute() { return { content: [{ type: "text", text: "async fixture result" }] }; },
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}`;
|
|
156
|
+
|
|
157
|
+
run = await runRealSubagentSession({
|
|
158
|
+
prompt: "Run the async child tool check.",
|
|
159
|
+
childText: CHILD_MARKER,
|
|
160
|
+
reportChildTools: true,
|
|
161
|
+
projectFiles: {
|
|
162
|
+
".selesai/agents/async-extension-worker.md": asyncExtensionAgent,
|
|
163
|
+
"fixture-async-extension.ts": fixtureAsyncExtension,
|
|
164
|
+
},
|
|
165
|
+
respond(context) {
|
|
166
|
+
const resultCount = (context.messages as Array<{ role?: string; toolName?: string }>).filter((message) => message.role === "toolResult" && message.toolName === "subagent").length;
|
|
167
|
+
if (resultCount > 0) return "Async child tool check complete.";
|
|
168
|
+
return subagentCall({ agent: "async-extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-async-extension");
|
|
169
|
+
},
|
|
170
|
+
timeoutMs: 60_000,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const results = subagentToolResults(run.parentSession);
|
|
174
|
+
assert.equal(results.length, 1);
|
|
175
|
+
assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*fixture_async_search/);
|
|
176
|
+
assert.doesNotMatch(results[0] ?? "", /requested unavailable child tools/);
|
|
177
|
+
});
|
|
178
|
+
|
|
51
179
|
it("boots the extension in a real parent session and delivers a faux child result", async () => {
|
|
52
180
|
const { routeParentThroughSubagent, runRealSubagentSession, subagentToolResults } = await import("../support/real-session-runner.ts");
|
|
53
181
|
|
|
@@ -59,7 +187,7 @@ describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packag
|
|
|
59
187
|
process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = BOGUS_EXTRA_DIRS;
|
|
60
188
|
process.env.SELESAI_SUBAGENT_PARENT_SESSION = "polluted-parent";
|
|
61
189
|
process.env.SELESAI_SUBAGENT_PI_BINARY = BOGUS_PI_BINARY;
|
|
62
|
-
process.env.
|
|
190
|
+
process.env.SELESAI_SUBAGENTS_SELESAI_CODING_AGENT_PACKAGE_ROOT = BOGUS_PI_PACKAGE_ROOT;
|
|
63
191
|
|
|
64
192
|
try {
|
|
65
193
|
run = await runRealSubagentSession({
|