@selesai/code 0.5.20 → 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-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 +1 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import * as os from "node:os";
|
|
3
4
|
import * as path from "node:path";
|
|
4
|
-
import {
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV } from "../../shared/utils.ts";
|
|
5
7
|
import type { JsonSchemaObject } from "../../shared/types.ts";
|
|
6
8
|
|
|
7
9
|
export const STRUCTURED_OUTPUT_SCHEMA_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA";
|
|
8
10
|
export const STRUCTURED_OUTPUT_CAPTURE_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE";
|
|
11
|
+
export const MISSING_STRUCTURED_OUTPUT_CALL_ERROR = "Missing structured_output call; this step has outputSchema and must finish by calling structured_output.";
|
|
9
12
|
|
|
10
13
|
export interface StructuredOutputRuntime {
|
|
11
14
|
schema: JsonSchemaObject;
|
|
@@ -13,11 +16,108 @@ export interface StructuredOutputRuntime {
|
|
|
13
16
|
outputPath: string;
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
const SCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"] as const;
|
|
20
|
+
const SCHEMA_SINGLE_KEYWORDS = ["additionalItems", "additionalProperties", "contains", "not", "propertyNames", "if", "then", "else", "unevaluatedItems", "unevaluatedProperties", "contentSchema"] as const;
|
|
21
|
+
const SCHEMA_ARRAY_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems"] as const;
|
|
22
|
+
|
|
23
|
+
function rewriteLocalJsonPointerRefs(schema: unknown, pointerPrefix: string, inheritsWrapperResource = true): unknown {
|
|
24
|
+
if (typeof schema === "boolean" || !schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
25
|
+
const source = schema as Record<string, unknown>;
|
|
26
|
+
const rewritten: Record<string, unknown> = { ...source };
|
|
27
|
+
const sharesWrapperResource = inheritsWrapperResource && typeof source.$id !== "string";
|
|
28
|
+
if (sharesWrapperResource) {
|
|
29
|
+
for (const keyword of ["$ref", "$dynamicRef", "$recursiveRef"] as const) {
|
|
30
|
+
const ref = source[keyword];
|
|
31
|
+
if (ref === "#") rewritten[keyword] = pointerPrefix;
|
|
32
|
+
else if (typeof ref === "string" && ref.startsWith("#/")) rewritten[keyword] = `${pointerPrefix}${ref.slice(1)}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const keyword of SCHEMA_MAP_KEYWORDS) {
|
|
36
|
+
const entries = source[keyword];
|
|
37
|
+
if (!entries || typeof entries !== "object" || Array.isArray(entries)) continue;
|
|
38
|
+
rewritten[keyword] = Object.fromEntries(Object.entries(entries).map(([name, nested]) => [
|
|
39
|
+
name,
|
|
40
|
+
rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),
|
|
41
|
+
]));
|
|
42
|
+
}
|
|
43
|
+
const items = source.items;
|
|
44
|
+
if (Array.isArray(items)) rewritten.items = items.map((nested) => rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource));
|
|
45
|
+
else if (items !== undefined) rewritten.items = rewriteLocalJsonPointerRefs(items, pointerPrefix, sharesWrapperResource);
|
|
46
|
+
for (const keyword of SCHEMA_SINGLE_KEYWORDS) {
|
|
47
|
+
if (source[keyword] !== undefined) rewritten[keyword] = rewriteLocalJsonPointerRefs(source[keyword], pointerPrefix, sharesWrapperResource);
|
|
48
|
+
}
|
|
49
|
+
for (const keyword of SCHEMA_ARRAY_KEYWORDS) {
|
|
50
|
+
if (Array.isArray(source[keyword])) rewritten[keyword] = source[keyword].map((nested) => rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource));
|
|
51
|
+
}
|
|
52
|
+
const dependencies = source.dependencies;
|
|
53
|
+
if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
|
|
54
|
+
rewritten.dependencies = Object.fromEntries(Object.entries(dependencies).map(([name, nested]) => [
|
|
55
|
+
name,
|
|
56
|
+
Array.isArray(nested) ? nested : rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),
|
|
57
|
+
]));
|
|
58
|
+
}
|
|
59
|
+
return rewritten;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createStructuredOutputToolParameters(schema: JsonSchemaObject): JsonSchemaObject {
|
|
63
|
+
return {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties: { value: rewriteLocalJsonPointerRefs(schema, "#/properties/value") },
|
|
66
|
+
required: ["value"],
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
16
71
|
interface CompiledJsonSchema {
|
|
17
72
|
Check(value: unknown): boolean;
|
|
18
73
|
Errors(value: unknown): Iterable<{ instancePath?: string; message?: string }>;
|
|
19
74
|
}
|
|
20
75
|
|
|
76
|
+
type CompileJsonSchema = (schema: unknown) => CompiledJsonSchema;
|
|
77
|
+
|
|
78
|
+
let cachedCompile: Promise<CompileJsonSchema> | undefined;
|
|
79
|
+
|
|
80
|
+
export async function resolveCompileFromPackageRoot(packageRoot: string): Promise<CompileJsonSchema | undefined> {
|
|
81
|
+
const requireFromRoot = createRequire(path.join(packageRoot, "package.json"));
|
|
82
|
+
const resolved = requireFromRoot.resolve("typebox/compile");
|
|
83
|
+
const mod = (await import(pathToFileURL(resolved).href)) as { Compile?: unknown };
|
|
84
|
+
return typeof mod.Compile === "function" ? (mod.Compile as CompileJsonSchema) : undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function importCompile(): Promise<CompileJsonSchema> {
|
|
88
|
+
const failures: string[] = [];
|
|
89
|
+
try {
|
|
90
|
+
const mod = (await import("typebox/compile")) as { Compile?: unknown };
|
|
91
|
+
if (typeof mod.Compile === "function") return mod.Compile as CompileJsonSchema;
|
|
92
|
+
failures.push("typebox/compile did not export a Compile function");
|
|
93
|
+
} catch (error) {
|
|
94
|
+
failures.push(`direct import failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
95
|
+
}
|
|
96
|
+
const packageRoot = process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV];
|
|
97
|
+
if (packageRoot) {
|
|
98
|
+
try {
|
|
99
|
+
const compile = await resolveCompileFromPackageRoot(packageRoot);
|
|
100
|
+
if (compile) return compile;
|
|
101
|
+
failures.push("Pi package root typebox/compile did not export a Compile function");
|
|
102
|
+
} catch (error) {
|
|
103
|
+
failures.push(`Pi package root import failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
failures.push(`${SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV} is not set`);
|
|
107
|
+
}
|
|
108
|
+
throw new Error(`Cannot load typebox/compile for structured output validation (${failures.join("; ")})`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function loadCompile(): Promise<CompileJsonSchema> {
|
|
112
|
+
if (!cachedCompile) {
|
|
113
|
+
cachedCompile = importCompile().catch((error) => {
|
|
114
|
+
cachedCompile = undefined;
|
|
115
|
+
throw error;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return cachedCompile;
|
|
119
|
+
}
|
|
120
|
+
|
|
21
121
|
export function assertJsonSchemaObject(schema: unknown, label = "outputSchema"): asserts schema is JsonSchemaObject {
|
|
22
122
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
23
123
|
throw new Error(`${label} must be a JSON Schema object.`);
|
|
@@ -35,10 +135,11 @@ export function createStructuredOutputRuntime(schema: JsonSchemaObject, baseDir?
|
|
|
35
135
|
return { schema, schemaPath, outputPath };
|
|
36
136
|
}
|
|
37
137
|
|
|
38
|
-
export function validateStructuredOutputValue(schema: JsonSchemaObject, value: unknown): { status: "valid" } | { status: "invalid"; message: string } {
|
|
138
|
+
export async function validateStructuredOutputValue(schema: JsonSchemaObject, value: unknown): Promise<{ status: "valid" } | { status: "invalid"; message: string }> {
|
|
139
|
+
const compile = await loadCompile();
|
|
39
140
|
let validator: CompiledJsonSchema;
|
|
40
141
|
try {
|
|
41
|
-
validator = (
|
|
142
|
+
validator = compile(schema);
|
|
42
143
|
} catch (error) {
|
|
43
144
|
return { status: "invalid", message: `invalid outputSchema: ${error instanceof Error ? error.message : String(error)}` };
|
|
44
145
|
}
|
|
@@ -52,9 +153,9 @@ export function validateStructuredOutputValue(schema: JsonSchemaObject, value: u
|
|
|
52
153
|
return { status: "invalid", message: errors.join("; ") || "schema validation failed" };
|
|
53
154
|
}
|
|
54
155
|
|
|
55
|
-
export function readStructuredOutput(runtime: StructuredOutputRuntime): { value?: unknown; error?: string } {
|
|
156
|
+
export async function readStructuredOutput(runtime: StructuredOutputRuntime): Promise<{ value?: unknown; error?: string }> {
|
|
56
157
|
if (!fs.existsSync(runtime.outputPath)) {
|
|
57
|
-
return { error:
|
|
158
|
+
return { error: MISSING_STRUCTURED_OUTPUT_CALL_ERROR };
|
|
58
159
|
}
|
|
59
160
|
let value: unknown;
|
|
60
161
|
try {
|
|
@@ -62,8 +163,12 @@ export function readStructuredOutput(runtime: StructuredOutputRuntime): { value?
|
|
|
62
163
|
} catch (error) {
|
|
63
164
|
return { error: `Failed to read structured output: ${error instanceof Error ? error.message : String(error)}` };
|
|
64
165
|
}
|
|
65
|
-
|
|
66
|
-
|
|
166
|
+
try {
|
|
167
|
+
const validation = await validateStructuredOutputValue(runtime.schema, value);
|
|
168
|
+
if (validation.status === "invalid") return { error: `Structured output validation failed: ${validation.message}` };
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return { error: `Failed to validate structured output: ${error instanceof Error ? error.message : String(error)}` };
|
|
171
|
+
}
|
|
67
172
|
return { value };
|
|
68
173
|
}
|
|
69
174
|
|
|
@@ -74,9 +74,10 @@ export function deriveActivityState(input: {
|
|
|
74
74
|
config: ResolvedControlConfig;
|
|
75
75
|
startedAt: number;
|
|
76
76
|
lastActivityAt?: number;
|
|
77
|
+
currentTool?: string;
|
|
77
78
|
now?: number;
|
|
78
79
|
}): ActivityState | undefined {
|
|
79
|
-
if (!input.config.enabled) return undefined;
|
|
80
|
+
if (!input.config.enabled || input.currentTool) return undefined;
|
|
80
81
|
const now = input.now ?? Date.now();
|
|
81
82
|
const lastActivity = input.lastActivityAt ?? input.startedAt;
|
|
82
83
|
const ageMs = Math.max(0, now - lastActivity);
|
|
@@ -174,7 +175,8 @@ export function formatControlNoticeMessage(event: ControlEvent, childIntercomTar
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
const nudgeMessage = "What are you blocked on? Reply with the smallest next step or ask for a decision.";
|
|
177
|
-
const
|
|
178
|
+
const steerCommand = `subagent({ action: "steer", id: "${runTarget}", ${event.index !== undefined ? `index: ${event.index}, ` : ""}message: "${nudgeMessage}" })`;
|
|
179
|
+
const nestedResumeCommand = `subagent({ action: "resume", id: "${runTarget}", message: "${nudgeMessage}" })`;
|
|
178
180
|
if (event.type === "active_long_running") {
|
|
179
181
|
const facts = formatLongRunningFacts(event);
|
|
180
182
|
return [
|
|
@@ -182,21 +184,27 @@ export function formatControlNoticeMessage(event: ControlEvent, childIntercomTar
|
|
|
182
184
|
`Run: ${runTarget}${event.index !== undefined ? ` step ${event.index + 1}` : ""}`,
|
|
183
185
|
`Signal: ${event.message}`,
|
|
184
186
|
facts ? `Facts: ${facts}` : undefined,
|
|
185
|
-
"Hint: Inspect status
|
|
186
|
-
`
|
|
187
|
+
"Hint: Inspect status first. Use steer for a top-level live async child, routed resume for a live nested child, or resume to revive a paused/completed/failed child.",
|
|
188
|
+
`Top-level live async nudge: ${steerCommand}`,
|
|
189
|
+
`Routed live nested nudge: ${nestedResumeCommand}`,
|
|
187
190
|
childIntercomTarget ? `Direct intercom target: ${childIntercomTarget}` : undefined,
|
|
188
191
|
`Status: subagent({ action: "status", id: "${runTarget}" })`,
|
|
189
192
|
`Interrupt: subagent({ action: "interrupt", id: "${runTarget}" })`,
|
|
190
193
|
].filter((line): line is string => Boolean(line)).join("\n");
|
|
191
194
|
}
|
|
192
195
|
|
|
196
|
+
const supervisorHint = event.reason === "supervisor_request"
|
|
197
|
+
? "Supervisor request: reply to the pending request. If subagent_supervisor pending is empty, check intercom pending because an external intercom tool may own the request."
|
|
198
|
+
: undefined;
|
|
193
199
|
return [
|
|
194
200
|
`Subagent needs attention: ${event.agent}`,
|
|
195
201
|
`Run: ${runTarget}${event.index !== undefined ? ` step ${event.index + 1}` : ""}`,
|
|
196
202
|
`Signal: ${event.message}`,
|
|
197
203
|
event.recentFailureSummary ? `Recent failures: ${event.recentFailureSummary}` : undefined,
|
|
198
|
-
|
|
199
|
-
|
|
204
|
+
supervisorHint,
|
|
205
|
+
"Hint: Inspect status first unless the run is clearly blocked. Use steer for a top-level live async child, routed resume for a live nested child, or resume to revive a paused/completed/failed child.",
|
|
206
|
+
`Top-level live async nudge: ${steerCommand}`,
|
|
207
|
+
`Routed live nested nudge: ${nestedResumeCommand}`,
|
|
200
208
|
childIntercomTarget ? `Direct intercom target: ${childIntercomTarget}` : undefined,
|
|
201
209
|
`Status: subagent({ action: "status", id: "${runTarget}" })`,
|
|
202
210
|
`Interrupt: subagent({ action: "interrupt", id: "${runTarget}" })`,
|
|
@@ -2,11 +2,25 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@selesai/code";
|
|
4
4
|
import { registerNativeSupervisorClient } from "../../intercom/native-supervisor-channel.ts";
|
|
5
|
-
import { consumeSteerRequestsFromDir, writeSteerRequestToDir, type SteerRequest } from "../background/control-channel.ts";
|
|
6
|
-
import { SUBAGENT_FANOUT_CHILD_ENV, SUBAGENT_STEER_INBOX_ENV } from "./pi-args.ts";
|
|
7
|
-
import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
|
|
8
|
-
import {
|
|
9
|
-
|
|
5
|
+
import { consumeSteerRequestsFromDir, steerAckPathFromDir, writeSteerAckAt, writeSteerCapabilityAt, writeSteerRequestToDir, type SteerRequest } from "../background/control-channel.ts";
|
|
6
|
+
import { SUBAGENT_CHILD_AGENT_ENV, SUBAGENT_CHILD_INDEX_ENV, SUBAGENT_FANOUT_CHILD_ENV, SUBAGENT_STEER_ACK_DIR_ENV, SUBAGENT_STEER_CAPABILITY_ENV, SUBAGENT_STEER_INBOX_ENV } from "./pi-args.ts";
|
|
7
|
+
import { createStructuredOutputToolParameters, STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
|
|
8
|
+
import {
|
|
9
|
+
CHILD_TOOL_DIAGNOSTIC_PATH_ENV,
|
|
10
|
+
MCP_DIRECT_CHILD_TOOLS_ENV,
|
|
11
|
+
REQUIRED_CHILD_TOOLS_ENV,
|
|
12
|
+
writeChildToolDiagnostic,
|
|
13
|
+
type ChildToolDiagnostic,
|
|
14
|
+
} from "./tool-availability.ts";
|
|
15
|
+
import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV, decodeToolBudgetEnv, shouldBlockToolForBudget, toolBudgetBlockedMessage, toolBudgetSoftNudge } from "./tool-budget.ts";
|
|
16
|
+
import type { JsonSchemaObject, ResolvedToolBudget, SubagentState } from "../../shared/types.ts";
|
|
17
|
+
import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
|
|
18
|
+
import { resolveWatchPath } from "../../shared/utils.ts";
|
|
19
|
+
import { registerChildWatchdog } from "../../watchdog/register-child.ts";
|
|
20
|
+
import { SUBAGENT_WATCHDOG_WARNING_TYPE } from "../../watchdog/types.ts";
|
|
21
|
+
import { resolveWaitToolConfig } from "../background/wait-config.ts";
|
|
22
|
+
import { registerWaitTool } from "../background/wait-tool.ts";
|
|
23
|
+
import { drainOutstandingWork } from "../background/auto-drain.ts";
|
|
10
24
|
|
|
11
25
|
const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
|
|
12
26
|
const SUBAGENT_INHERIT_SKILLS_ENV = "SELESAI_SUBAGENT_INHERIT_SKILLS";
|
|
@@ -55,6 +69,36 @@ function readBooleanEnv(name: string): boolean | undefined {
|
|
|
55
69
|
return value !== "0";
|
|
56
70
|
}
|
|
57
71
|
|
|
72
|
+
function readRequiredChildTools(): string[] | undefined {
|
|
73
|
+
const encoded = process.env[REQUIRED_CHILD_TOOLS_ENV]?.trim();
|
|
74
|
+
if (!encoded) return undefined;
|
|
75
|
+
const required = JSON.parse(encoded) as unknown;
|
|
76
|
+
if (!Array.isArray(required) || required.some((name) => typeof name !== "string" || !name)) {
|
|
77
|
+
throw new Error(`Invalid ${REQUIRED_CHILD_TOOLS_ENV} payload.`);
|
|
78
|
+
}
|
|
79
|
+
return required;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readMcpDirectChildTools(): string[] | undefined {
|
|
83
|
+
const encoded = process.env[MCP_DIRECT_CHILD_TOOLS_ENV]?.trim();
|
|
84
|
+
if (!encoded) return undefined;
|
|
85
|
+
try {
|
|
86
|
+
const tools = JSON.parse(encoded) as unknown;
|
|
87
|
+
if (!Array.isArray(tools) || tools.some((name) => typeof name !== "string" || !name)) return undefined;
|
|
88
|
+
return tools;
|
|
89
|
+
} catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function refreshChildToolDiagnostic(pi: ExtensionAPI): ChildToolDiagnostic | undefined {
|
|
95
|
+
const filePath = process.env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV]?.trim();
|
|
96
|
+
const required = readRequiredChildTools();
|
|
97
|
+
if (!filePath || !required) return undefined;
|
|
98
|
+
const available = pi.getAllTools().map((tool) => tool.name);
|
|
99
|
+
return writeChildToolDiagnostic(filePath, required, available, process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(), readMcpDirectChildTools());
|
|
100
|
+
}
|
|
101
|
+
|
|
58
102
|
function findSectionEnd(prompt: string, startIndex: number, nextHeaders: string[]): number {
|
|
59
103
|
let endIndex = prompt.length;
|
|
60
104
|
for (const header of nextHeaders) {
|
|
@@ -114,9 +158,9 @@ export function rewriteSubagentPrompt(
|
|
|
114
158
|
|
|
115
159
|
function isParentOnlySubagentMessage(message: unknown): boolean {
|
|
116
160
|
const m = message as { role?: string; customType?: string };
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
161
|
+
if (m?.role !== "custom" || typeof m.customType !== "string") return false;
|
|
162
|
+
if (m.customType === SUBAGENT_WATCHDOG_WARNING_TYPE) return true;
|
|
163
|
+
return PARENT_ONLY_CUSTOM_MESSAGE_TYPES.has(m.customType);
|
|
120
164
|
}
|
|
121
165
|
|
|
122
166
|
function isSubagentToolResultMessage(message: unknown): boolean {
|
|
@@ -190,29 +234,59 @@ function registerToolBudget(pi: ExtensionAPI, budget: ResolvedToolBudget | undef
|
|
|
190
234
|
});
|
|
191
235
|
}
|
|
192
236
|
|
|
193
|
-
function registerSteeringInbox(
|
|
237
|
+
export function registerSteeringInbox(
|
|
238
|
+
pi: ExtensionAPI,
|
|
239
|
+
deps: { watch?: typeof fs.watch; nativeRealpath?: (filePath: string) => string } = {},
|
|
240
|
+
): void {
|
|
194
241
|
const steerInbox = process.env[SUBAGENT_STEER_INBOX_ENV]?.trim();
|
|
195
242
|
if (!steerInbox) return;
|
|
243
|
+
const capabilityPath = process.env[SUBAGENT_STEER_CAPABILITY_ENV]?.trim();
|
|
244
|
+
const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();
|
|
196
245
|
const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: "steer" }) => unknown }).sendUserMessage;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
let canSteer = false;
|
|
246
|
+
const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);
|
|
247
|
+
const pending = new Map<string, string[]>();
|
|
200
248
|
let disposed = false;
|
|
201
249
|
let flushing = false;
|
|
202
250
|
let started = false;
|
|
251
|
+
let canSteer = typeof sendUserMessage === "function";
|
|
203
252
|
let watcher: fs.FSWatcher | undefined;
|
|
204
253
|
let interval: NodeJS.Timeout | undefined;
|
|
254
|
+
const acknowledge = (request: SteerRequest, state: "delivered" | "failed", message: string): void => {
|
|
255
|
+
if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;
|
|
256
|
+
writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {
|
|
257
|
+
requestId: request.id,
|
|
258
|
+
index: childIndex,
|
|
259
|
+
ts: Date.now(),
|
|
260
|
+
state,
|
|
261
|
+
message,
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
const publishCapability = (): void => {
|
|
265
|
+
if (!capabilityPath || !Number.isInteger(childIndex) || childIndex < 0) return;
|
|
266
|
+
writeSteerCapabilityAt(capabilityPath, { index: childIndex, pid: process.pid, readyAt: Date.now(), supported: canSteer });
|
|
267
|
+
};
|
|
205
268
|
const flush = (): void => {
|
|
206
|
-
if (disposed || flushing
|
|
269
|
+
if (disposed || flushing) return;
|
|
207
270
|
flushing = true;
|
|
208
271
|
try {
|
|
209
272
|
const requests = consumeSteerRequestsFromDir(steerInbox);
|
|
210
273
|
for (let index = 0; index < requests.length; index++) {
|
|
211
274
|
const request = requests[index]!;
|
|
275
|
+
if (!canSteer || typeof sendUserMessage !== "function") {
|
|
276
|
+
acknowledge(request, "failed", "Child Pi session does not support sendUserMessage steering.");
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const formatted = formatSteerMessage(request);
|
|
280
|
+
const ids = pending.get(formatted) ?? [];
|
|
281
|
+
ids.push(request.id);
|
|
282
|
+
pending.set(formatted, ids);
|
|
212
283
|
try {
|
|
213
|
-
sendUserMessage(
|
|
214
|
-
} catch {
|
|
215
|
-
|
|
284
|
+
sendUserMessage(formatted, { deliverAs: "steer" });
|
|
285
|
+
} catch (error) {
|
|
286
|
+
ids.pop();
|
|
287
|
+
if (ids.length === 0) pending.delete(formatted);
|
|
288
|
+
acknowledge(request, "failed", error instanceof Error ? error.message : String(error));
|
|
289
|
+
for (const retry of requests.slice(index + 1)) writeSteerRequestToDir(steerInbox, retry);
|
|
216
290
|
break;
|
|
217
291
|
}
|
|
218
292
|
}
|
|
@@ -220,16 +294,30 @@ function registerSteeringInbox(pi: ExtensionAPI): void {
|
|
|
220
294
|
flushing = false;
|
|
221
295
|
}
|
|
222
296
|
};
|
|
297
|
+
const onInput = (event: unknown): undefined => {
|
|
298
|
+
if (disposed || !event || typeof event !== "object") return undefined;
|
|
299
|
+
const input = event as { source?: unknown; streamingBehavior?: unknown; text?: unknown; content?: unknown };
|
|
300
|
+
if (input.source !== "extension" || input.streamingBehavior !== "steer") return undefined;
|
|
301
|
+
const text = typeof input.text === "string" ? input.text : typeof input.content === "string" ? input.content : undefined;
|
|
302
|
+
if (!text) return undefined;
|
|
303
|
+
const ids = pending.get(text);
|
|
304
|
+
const requestId = ids?.shift();
|
|
305
|
+
if (!requestId) return undefined;
|
|
306
|
+
if (ids?.length === 0) pending.delete(text);
|
|
307
|
+
acknowledge({ type: "steer", id: requestId, ts: Date.now(), message: text }, "delivered", "Pi accepted the correlated steering input.");
|
|
308
|
+
return undefined;
|
|
309
|
+
};
|
|
223
310
|
const start = (): void => {
|
|
224
311
|
if (started || disposed) return;
|
|
225
312
|
try {
|
|
226
313
|
fs.mkdirSync(steerInbox, { recursive: true });
|
|
314
|
+
publishCapability();
|
|
227
315
|
} catch {
|
|
228
316
|
return;
|
|
229
317
|
}
|
|
230
318
|
started = true;
|
|
231
319
|
try {
|
|
232
|
-
watcher = fs.watch(steerInbox, () => flush());
|
|
320
|
+
watcher = (deps.watch ?? fs.watch)(resolveWatchPath(steerInbox, deps.nativeRealpath), () => flush());
|
|
233
321
|
watcher.on("error", () => {});
|
|
234
322
|
} catch {
|
|
235
323
|
watcher = undefined;
|
|
@@ -239,28 +327,44 @@ function registerSteeringInbox(pi: ExtensionAPI): void {
|
|
|
239
327
|
};
|
|
240
328
|
const activate = (): undefined => {
|
|
241
329
|
start();
|
|
242
|
-
canSteer = true;
|
|
243
330
|
flush();
|
|
244
331
|
return undefined;
|
|
245
332
|
};
|
|
246
333
|
|
|
247
334
|
const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
|
|
335
|
+
// Register input before the watcher so an accepted extension input cannot race request dispatch.
|
|
336
|
+
onRuntimeEvent("input", onInput);
|
|
248
337
|
onRuntimeEvent("session_start", () => start());
|
|
249
338
|
for (const eventName of ["message_start", "message_update", "message_end", "tool_execution_start", "tool_execution_end", "turn_end"] as const) {
|
|
250
339
|
onRuntimeEvent(eventName, activate);
|
|
251
340
|
}
|
|
252
341
|
onRuntimeEvent("session_shutdown", () => {
|
|
253
342
|
disposed = true;
|
|
254
|
-
try {
|
|
255
|
-
watcher?.close();
|
|
256
|
-
} catch {}
|
|
343
|
+
try { watcher?.close(); } catch {}
|
|
257
344
|
if (interval) clearInterval(interval);
|
|
258
345
|
});
|
|
259
346
|
}
|
|
260
347
|
|
|
261
348
|
export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
262
349
|
registerSteeringInbox(pi);
|
|
263
|
-
registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV]));
|
|
350
|
+
registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === "1" }));
|
|
351
|
+
registerChildWatchdog(pi);
|
|
352
|
+
const waitToolEnabled = resolveWaitToolConfig().enabled;
|
|
353
|
+
const waitState = {
|
|
354
|
+
baseCwd: "",
|
|
355
|
+
currentSessionId: null,
|
|
356
|
+
asyncJobs: new Map(),
|
|
357
|
+
foregroundControls: new Map(),
|
|
358
|
+
lastForegroundControlId: null,
|
|
359
|
+
cleanupTimers: new Map(),
|
|
360
|
+
lastUiContext: null,
|
|
361
|
+
poller: null,
|
|
362
|
+
completionSeen: new Map(),
|
|
363
|
+
watcher: null,
|
|
364
|
+
watcherRestartTimer: null,
|
|
365
|
+
resultFileCoalescer: { schedule: () => false, clear: () => {} },
|
|
366
|
+
} as unknown as SubagentState;
|
|
367
|
+
if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState, waitToolEnabled);
|
|
264
368
|
let nativeSupervisorClientRegistered = false;
|
|
265
369
|
let nativeSupervisorFallbackRegistered = false;
|
|
266
370
|
const registerNativeSupervisorClientOnce = (): void => {
|
|
@@ -275,17 +379,24 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
275
379
|
registerNativeSupervisorClient(pi);
|
|
276
380
|
};
|
|
277
381
|
const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
|
|
278
|
-
onRuntimeEvent("session_start",
|
|
382
|
+
onRuntimeEvent("session_start", (_event: unknown, ctx: unknown) => {
|
|
383
|
+
const sessionManager = (ctx as { sessionManager?: Parameters<typeof resolveCurrentSessionId>[0] } | undefined)?.sessionManager;
|
|
384
|
+
waitState.currentSessionId = sessionManager ? resolveCurrentSessionId(sessionManager) : null;
|
|
385
|
+
registerNativeSupervisorClientOnce();
|
|
386
|
+
if (readRequiredChildTools()?.includes("intercom")) registerNativeSupervisorFallbackOnce();
|
|
387
|
+
});
|
|
388
|
+
onRuntimeEvent("agent_start", () => {
|
|
389
|
+
refreshChildToolDiagnostic(pi);
|
|
390
|
+
});
|
|
391
|
+
onRuntimeEvent("agent_end", async (_event: unknown, ctx: unknown) => {
|
|
392
|
+
if ((ctx as { hasUI?: boolean } | undefined)?.hasUI === true) return;
|
|
393
|
+
await drainOutstandingWork({ state: waitState, events: pi.events });
|
|
394
|
+
});
|
|
279
395
|
const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];
|
|
280
396
|
const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];
|
|
281
397
|
if (structuredOutputPath && structuredSchemaPath) {
|
|
282
398
|
const schema = JSON.parse(fs.readFileSync(structuredSchemaPath, "utf-8")) as JsonSchemaObject;
|
|
283
|
-
const parameters =
|
|
284
|
-
type: "object",
|
|
285
|
-
properties: { value: schema },
|
|
286
|
-
required: ["value"],
|
|
287
|
-
additionalProperties: false,
|
|
288
|
-
};
|
|
399
|
+
const parameters = createStructuredOutputToolParameters(schema);
|
|
289
400
|
const registerTool = pi.registerTool as unknown as (tool: {
|
|
290
401
|
name: string;
|
|
291
402
|
label: string;
|
|
@@ -299,7 +410,7 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
299
410
|
description: "Submit the required final structured output for this subagent step. This terminates the step.",
|
|
300
411
|
parameters: parameters as never,
|
|
301
412
|
async execute(_id: string, params: { value: unknown }) {
|
|
302
|
-
const validation = validateStructuredOutputValue(schema, params.value);
|
|
413
|
+
const validation = await validateStructuredOutputValue(schema, params.value);
|
|
303
414
|
if (validation.status === "invalid") {
|
|
304
415
|
throw new Error(`Structured output validation failed: ${validation.message}`);
|
|
305
416
|
}
|
|
@@ -330,12 +441,14 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
330
441
|
const inheritProjectContext = readBooleanEnv(SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV);
|
|
331
442
|
const inheritSkills = readBooleanEnv(SUBAGENT_INHERIT_SKILLS_ENV);
|
|
332
443
|
const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
444
|
+
let rewritten = event.systemPrompt;
|
|
445
|
+
if (inheritProjectContext !== undefined || inheritSkills !== undefined || fanoutChild !== undefined) {
|
|
446
|
+
rewritten = rewriteSubagentPrompt(event.systemPrompt, {
|
|
447
|
+
inheritProjectContext: inheritProjectContext ?? true,
|
|
448
|
+
inheritSkills: inheritSkills ?? true,
|
|
449
|
+
fanoutChild: fanoutChild === true,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
339
452
|
if (rewritten === event.systemPrompt) return;
|
|
340
453
|
return { systemPrompt: rewritten };
|
|
341
454
|
});
|