@caupulican/pi-adaptative 0.80.103 → 0.81.0
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/CHANGELOG.md +120 -0
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +6 -6
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +152 -512
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +635 -4590
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
- package/dist/core/autonomy/session-lane-record.js.map +1 -1
- package/dist/core/autonomy/status.d.ts +1 -0
- package/dist/core/autonomy/status.d.ts.map +1 -1
- package/dist/core/autonomy/status.js +1 -0
- package/dist/core/autonomy/status.js.map +1 -1
- package/dist/core/autonomy-telemetry.d.ts +80 -0
- package/dist/core/autonomy-telemetry.d.ts.map +1 -0
- package/dist/core/autonomy-telemetry.js +266 -0
- package/dist/core/autonomy-telemetry.js.map +1 -0
- package/dist/core/background-lane-controller.d.ts +186 -0
- package/dist/core/background-lane-controller.d.ts.map +1 -0
- package/dist/core/background-lane-controller.js +691 -0
- package/dist/core/background-lane-controller.js.map +1 -0
- package/dist/core/bash-execution-controller.d.ts +51 -0
- package/dist/core/bash-execution-controller.d.ts.map +1 -0
- package/dist/core/bash-execution-controller.js +96 -0
- package/dist/core/bash-execution-controller.js.map +1 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +9 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction-support.d.ts +56 -0
- package/dist/core/compaction-support.d.ts.map +1 -0
- package/dist/core/compaction-support.js +99 -0
- package/dist/core/compaction-support.js.map +1 -0
- package/dist/core/context/artifact-retrieval.d.ts +1 -1
- package/dist/core/context/artifact-retrieval.d.ts.map +1 -1
- package/dist/core/context/artifact-retrieval.js +1 -1
- package/dist/core/context/artifact-retrieval.js.map +1 -1
- package/dist/core/context/context-composition.d.ts.map +1 -1
- package/dist/core/context/context-composition.js +1 -1
- package/dist/core/context/context-composition.js.map +1 -1
- package/dist/core/context/tool-output-packer.d.ts +1 -1
- package/dist/core/context/tool-output-packer.d.ts.map +1 -1
- package/dist/core/context/tool-output-packer.js +1 -1
- package/dist/core/context/tool-output-packer.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +1 -1
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +223 -0
- package/dist/core/context-pipeline.d.ts.map +1 -0
- package/dist/core/context-pipeline.js +594 -0
- package/dist/core/context-pipeline.js.map +1 -0
- package/dist/core/cost/daily-usage.d.ts +1 -1
- package/dist/core/cost/daily-usage.d.ts.map +1 -1
- package/dist/core/cost/daily-usage.js +1 -1
- package/dist/core/cost/daily-usage.js.map +1 -1
- package/dist/core/cost/session-usage.d.ts +1 -1
- package/dist/core/cost/session-usage.d.ts.map +1 -1
- package/dist/core/cost/session-usage.js +1 -1
- package/dist/core/cost/session-usage.js.map +1 -1
- package/dist/core/delegation/session-worker-result.d.ts +1 -1
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/exec.d.ts +2 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +15 -9
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/index.d.ts +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +2 -2
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/builtin.d.ts.map +1 -1
- package/dist/core/extensions/builtin.js +2 -2
- package/dist/core/extensions/builtin.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +2 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +24 -0
- package/dist/core/goal-loop-controller.d.ts.map +1 -0
- package/dist/core/goal-loop-controller.js +83 -0
- package/dist/core/goal-loop-controller.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +1 -1
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +1 -1
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +1 -1
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/session-learning-decision.d.ts +1 -1
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
- package/dist/core/learning/session-learning-decision.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +99 -0
- package/dist/core/local-runtime-controller.d.ts.map +1 -0
- package/dist/core/local-runtime-controller.js +214 -0
- package/dist/core/local-runtime-controller.js.map +1 -0
- package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
- package/dist/core/memory/providers/transcript-recall.js +1 -1
- package/dist/core/memory/providers/transcript-recall.js.map +1 -1
- package/dist/core/memory-controller.d.ts +139 -0
- package/dist/core/memory-controller.d.ts.map +1 -0
- package/dist/core/memory-controller.js +323 -0
- package/dist/core/memory-controller.js.map +1 -0
- package/dist/core/model-router/status.d.ts +1 -1
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +140 -0
- package/dist/core/model-router-controller.d.ts.map +1 -0
- package/dist/core/model-router-controller.js +623 -0
- package/dist/core/model-router-controller.js.map +1 -0
- package/dist/core/model-selection-controller.d.ts +95 -0
- package/dist/core/model-selection-controller.d.ts.map +1 -0
- package/dist/core/model-selection-controller.js +252 -0
- package/dist/core/model-selection-controller.js.map +1 -0
- package/dist/core/models/model-ref.d.ts +13 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +22 -0
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/profile-filter-controller.d.ts +77 -0
- package/dist/core/profile-filter-controller.d.ts.map +1 -0
- package/dist/core/profile-filter-controller.js +159 -0
- package/dist/core/profile-filter-controller.js.map +1 -0
- package/dist/core/reflection-controller.d.ts +111 -0
- package/dist/core/reflection-controller.d.ts.map +1 -0
- package/dist/core/reflection-controller.js +412 -0
- package/dist/core/reflection-controller.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +12 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +21 -0
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/research/session-evidence-bundle.d.ts +1 -1
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/session-evidence-bundle.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +222 -0
- package/dist/core/runtime-builder.d.ts.map +1 -0
- package/dist/core/runtime-builder.js +640 -0
- package/dist/core/runtime-builder.js.map +1 -0
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-analytics.d.ts +96 -0
- package/dist/core/session-analytics.d.ts.map +1 -0
- package/dist/core/session-analytics.js +331 -0
- package/dist/core/session-analytics.js.map +1 -0
- package/dist/core/session-manager-factory.d.ts +18 -0
- package/dist/core/session-manager-factory.d.ts.map +1 -0
- package/dist/core/session-manager-factory.js +32 -0
- package/dist/core/session-manager-factory.js.map +1 -0
- package/dist/core/session-tree-navigator.d.ts +68 -0
- package/dist/core/session-tree-navigator.d.ts.map +1 -0
- package/dist/core/session-tree-navigator.js +217 -0
- package/dist/core/session-tree-navigator.js.map +1 -0
- package/dist/core/system-prompt-builder.d.ts +63 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -0
- package/dist/core/system-prompt-builder.js +181 -0
- package/dist/core/system-prompt-builder.js.map +1 -0
- package/dist/core/tool-gate-controller.d.ts +36 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -0
- package/dist/core/tool-gate-controller.js +94 -0
- package/dist/core/tool-gate-controller.js.map +1 -0
- package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
- package/dist/core/tools/artifact-retrieve.js +1 -1
- package/dist/core/tools/artifact-retrieve.js.map +1 -1
- package/dist/core/tools/bash.d.ts +4 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +49 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +61 -1
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +13 -12
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.d.ts +59 -0
- package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -0
- package/dist/modes/interactive/auth-dialogs-controller.js +398 -0
- package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -0
- package/dist/modes/interactive/auto-learn-controller.d.ts +168 -0
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -0
- package/dist/modes/interactive/auto-learn-controller.js +1239 -0
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -0
- package/dist/modes/interactive/autocomplete-provider.d.ts +26 -0
- package/dist/modes/interactive/autocomplete-provider.d.ts.map +1 -0
- package/dist/modes/interactive/autocomplete-provider.js +103 -0
- package/dist/modes/interactive/autocomplete-provider.js.map +1 -0
- package/dist/modes/interactive/autonomy-commands.d.ts +38 -0
- package/dist/modes/interactive/autonomy-commands.d.ts.map +1 -0
- package/dist/modes/interactive/autonomy-commands.js +142 -0
- package/dist/modes/interactive/autonomy-commands.js.map +1 -0
- package/dist/modes/interactive/clipboard-input.d.ts +37 -0
- package/dist/modes/interactive/clipboard-input.d.ts.map +1 -0
- package/dist/modes/interactive/clipboard-input.js +59 -0
- package/dist/modes/interactive/clipboard-input.js.map +1 -0
- package/dist/modes/interactive/compaction-queue.d.ts +30 -0
- package/dist/modes/interactive/compaction-queue.d.ts.map +1 -0
- package/dist/modes/interactive/compaction-queue.js +91 -0
- package/dist/modes/interactive/compaction-queue.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/config-backup.d.ts +27 -0
- package/dist/modes/interactive/config-backup.d.ts.map +1 -0
- package/dist/modes/interactive/config-backup.js +146 -0
- package/dist/modes/interactive/config-backup.js.map +1 -0
- package/dist/modes/interactive/editor-overlay-host.d.ts +48 -0
- package/dist/modes/interactive/editor-overlay-host.d.ts.map +1 -0
- package/dist/modes/interactive/editor-overlay-host.js +43 -0
- package/dist/modes/interactive/editor-overlay-host.js.map +1 -0
- package/dist/modes/interactive/extension-ui-host.d.ts +165 -0
- package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -0
- package/dist/modes/interactive/extension-ui-host.js +610 -0
- package/dist/modes/interactive/extension-ui-host.js.map +1 -0
- package/dist/modes/interactive/external-editor.d.ts +18 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +107 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/history-reload-math.d.ts +24 -0
- package/dist/modes/interactive/history-reload-math.d.ts.map +1 -0
- package/dist/modes/interactive/history-reload-math.js +129 -0
- package/dist/modes/interactive/history-reload-math.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +22 -238
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +714 -5910
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/key-handlers.d.ts +46 -0
- package/dist/modes/interactive/key-handlers.d.ts.map +1 -0
- package/dist/modes/interactive/key-handlers.js +80 -0
- package/dist/modes/interactive/key-handlers.js.map +1 -0
- package/dist/modes/interactive/local-model-commands.d.ts +68 -0
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -0
- package/dist/modes/interactive/local-model-commands.js +288 -0
- package/dist/modes/interactive/local-model-commands.js.map +1 -0
- package/dist/modes/interactive/profile-menu-controller.d.ts +77 -0
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -0
- package/dist/modes/interactive/profile-menu-controller.js +917 -0
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -0
- package/dist/modes/interactive/report-commands.d.ts +46 -0
- package/dist/modes/interactive/report-commands.d.ts.map +1 -0
- package/dist/modes/interactive/report-commands.js +255 -0
- package/dist/modes/interactive/report-commands.js.map +1 -0
- package/dist/modes/interactive/resource-display.d.ts +73 -0
- package/dist/modes/interactive/resource-display.d.ts.map +1 -0
- package/dist/modes/interactive/resource-display.js +278 -0
- package/dist/modes/interactive/resource-display.js.map +1 -0
- package/dist/modes/interactive/resource-shell-commands.d.ts +64 -0
- package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -0
- package/dist/modes/interactive/resource-shell-commands.js +202 -0
- package/dist/modes/interactive/resource-shell-commands.js.map +1 -0
- package/dist/modes/interactive/session-flow-commands.d.ts +139 -0
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -0
- package/dist/modes/interactive/session-flow-commands.js +458 -0
- package/dist/modes/interactive/session-flow-commands.js.map +1 -0
- package/dist/modes/interactive/session-io-commands.d.ts +73 -0
- package/dist/modes/interactive/session-io-commands.d.ts.map +1 -0
- package/dist/modes/interactive/session-io-commands.js +202 -0
- package/dist/modes/interactive/session-io-commands.js.map +1 -0
- package/dist/modes/interactive/settings-selector-flow.d.ts +42 -0
- package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -0
- package/dist/modes/interactive/settings-selector-flow.js +287 -0
- package/dist/modes/interactive/settings-selector-flow.js.map +1 -0
- package/dist/modes/interactive/signal-lifecycle.d.ts +55 -0
- package/dist/modes/interactive/signal-lifecycle.d.ts.map +1 -0
- package/dist/modes/interactive/signal-lifecycle.js +177 -0
- package/dist/modes/interactive/signal-lifecycle.js.map +1 -0
- package/dist/modes/interactive/startup-checks.d.ts +38 -0
- package/dist/modes/interactive/startup-checks.d.ts.map +1 -0
- package/dist/modes/interactive/startup-checks.js +189 -0
- package/dist/modes/interactive/startup-checks.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -14
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +5 -30
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/process-memory.d.ts +8 -0
- package/dist/utils/process-memory.d.ts.map +1 -0
- package/dist/utils/process-memory.js +11 -0
- package/dist/utils/process-memory.js.map +1 -0
- package/dist/utils/shell.d.ts +0 -9
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +0 -37
- package/dist/utils/shell.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/11-sessions.ts +8 -8
- package/examples/sdk/13-session-runtime.ts +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/core/compaction/branch-summarization.d.ts +0 -88
- package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/core/compaction/branch-summarization.js +0 -243
- package/dist/core/compaction/branch-summarization.js.map +0 -1
- package/dist/core/compaction/compaction.d.ts +0 -143
- package/dist/core/compaction/compaction.d.ts.map +0 -1
- package/dist/core/compaction/compaction.js +0 -659
- package/dist/core/compaction/compaction.js.map +0 -1
- package/dist/core/compaction/index.d.ts +0 -7
- package/dist/core/compaction/index.d.ts.map +0 -1
- package/dist/core/compaction/index.js +0 -7
- package/dist/core/compaction/index.js.map +0 -1
- package/dist/core/compaction/utils.d.ts +0 -38
- package/dist/core/compaction/utils.d.ts.map +0 -1
- package/dist/core/compaction/utils.js +0 -153
- package/dist/core/compaction/utils.js.map +0 -1
- package/dist/core/message-retention.d.ts +0 -26
- package/dist/core/message-retention.d.ts.map +0 -1
- package/dist/core/message-retention.js +0 -95
- package/dist/core/message-retention.js.map +0 -1
- package/dist/core/messages.d.ts +0 -77
- package/dist/core/messages.d.ts.map +0 -1
- package/dist/core/messages.js +0 -123
- package/dist/core/messages.js.map +0 -1
- package/dist/core/session-manager.d.ts +0 -337
- package/dist/core/session-manager.d.ts.map +0 -1
- package/dist/core/session-manager.js +0 -1328
- package/dist/core/session-manager.js.map +0 -1
- package/dist/core/tools/truncate.d.ts +0 -70
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js +0 -215
- package/dist/core/tools/truncate.js.map +0 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-tree navigation (in-file branch switching + fork-selector reads).
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). `navigateTree` moves the leaf
|
|
5
|
+
* to another node in the SAME session file (unlike fork(), which creates a new file), optionally
|
|
6
|
+
* summarizing the abandoned branch via the model or an extension override. It owns no state: the
|
|
7
|
+
* branch-summary abort controller stays on the session (also read by `isCompacting`) and is set/cleared
|
|
8
|
+
* here through a dep so the session's abort/compacting surface is untouched.
|
|
9
|
+
*/
|
|
10
|
+
import { collectEntriesForBranchSummary, generateBranchSummary, } from "@caupulican/pi-agent-core/node";
|
|
11
|
+
export class SessionTreeNavigator {
|
|
12
|
+
deps;
|
|
13
|
+
constructor(deps) {
|
|
14
|
+
this.deps = deps;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Navigate to a different node in the session tree.
|
|
18
|
+
* Unlike fork() which creates a new session file, this stays in the same file.
|
|
19
|
+
*
|
|
20
|
+
* @param targetId The entry ID to navigate to
|
|
21
|
+
* @param options.summarize Whether user wants to summarize abandoned branch
|
|
22
|
+
* @param options.customInstructions Custom instructions for summarizer
|
|
23
|
+
* @param options.replaceInstructions If true, customInstructions replaces the default prompt
|
|
24
|
+
* @param options.label Label to attach to the branch summary entry
|
|
25
|
+
* @returns Result with editorText (if user message) and cancelled status
|
|
26
|
+
*/
|
|
27
|
+
async navigateTree(targetId, options = {}) {
|
|
28
|
+
const sessionManager = this.deps.getSessionManager();
|
|
29
|
+
const extensionRunner = this.deps.getExtensionRunner();
|
|
30
|
+
const oldLeafId = sessionManager.getLeafId();
|
|
31
|
+
// No-op if already at target
|
|
32
|
+
if (targetId === oldLeafId) {
|
|
33
|
+
return { cancelled: false };
|
|
34
|
+
}
|
|
35
|
+
// Model required for summarization
|
|
36
|
+
if (options.summarize && !this.deps.getModel()) {
|
|
37
|
+
throw new Error("No model available for summarization");
|
|
38
|
+
}
|
|
39
|
+
const targetEntry = sessionManager.getEntry(targetId);
|
|
40
|
+
if (!targetEntry) {
|
|
41
|
+
throw new Error(`Entry ${targetId} not found`);
|
|
42
|
+
}
|
|
43
|
+
// Collect entries to summarize (from old leaf to common ancestor)
|
|
44
|
+
const { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary(sessionManager, oldLeafId, targetId);
|
|
45
|
+
// Prepare event data - mutable so extensions can override
|
|
46
|
+
let customInstructions = options.customInstructions;
|
|
47
|
+
let replaceInstructions = options.replaceInstructions;
|
|
48
|
+
let label = options.label;
|
|
49
|
+
const preparation = {
|
|
50
|
+
targetId,
|
|
51
|
+
oldLeafId,
|
|
52
|
+
commonAncestorId,
|
|
53
|
+
entriesToSummarize,
|
|
54
|
+
userWantsSummary: options.summarize ?? false,
|
|
55
|
+
customInstructions,
|
|
56
|
+
replaceInstructions,
|
|
57
|
+
label,
|
|
58
|
+
};
|
|
59
|
+
// Set up abort controller for summarization
|
|
60
|
+
const branchSummaryAbort = new AbortController();
|
|
61
|
+
this.deps.setBranchSummaryAbort(branchSummaryAbort);
|
|
62
|
+
try {
|
|
63
|
+
let extensionSummary;
|
|
64
|
+
let fromExtension = false;
|
|
65
|
+
// Emit session_before_tree event
|
|
66
|
+
if (extensionRunner.hasHandlers("session_before_tree")) {
|
|
67
|
+
const result = (await extensionRunner.emit({
|
|
68
|
+
type: "session_before_tree",
|
|
69
|
+
preparation,
|
|
70
|
+
signal: branchSummaryAbort.signal,
|
|
71
|
+
}));
|
|
72
|
+
if (result?.cancel) {
|
|
73
|
+
return { cancelled: true };
|
|
74
|
+
}
|
|
75
|
+
if (result?.summary && options.summarize) {
|
|
76
|
+
extensionSummary = result.summary;
|
|
77
|
+
fromExtension = true;
|
|
78
|
+
}
|
|
79
|
+
// Allow extensions to override instructions and label
|
|
80
|
+
if (result?.customInstructions !== undefined) {
|
|
81
|
+
customInstructions = result.customInstructions;
|
|
82
|
+
}
|
|
83
|
+
if (result?.replaceInstructions !== undefined) {
|
|
84
|
+
replaceInstructions = result.replaceInstructions;
|
|
85
|
+
}
|
|
86
|
+
if (result?.label !== undefined) {
|
|
87
|
+
label = result.label;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Run default summarizer if needed
|
|
91
|
+
let summaryText;
|
|
92
|
+
let summaryDetails;
|
|
93
|
+
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
|
94
|
+
const model = this.deps.getModel();
|
|
95
|
+
const { apiKey, headers } = await this.deps.getRequiredRequestAuth(model);
|
|
96
|
+
const branchSummarySettings = this.deps.getSettingsManager().getBranchSummarySettings();
|
|
97
|
+
const result = await generateBranchSummary(entriesToSummarize, {
|
|
98
|
+
model,
|
|
99
|
+
apiKey,
|
|
100
|
+
headers,
|
|
101
|
+
signal: branchSummaryAbort.signal,
|
|
102
|
+
customInstructions,
|
|
103
|
+
replaceInstructions,
|
|
104
|
+
reserveTokens: branchSummarySettings.reserveTokens,
|
|
105
|
+
});
|
|
106
|
+
if (result.aborted) {
|
|
107
|
+
return { cancelled: true, aborted: true };
|
|
108
|
+
}
|
|
109
|
+
if (result.error) {
|
|
110
|
+
throw new Error(result.error);
|
|
111
|
+
}
|
|
112
|
+
summaryText = result.summary;
|
|
113
|
+
summaryDetails = {
|
|
114
|
+
readFiles: result.readFiles || [],
|
|
115
|
+
modifiedFiles: result.modifiedFiles || [],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
else if (extensionSummary) {
|
|
119
|
+
summaryText = extensionSummary.summary;
|
|
120
|
+
summaryDetails = extensionSummary.details;
|
|
121
|
+
}
|
|
122
|
+
// Determine the new leaf position based on target type
|
|
123
|
+
let newLeafId;
|
|
124
|
+
let editorText;
|
|
125
|
+
if (targetEntry.type === "message" && targetEntry.message.role === "user") {
|
|
126
|
+
// User message: leaf = parent (null if root), text goes to editor
|
|
127
|
+
newLeafId = targetEntry.parentId;
|
|
128
|
+
editorText = this._extractUserMessageText(targetEntry.message.content);
|
|
129
|
+
}
|
|
130
|
+
else if (targetEntry.type === "custom_message") {
|
|
131
|
+
// Custom message: leaf = parent (null if root), text goes to editor
|
|
132
|
+
newLeafId = targetEntry.parentId;
|
|
133
|
+
editorText =
|
|
134
|
+
typeof targetEntry.content === "string"
|
|
135
|
+
? targetEntry.content
|
|
136
|
+
: targetEntry.content
|
|
137
|
+
.filter((c) => c.type === "text")
|
|
138
|
+
.map((c) => c.text)
|
|
139
|
+
.join("");
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
// Non-user message: leaf = selected node
|
|
143
|
+
newLeafId = targetId;
|
|
144
|
+
}
|
|
145
|
+
// Switch leaf (with or without summary)
|
|
146
|
+
// Summary is attached at the navigation target position (newLeafId), not the old branch
|
|
147
|
+
let summaryEntry;
|
|
148
|
+
if (summaryText) {
|
|
149
|
+
// Create summary at target position (can be null for root)
|
|
150
|
+
const summaryId = sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension);
|
|
151
|
+
summaryEntry = sessionManager.getEntry(summaryId);
|
|
152
|
+
// Attach label to the summary entry
|
|
153
|
+
if (label) {
|
|
154
|
+
sessionManager.appendLabelChange(summaryId, label);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (newLeafId === null) {
|
|
158
|
+
// No summary, navigating to root - reset leaf
|
|
159
|
+
sessionManager.resetLeaf();
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
// No summary, navigating to non-root
|
|
163
|
+
sessionManager.branch(newLeafId);
|
|
164
|
+
}
|
|
165
|
+
// Attach label to target entry when not summarizing (no summary entry to label)
|
|
166
|
+
if (label && !summaryText) {
|
|
167
|
+
sessionManager.appendLabelChange(targetId, label);
|
|
168
|
+
}
|
|
169
|
+
// Update agent state
|
|
170
|
+
const sessionContext = sessionManager.buildSessionContext();
|
|
171
|
+
this.deps.getAgent().state.messages = sessionContext.messages;
|
|
172
|
+
// Emit session_tree event
|
|
173
|
+
await extensionRunner.emit({
|
|
174
|
+
type: "session_tree",
|
|
175
|
+
newLeafId: sessionManager.getLeafId(),
|
|
176
|
+
oldLeafId,
|
|
177
|
+
summaryEntry,
|
|
178
|
+
fromExtension: summaryText ? fromExtension : undefined,
|
|
179
|
+
});
|
|
180
|
+
// Emit to custom tools
|
|
181
|
+
return { editorText, cancelled: false, summaryEntry };
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
this.deps.setBranchSummaryAbort(undefined);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get all user messages from session for fork selector.
|
|
189
|
+
*/
|
|
190
|
+
getUserMessagesForForking() {
|
|
191
|
+
const entries = this.deps.getSessionManager().getEntries();
|
|
192
|
+
const result = [];
|
|
193
|
+
for (const entry of entries) {
|
|
194
|
+
if (entry.type !== "message")
|
|
195
|
+
continue;
|
|
196
|
+
if (entry.message.role !== "user")
|
|
197
|
+
continue;
|
|
198
|
+
const text = this._extractUserMessageText(entry.message.content);
|
|
199
|
+
if (text) {
|
|
200
|
+
result.push({ entryId: entry.id, text });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
_extractUserMessageText(content) {
|
|
206
|
+
if (typeof content === "string")
|
|
207
|
+
return content;
|
|
208
|
+
if (Array.isArray(content)) {
|
|
209
|
+
return content
|
|
210
|
+
.filter((c) => c.type === "text")
|
|
211
|
+
.map((c) => c.text)
|
|
212
|
+
.join("");
|
|
213
|
+
}
|
|
214
|
+
return "";
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=session-tree-navigator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tree-navigator.js","sourceRoot":"","sources":["../../src/core/session-tree-navigator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Session-tree navigation (in-file branch switching + fork-selector reads).\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). `navigateTree` moves the leaf\n * to another node in the SAME session file (unlike fork(), which creates a new file), optionally\n * summarizing the abandoned branch via the model or an extension override. It owns no state: the\n * branch-summary abort controller stays on the session (also read by `isCompacting`) and is set/cleared\n * here through a dep so the session's abort/compacting surface is untouched.\n */\n\nimport type { Agent } from \"@caupulican/pi-agent-core\";\nimport {\n\ttype BranchSummaryEntry,\n\tcollectEntriesForBranchSummary,\n\tgenerateBranchSummary,\n\ttype SessionManager,\n} from \"@caupulican/pi-agent-core/node\";\nimport type { Model } from \"@caupulican/pi-ai\";\nimport type { ExtensionRunner, SessionBeforeTreeResult, TreePreparation } from \"./extensions/index.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\nexport interface SessionTreeNavigatorDeps {\n\t/** Session log — leaf/branch reads and writes go through this. */\n\tgetSessionManager(): SessionManager;\n\t/** Current model — required to run the default branch summarizer. */\n\tgetModel(): Model<any> | undefined;\n\t/** Extension runner — `session_before_tree`/`session_tree` hooks fire here. */\n\tgetExtensionRunner(): ExtensionRunner;\n\t/** Resolve request auth for the summarizer call (session-owned, also used by compaction). */\n\tgetRequiredRequestAuth(model: Model<any>): Promise<{ apiKey: string; headers?: Record<string, string> }>;\n\t/** Settings — branch-summary reserve tokens. */\n\tgetSettingsManager(): SettingsManager;\n\t/** The underlying agent — the rebuilt message view is assigned to `agent.state.messages`. */\n\tgetAgent(): Agent;\n\t/** Store/clear the in-flight branch-summary abort controller on the session (read by isCompacting). */\n\tsetBranchSummaryAbort(controller: AbortController | undefined): void;\n}\n\nexport class SessionTreeNavigator {\n\tprivate readonly deps: SessionTreeNavigatorDeps;\n\n\tconstructor(deps: SessionTreeNavigatorDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/**\n\t * Navigate to a different node in the session tree.\n\t * Unlike fork() which creates a new session file, this stays in the same file.\n\t *\n\t * @param targetId The entry ID to navigate to\n\t * @param options.summarize Whether user wants to summarize abandoned branch\n\t * @param options.customInstructions Custom instructions for summarizer\n\t * @param options.replaceInstructions If true, customInstructions replaces the default prompt\n\t * @param options.label Label to attach to the branch summary entry\n\t * @returns Result with editorText (if user message) and cancelled status\n\t */\n\tasync navigateTree(\n\t\ttargetId: string,\n\t\toptions: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string } = {},\n\t): Promise<{ editorText?: string; cancelled: boolean; aborted?: boolean; summaryEntry?: BranchSummaryEntry }> {\n\t\tconst sessionManager = this.deps.getSessionManager();\n\t\tconst extensionRunner = this.deps.getExtensionRunner();\n\t\tconst oldLeafId = sessionManager.getLeafId();\n\n\t\t// No-op if already at target\n\t\tif (targetId === oldLeafId) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\t// Model required for summarization\n\t\tif (options.summarize && !this.deps.getModel()) {\n\t\t\tthrow new Error(\"No model available for summarization\");\n\t\t}\n\n\t\tconst targetEntry = sessionManager.getEntry(targetId);\n\t\tif (!targetEntry) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\n\t\t// Collect entries to summarize (from old leaf to common ancestor)\n\t\tconst { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary(\n\t\t\tsessionManager,\n\t\t\toldLeafId,\n\t\t\ttargetId,\n\t\t);\n\n\t\t// Prepare event data - mutable so extensions can override\n\t\tlet customInstructions = options.customInstructions;\n\t\tlet replaceInstructions = options.replaceInstructions;\n\t\tlet label = options.label;\n\n\t\tconst preparation: TreePreparation = {\n\t\t\ttargetId,\n\t\t\toldLeafId,\n\t\t\tcommonAncestorId,\n\t\t\tentriesToSummarize,\n\t\t\tuserWantsSummary: options.summarize ?? false,\n\t\t\tcustomInstructions,\n\t\t\treplaceInstructions,\n\t\t\tlabel,\n\t\t};\n\n\t\t// Set up abort controller for summarization\n\t\tconst branchSummaryAbort = new AbortController();\n\t\tthis.deps.setBranchSummaryAbort(branchSummaryAbort);\n\n\t\ttry {\n\t\t\tlet extensionSummary: { summary: string; details?: unknown } | undefined;\n\t\t\tlet fromExtension = false;\n\n\t\t\t// Emit session_before_tree event\n\t\t\tif (extensionRunner.hasHandlers(\"session_before_tree\")) {\n\t\t\t\tconst result = (await extensionRunner.emit({\n\t\t\t\t\ttype: \"session_before_tree\",\n\t\t\t\t\tpreparation,\n\t\t\t\t\tsignal: branchSummaryAbort.signal,\n\t\t\t\t})) as SessionBeforeTreeResult | undefined;\n\n\t\t\t\tif (result?.cancel) {\n\t\t\t\t\treturn { cancelled: true };\n\t\t\t\t}\n\n\t\t\t\tif (result?.summary && options.summarize) {\n\t\t\t\t\textensionSummary = result.summary;\n\t\t\t\t\tfromExtension = true;\n\t\t\t\t}\n\n\t\t\t\t// Allow extensions to override instructions and label\n\t\t\t\tif (result?.customInstructions !== undefined) {\n\t\t\t\t\tcustomInstructions = result.customInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.replaceInstructions !== undefined) {\n\t\t\t\t\treplaceInstructions = result.replaceInstructions;\n\t\t\t\t}\n\t\t\t\tif (result?.label !== undefined) {\n\t\t\t\t\tlabel = result.label;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Run default summarizer if needed\n\t\t\tlet summaryText: string | undefined;\n\t\t\tlet summaryDetails: unknown;\n\t\t\tif (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {\n\t\t\t\tconst model = this.deps.getModel()!;\n\t\t\t\tconst { apiKey, headers } = await this.deps.getRequiredRequestAuth(model);\n\t\t\t\tconst branchSummarySettings = this.deps.getSettingsManager().getBranchSummarySettings();\n\t\t\t\tconst result = await generateBranchSummary(entriesToSummarize, {\n\t\t\t\t\tmodel,\n\t\t\t\t\tapiKey,\n\t\t\t\t\theaders,\n\t\t\t\t\tsignal: branchSummaryAbort.signal,\n\t\t\t\t\tcustomInstructions,\n\t\t\t\t\treplaceInstructions,\n\t\t\t\t\treserveTokens: branchSummarySettings.reserveTokens,\n\t\t\t\t});\n\t\t\t\tif (result.aborted) {\n\t\t\t\t\treturn { cancelled: true, aborted: true };\n\t\t\t\t}\n\t\t\t\tif (result.error) {\n\t\t\t\t\tthrow new Error(result.error);\n\t\t\t\t}\n\t\t\t\tsummaryText = result.summary;\n\t\t\t\tsummaryDetails = {\n\t\t\t\t\treadFiles: result.readFiles || [],\n\t\t\t\t\tmodifiedFiles: result.modifiedFiles || [],\n\t\t\t\t};\n\t\t\t} else if (extensionSummary) {\n\t\t\t\tsummaryText = extensionSummary.summary;\n\t\t\t\tsummaryDetails = extensionSummary.details;\n\t\t\t}\n\n\t\t\t// Determine the new leaf position based on target type\n\t\t\tlet newLeafId: string | null;\n\t\t\tlet editorText: string | undefined;\n\n\t\t\tif (targetEntry.type === \"message\" && targetEntry.message.role === \"user\") {\n\t\t\t\t// User message: leaf = parent (null if root), text goes to editor\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText = this._extractUserMessageText(targetEntry.message.content);\n\t\t\t} else if (targetEntry.type === \"custom_message\") {\n\t\t\t\t// Custom message: leaf = parent (null if root), text goes to editor\n\t\t\t\tnewLeafId = targetEntry.parentId;\n\t\t\t\teditorText =\n\t\t\t\t\ttypeof targetEntry.content === \"string\"\n\t\t\t\t\t\t? targetEntry.content\n\t\t\t\t\t\t: targetEntry.content\n\t\t\t\t\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t\t\t\t\t.map((c) => c.text)\n\t\t\t\t\t\t\t\t.join(\"\");\n\t\t\t} else {\n\t\t\t\t// Non-user message: leaf = selected node\n\t\t\t\tnewLeafId = targetId;\n\t\t\t}\n\n\t\t\t// Switch leaf (with or without summary)\n\t\t\t// Summary is attached at the navigation target position (newLeafId), not the old branch\n\t\t\tlet summaryEntry: BranchSummaryEntry | undefined;\n\t\t\tif (summaryText) {\n\t\t\t\t// Create summary at target position (can be null for root)\n\t\t\t\tconst summaryId = sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension);\n\t\t\t\tsummaryEntry = sessionManager.getEntry(summaryId) as BranchSummaryEntry;\n\n\t\t\t\t// Attach label to the summary entry\n\t\t\t\tif (label) {\n\t\t\t\t\tsessionManager.appendLabelChange(summaryId, label);\n\t\t\t\t}\n\t\t\t} else if (newLeafId === null) {\n\t\t\t\t// No summary, navigating to root - reset leaf\n\t\t\t\tsessionManager.resetLeaf();\n\t\t\t} else {\n\t\t\t\t// No summary, navigating to non-root\n\t\t\t\tsessionManager.branch(newLeafId);\n\t\t\t}\n\n\t\t\t// Attach label to target entry when not summarizing (no summary entry to label)\n\t\t\tif (label && !summaryText) {\n\t\t\t\tsessionManager.appendLabelChange(targetId, label);\n\t\t\t}\n\n\t\t\t// Update agent state\n\t\t\tconst sessionContext = sessionManager.buildSessionContext();\n\t\t\tthis.deps.getAgent().state.messages = sessionContext.messages;\n\n\t\t\t// Emit session_tree event\n\t\t\tawait extensionRunner.emit({\n\t\t\t\ttype: \"session_tree\",\n\t\t\t\tnewLeafId: sessionManager.getLeafId(),\n\t\t\t\toldLeafId,\n\t\t\t\tsummaryEntry,\n\t\t\t\tfromExtension: summaryText ? fromExtension : undefined,\n\t\t\t});\n\n\t\t\t// Emit to custom tools\n\n\t\t\treturn { editorText, cancelled: false, summaryEntry };\n\t\t} finally {\n\t\t\tthis.deps.setBranchSummaryAbort(undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Get all user messages from session for fork selector.\n\t */\n\tgetUserMessagesForForking(): Array<{ entryId: string; text: string }> {\n\t\tconst entries = this.deps.getSessionManager().getEntries();\n\t\tconst result: Array<{ entryId: string; text: string }> = [];\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tif (entry.message.role !== \"user\") continue;\n\n\t\t\tconst text = this._extractUserMessageText(entry.message.content);\n\t\t\tif (text) {\n\t\t\t\tresult.push({ entryId: entry.id, text });\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\t\tif (typeof content === \"string\") return content;\n\t\tif (Array.isArray(content)) {\n\t\t\treturn content\n\t\t\t\t.filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t}\n\t\treturn \"\";\n\t}\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session system-prompt construction.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Owns the assembly of the
|
|
5
|
+
* session's base system prompt from live session state — the active profile's situational soul, the
|
|
6
|
+
* self-modification and autonomy guardrail blocks, the memory block, the loader's custom/append
|
|
7
|
+
* prompts, and the per-tool snippet/guideline surface — into the {@link BuildSystemPromptOptions}
|
|
8
|
+
* that the pure {@link buildSystemPrompt} renderer (core/system-prompt.ts, a different job: the
|
|
9
|
+
* stateless string builder) consumes. Holds the last-built `_baseSystemPromptOptions` so a
|
|
10
|
+
* before_agent_start extension hook can read it. Takes narrow accessor deps (each read fresh, since
|
|
11
|
+
* several collaborators — tool registries, memory manager, extension runner — are reassigned across
|
|
12
|
+
* the session lifecycle) rather than the whole AgentSession.
|
|
13
|
+
*/
|
|
14
|
+
import type { Extension } from "./extensions/types.ts";
|
|
15
|
+
import type { MemoryManager } from "./memory/memory-manager.ts";
|
|
16
|
+
import type { ResourceLoader } from "./resource-loader.ts";
|
|
17
|
+
import type { SettingsManager } from "./settings-manager.ts";
|
|
18
|
+
import { type BuildSystemPromptOptions } from "./system-prompt.ts";
|
|
19
|
+
export interface SystemPromptBuilderDeps {
|
|
20
|
+
/** The session's working directory (read fresh; base for self-modification source resolution). */
|
|
21
|
+
getCwd(): string;
|
|
22
|
+
/** The session's settings manager — soul, self-modification, autonomy, and auto-learn settings. */
|
|
23
|
+
getSettingsManager(): SettingsManager;
|
|
24
|
+
/** The session's resource loader — custom/append system prompts, active skills, agents files. */
|
|
25
|
+
getResourceLoader(): ResourceLoader;
|
|
26
|
+
/** The session's memory manager — the static, frozen-per-session memory system-prompt block. */
|
|
27
|
+
getMemoryManager(): MemoryManager;
|
|
28
|
+
/** Whether a tool name is currently registered on the session. */
|
|
29
|
+
hasTool(name: string): boolean;
|
|
30
|
+
/** The one-line prompt snippet registered for a tool, if any. */
|
|
31
|
+
getToolPromptSnippet(name: string): string | undefined;
|
|
32
|
+
/** The extra guideline bullets registered for a tool, if any. */
|
|
33
|
+
getToolPromptGuidelines(name: string): string[] | undefined;
|
|
34
|
+
/** The session's currently active extensions. */
|
|
35
|
+
getActiveExtensions(): ReadonlyArray<Extension>;
|
|
36
|
+
}
|
|
37
|
+
export declare class SystemPromptBuilder {
|
|
38
|
+
private readonly deps;
|
|
39
|
+
private _baseSystemPromptOptions;
|
|
40
|
+
constructor(deps: SystemPromptBuilderDeps);
|
|
41
|
+
/** The options used to render the last base prompt — read by a before_agent_start extension hook. */
|
|
42
|
+
getBaseSystemPromptOptions(): BuildSystemPromptOptions;
|
|
43
|
+
normalizePromptSnippet(text: string | undefined): string | undefined;
|
|
44
|
+
normalizePromptGuidelines(guidelines: string[] | undefined): string[];
|
|
45
|
+
/**
|
|
46
|
+
* R6: the active profile's situational soul, wrapped so the model reads it as its identity for this
|
|
47
|
+
* situation. Empty when no active profile defines a soul.
|
|
48
|
+
*/
|
|
49
|
+
private _buildSituationSoulPrompt;
|
|
50
|
+
private _buildSelfModificationPrompt;
|
|
51
|
+
private _buildAutonomyPrompt;
|
|
52
|
+
private _buildSystemPromptOptionsForToolNames;
|
|
53
|
+
rebuildSystemPrompt(toolNames: string[]): string;
|
|
54
|
+
/**
|
|
55
|
+
* Build a system prompt for a specific tool surface WITHOUT touching the session's base prompt
|
|
56
|
+
* state. Used for a router-swapped turn (G4): the routed model runs against a filtered tool set,
|
|
57
|
+
* so it must also receive a system prompt whose tool guidelines/snippets match that filtered
|
|
58
|
+
* surface — but the change is per-turn, so it must not mutate `_baseSystemPromptOptions` (which
|
|
59
|
+
* later turns and extension events read).
|
|
60
|
+
*/
|
|
61
|
+
buildSystemPromptForToolNames(toolNames: string[]): string;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=system-prompt-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,KAAK,wBAAwB,EAAqB,MAAM,oBAAoB,CAAC;AAEtF,MAAM,WAAW,uBAAuB;IACvC,kGAAkG;IAClG,MAAM,IAAI,MAAM,CAAC;IACjB,qGAAmG;IACnG,kBAAkB,IAAI,eAAe,CAAC;IACtC,mGAAiG;IACjG,iBAAiB,IAAI,cAAc,CAAC;IACpC,kGAAgG;IAChG,gBAAgB,IAAI,aAAa,CAAC;IAClC,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,iEAAiE;IACjE,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD,iEAAiE;IACjE,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5D,iDAAiD;IACjD,mBAAmB,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;CAChD;AAED,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,wBAAwB,CAA4B;IAE5D,YAAY,IAAI,EAAE,uBAAuB,EAExC;IAED,uGAAqG;IACrG,0BAA0B,IAAI,wBAAwB,CAErD;IAED,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOnE;IAED,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,CAapE;IAED;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAMjC,OAAO,CAAC,4BAA4B;IAgDpC,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,qCAAqC;IAiD7C,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAG/C;IAED;;;;;;OAMG;IACH,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAEzD;CACD","sourcesContent":["/**\n * Session system-prompt construction.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the assembly of the\n * session's base system prompt from live session state — the active profile's situational soul, the\n * self-modification and autonomy guardrail blocks, the memory block, the loader's custom/append\n * prompts, and the per-tool snippet/guideline surface — into the {@link BuildSystemPromptOptions}\n * that the pure {@link buildSystemPrompt} renderer (core/system-prompt.ts, a different job: the\n * stateless string builder) consumes. Holds the last-built `_baseSystemPromptOptions` so a\n * before_agent_start extension hook can read it. Takes narrow accessor deps (each read fresh, since\n * several collaborators — tool registries, memory manager, extension runner — are reassigned across\n * the session lifecycle) rather than the whole AgentSession.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport type { Extension } from \"./extensions/types.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { UNTRUSTED_BOUNDARY_SYSTEM_RULE } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { type BuildSystemPromptOptions, buildSystemPrompt } from \"./system-prompt.ts\";\n\nexport interface SystemPromptBuilderDeps {\n\t/** The session's working directory (read fresh; base for self-modification source resolution). */\n\tgetCwd(): string;\n\t/** The session's settings manager — soul, self-modification, autonomy, and auto-learn settings. */\n\tgetSettingsManager(): SettingsManager;\n\t/** The session's resource loader — custom/append system prompts, active skills, agents files. */\n\tgetResourceLoader(): ResourceLoader;\n\t/** The session's memory manager — the static, frozen-per-session memory system-prompt block. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Whether a tool name is currently registered on the session. */\n\thasTool(name: string): boolean;\n\t/** The one-line prompt snippet registered for a tool, if any. */\n\tgetToolPromptSnippet(name: string): string | undefined;\n\t/** The extra guideline bullets registered for a tool, if any. */\n\tgetToolPromptGuidelines(name: string): string[] | undefined;\n\t/** The session's currently active extensions. */\n\tgetActiveExtensions(): ReadonlyArray<Extension>;\n}\n\nexport class SystemPromptBuilder {\n\tprivate readonly deps: SystemPromptBuilderDeps;\n\tprivate _baseSystemPromptOptions!: BuildSystemPromptOptions;\n\n\tconstructor(deps: SystemPromptBuilderDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The options used to render the last base prompt — read by a before_agent_start extension hook. */\n\tgetBaseSystemPromptOptions(): BuildSystemPromptOptions {\n\t\treturn this._baseSystemPromptOptions;\n\t}\n\n\tnormalizePromptSnippet(text: string | undefined): string | undefined {\n\t\tif (!text) return undefined;\n\t\tconst oneLine = text\n\t\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t.trim();\n\t\treturn oneLine.length > 0 ? oneLine : undefined;\n\t}\n\n\tnormalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\t\tif (!guidelines || guidelines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst unique = new Set<string>();\n\t\tfor (const guideline of guidelines) {\n\t\t\tconst normalized = guideline.trim();\n\t\t\tif (normalized.length > 0) {\n\t\t\t\tunique.add(normalized);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(unique);\n\t}\n\n\t/**\n\t * R6: the active profile's situational soul, wrapped so the model reads it as its identity for this\n\t * situation. Empty when no active profile defines a soul.\n\t */\n\tprivate _buildSituationSoulPrompt(): string | undefined {\n\t\tconst soul = this.deps.getSettingsManager().getActiveProfileSoul();\n\t\tif (!soul) return undefined;\n\t\treturn `<situation_soul>\\n${soul}\\n</situation_soul>`;\n\t}\n\n\tprivate _buildSelfModificationPrompt(): string | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getSelfModificationSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Resolve from an ordered candidate list first (portable WSL/Termux switching\n\t\t// from settings alone), then fall back to the legacy single sourcePath.\n\t\tconst rawCandidates = [\n\t\t\t...(Array.isArray(settings.sourcePaths) ? settings.sourcePaths : []),\n\t\t\t...(settings.sourcePath ? [settings.sourcePath] : []),\n\t\t]\n\t\t\t.map((candidate) => candidate?.trim())\n\t\t\t.filter((candidate): candidate is string => Boolean(candidate));\n\n\t\tif (rawCandidates.length === 0) {\n\t\t\treturn `Pi self-modification guardrails (local setting active, source missing):\n- Self-modification is enabled, but no \\`selfModification.sourcePaths\\`/\\`selfModification.sourcePath\\` value is set.\n- Do not modify Pi core or runtime output. Ask the user to set \\`selfModification.sourcePaths\\` to the pi-adaptative source checkout before proceeding.`;\n\t\t}\n\n\t\tconst resolvedCandidates = rawCandidates.map((candidate) =>\n\t\t\tresolvePath(candidate, this.deps.getCwd(), { trim: true }),\n\t\t);\n\t\tconst sourcePath =\n\t\t\tresolvedCandidates.find(\n\t\t\t\t(candidate) => existsSync(candidate) && existsSync(resolvePath(\"package.json\", candidate)),\n\t\t\t) ?? resolvedCandidates[0];\n\t\tconst sourceLooksValid = existsSync(sourcePath) && existsSync(resolvePath(\"package.json\", sourcePath));\n\t\tconst sourceStatus = sourceLooksValid\n\t\t\t? sourcePath\n\t\t\t: `${sourcePath} (missing or not a source checkout; ask the user to correct \\`selfModification.sourcePaths\\` before editing)`;\n\t\tconst autonomy = this.deps.getSettingsManager().getAutonomySettings();\n\t\tconst settingsGate =\n\t\t\tautonomy.mode === \"full\"\n\t\t\t\t? \"In autonomy.mode=full, autonomy/autoLearn setting tuning is covered by the standing autonomy grant; ask before changing credentials, provider auth, package sources, or unrelated preferences.\"\n\t\t\t\t: \"Ask for explicit approval before changing global settings.\";\n\t\treturn `Pi self-modification guardrails (local setting active):\n- Authorized pi-adaptative source path: ${sourceStatus}\n- Only modify Pi core/harness source under the authorized source path; never patch installed node_modules or generated runtime output as the source of truth.\n- Before changing Pi itself, restate the objective and scope, inspect relevant source/docs/examples, and make the smallest auditable change.\n- Preserve user changes: check git status before and after, avoid unrelated edits, and do not overwrite concurrent work.\n- Validate with focused tests and broader checks proportional to risk before claiming success.\n- Reload/restart/renew only after source changes are saved and auditable.\n- ${settingsGate}\n- Always ask for explicit approval before publishing, pushing, tagging, or releasing.`;\n\t}\n\n\tprivate _buildAutonomyPrompt(): string | undefined {\n\t\tconst autoLearn = this.deps.getSettingsManager().getAutoLearnSettings();\n\t\tconst autonomy = this.deps.getSettingsManager().getAutonomySettings();\n\t\tif (!autoLearn.enabled && autonomy.mode !== \"full\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst reflection = autoLearn.reflectionReview ?? autonomy.mode !== \"off\";\n\t\tconst model = autoLearn.model?.trim() || \"active\";\n\t\tif (autonomy.mode === \"full\") {\n\t\t\treturn `Pi autonomy policy (mode full, standing autonomy):\n- Setting-authorized background learners may run after long sessions or corrective/complex turns using model ${model}; they may act without asking first inside this standing grant.\n- Standing grant: write high-confidence durable memory, create/patch user/project skills, create/patch small user/project extensions/tools, tune autonomy/autoLearn settings, edit the authorized selfModification.sourcePath, run validation, and leave audit/rollback evidence.\n- Hard stops still require explicit foreground approval: publish/npm release, git push, tag creation, credential/provider-auth changes, destructive user-data deletion, network-exposed services, or expanding authority beyond this policy.\n- Treat current-turn evidence as a cue, not proof; prefer deterministic or longitudinal corroboration for durable behavior changes.\n- Active-task work remains primary: autonomy runs must not interrupt user-visible execution or claim task completion without evidence.`;\n\t\t}\n\t\treturn `Pi autonomy policy (mode ${autonomy.mode}):\n- Setting-authorized background learners may run after long sessions${reflection ? \" or corrective/complex turns\" : \"\"} using model ${model}.\n- Background learning may query durable memory and run bounded learning tools.\n- Auto-apply is limited to high-confidence durable memory when explicitly configured; tooling, skill, prompt, extension, settings, and core-source changes stay proposal/approval-gated.\n- Treat current-turn evidence as a cue, not proof; prefer longitudinal corroboration before changing durable behavior.\n- Active-task work remains primary: learning runs must not interrupt user-visible execution or claim task completion.`;\n\t}\n\n\tprivate _buildSystemPromptOptionsForToolNames(toolNames: string[]): BuildSystemPromptOptions {\n\t\tconst validToolNames = toolNames.filter((name) => this.deps.hasTool(name));\n\t\tconst toolSnippets: Record<string, string> = {};\n\t\tconst promptGuidelines: string[] = [];\n\t\tfor (const name of validToolNames) {\n\t\t\tconst snippet = this.deps.getToolPromptSnippet(name);\n\t\t\tif (snippet) {\n\t\t\t\ttoolSnippets[name] = snippet;\n\t\t\t}\n\n\t\t\tconst toolGuidelines = this.deps.getToolPromptGuidelines(name);\n\t\t\tif (toolGuidelines) {\n\t\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t\t}\n\t\t}\n\n\t\tconst loaderSystemPrompt = this.deps.getResourceLoader().getSystemPrompt();\n\t\tconst loaderAppendSystemPrompt = this.deps.getResourceLoader().getAppendSystemPrompt();\n\t\tconst appendSystemPromptParts = [\n\t\t\t// R6: situational soul — the active profile's identity prefix, switched atomically with the\n\t\t\t// profile's capabilities/model. Most prominent, so it comes first.\n\t\t\tthis._buildSituationSoulPrompt(),\n\t\t\t// Always-on untrusted-content boundary contract (gives the <untrusted_content> fences meaning).\n\t\t\tUNTRUSTED_BOUNDARY_SYSTEM_RULE,\n\t\t\tthis._buildSelfModificationPrompt(),\n\t\t\tthis._buildAutonomyPrompt(),\n\t\t\t// Memory subsystem: static, frozen-per-session block (e.g. file-store MEMORY.md/USER.md).\n\t\t\tthis.deps.getMemoryManager().buildSystemPromptBlock() || undefined,\n\t\t\t...loaderAppendSystemPrompt,\n\t\t].filter((part): part is string => Boolean(part));\n\t\tconst appendSystemPrompt = appendSystemPromptParts.length > 0 ? appendSystemPromptParts.join(\"\\n\\n\") : undefined;\n\t\t// Only surface skills the active profile permits — the agent must not be told about (or able\n\t\t// to invoke) a skill its profile blocks.\n\t\tconst loadedSkills = this.deps.getResourceLoader().getActiveSkills();\n\t\tconst loadedContextFiles = this.deps.getResourceLoader().getAgentsFiles().agentsFiles;\n\n\t\treturn {\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tskills: loadedSkills,\n\t\t\tcontextFiles: loadedContextFiles,\n\t\t\tcustomPrompt: loaderSystemPrompt,\n\t\t\tappendSystemPrompt,\n\t\t\tselectedTools: validToolNames,\n\t\t\ttoolSnippets,\n\t\t\tpromptGuidelines,\n\t\t\textensions: [...this.deps.getActiveExtensions()],\n\t\t};\n\t}\n\n\trebuildSystemPrompt(toolNames: string[]): string {\n\t\tthis._baseSystemPromptOptions = this._buildSystemPromptOptionsForToolNames(toolNames);\n\t\treturn buildSystemPrompt(this._baseSystemPromptOptions);\n\t}\n\n\t/**\n\t * Build a system prompt for a specific tool surface WITHOUT touching the session's base prompt\n\t * state. Used for a router-swapped turn (G4): the routed model runs against a filtered tool set,\n\t * so it must also receive a system prompt whose tool guidelines/snippets match that filtered\n\t * surface — but the change is per-turn, so it must not mutate `_baseSystemPromptOptions` (which\n\t * later turns and extension events read).\n\t */\n\tbuildSystemPromptForToolNames(toolNames: string[]): string {\n\t\treturn buildSystemPrompt(this._buildSystemPromptOptionsForToolNames(toolNames));\n\t}\n}\n"]}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session system-prompt construction.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Owns the assembly of the
|
|
5
|
+
* session's base system prompt from live session state — the active profile's situational soul, the
|
|
6
|
+
* self-modification and autonomy guardrail blocks, the memory block, the loader's custom/append
|
|
7
|
+
* prompts, and the per-tool snippet/guideline surface — into the {@link BuildSystemPromptOptions}
|
|
8
|
+
* that the pure {@link buildSystemPrompt} renderer (core/system-prompt.ts, a different job: the
|
|
9
|
+
* stateless string builder) consumes. Holds the last-built `_baseSystemPromptOptions` so a
|
|
10
|
+
* before_agent_start extension hook can read it. Takes narrow accessor deps (each read fresh, since
|
|
11
|
+
* several collaborators — tool registries, memory manager, extension runner — are reassigned across
|
|
12
|
+
* the session lifecycle) rather than the whole AgentSession.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { resolvePath } from "../utils/paths.js";
|
|
16
|
+
import { UNTRUSTED_BOUNDARY_SYSTEM_RULE } from "./security/untrusted-boundary.js";
|
|
17
|
+
import { buildSystemPrompt } from "./system-prompt.js";
|
|
18
|
+
export class SystemPromptBuilder {
|
|
19
|
+
deps;
|
|
20
|
+
_baseSystemPromptOptions;
|
|
21
|
+
constructor(deps) {
|
|
22
|
+
this.deps = deps;
|
|
23
|
+
}
|
|
24
|
+
/** The options used to render the last base prompt — read by a before_agent_start extension hook. */
|
|
25
|
+
getBaseSystemPromptOptions() {
|
|
26
|
+
return this._baseSystemPromptOptions;
|
|
27
|
+
}
|
|
28
|
+
normalizePromptSnippet(text) {
|
|
29
|
+
if (!text)
|
|
30
|
+
return undefined;
|
|
31
|
+
const oneLine = text
|
|
32
|
+
.replace(/[\r\n]+/g, " ")
|
|
33
|
+
.replace(/\s+/g, " ")
|
|
34
|
+
.trim();
|
|
35
|
+
return oneLine.length > 0 ? oneLine : undefined;
|
|
36
|
+
}
|
|
37
|
+
normalizePromptGuidelines(guidelines) {
|
|
38
|
+
if (!guidelines || guidelines.length === 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const unique = new Set();
|
|
42
|
+
for (const guideline of guidelines) {
|
|
43
|
+
const normalized = guideline.trim();
|
|
44
|
+
if (normalized.length > 0) {
|
|
45
|
+
unique.add(normalized);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return Array.from(unique);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* R6: the active profile's situational soul, wrapped so the model reads it as its identity for this
|
|
52
|
+
* situation. Empty when no active profile defines a soul.
|
|
53
|
+
*/
|
|
54
|
+
_buildSituationSoulPrompt() {
|
|
55
|
+
const soul = this.deps.getSettingsManager().getActiveProfileSoul();
|
|
56
|
+
if (!soul)
|
|
57
|
+
return undefined;
|
|
58
|
+
return `<situation_soul>\n${soul}\n</situation_soul>`;
|
|
59
|
+
}
|
|
60
|
+
_buildSelfModificationPrompt() {
|
|
61
|
+
const settings = this.deps.getSettingsManager().getSelfModificationSettings();
|
|
62
|
+
if (!settings.enabled) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
// Resolve from an ordered candidate list first (portable WSL/Termux switching
|
|
66
|
+
// from settings alone), then fall back to the legacy single sourcePath.
|
|
67
|
+
const rawCandidates = [
|
|
68
|
+
...(Array.isArray(settings.sourcePaths) ? settings.sourcePaths : []),
|
|
69
|
+
...(settings.sourcePath ? [settings.sourcePath] : []),
|
|
70
|
+
]
|
|
71
|
+
.map((candidate) => candidate?.trim())
|
|
72
|
+
.filter((candidate) => Boolean(candidate));
|
|
73
|
+
if (rawCandidates.length === 0) {
|
|
74
|
+
return `Pi self-modification guardrails (local setting active, source missing):
|
|
75
|
+
- Self-modification is enabled, but no \`selfModification.sourcePaths\`/\`selfModification.sourcePath\` value is set.
|
|
76
|
+
- Do not modify Pi core or runtime output. Ask the user to set \`selfModification.sourcePaths\` to the pi-adaptative source checkout before proceeding.`;
|
|
77
|
+
}
|
|
78
|
+
const resolvedCandidates = rawCandidates.map((candidate) => resolvePath(candidate, this.deps.getCwd(), { trim: true }));
|
|
79
|
+
const sourcePath = resolvedCandidates.find((candidate) => existsSync(candidate) && existsSync(resolvePath("package.json", candidate))) ?? resolvedCandidates[0];
|
|
80
|
+
const sourceLooksValid = existsSync(sourcePath) && existsSync(resolvePath("package.json", sourcePath));
|
|
81
|
+
const sourceStatus = sourceLooksValid
|
|
82
|
+
? sourcePath
|
|
83
|
+
: `${sourcePath} (missing or not a source checkout; ask the user to correct \`selfModification.sourcePaths\` before editing)`;
|
|
84
|
+
const autonomy = this.deps.getSettingsManager().getAutonomySettings();
|
|
85
|
+
const settingsGate = autonomy.mode === "full"
|
|
86
|
+
? "In autonomy.mode=full, autonomy/autoLearn setting tuning is covered by the standing autonomy grant; ask before changing credentials, provider auth, package sources, or unrelated preferences."
|
|
87
|
+
: "Ask for explicit approval before changing global settings.";
|
|
88
|
+
return `Pi self-modification guardrails (local setting active):
|
|
89
|
+
- Authorized pi-adaptative source path: ${sourceStatus}
|
|
90
|
+
- Only modify Pi core/harness source under the authorized source path; never patch installed node_modules or generated runtime output as the source of truth.
|
|
91
|
+
- Before changing Pi itself, restate the objective and scope, inspect relevant source/docs/examples, and make the smallest auditable change.
|
|
92
|
+
- Preserve user changes: check git status before and after, avoid unrelated edits, and do not overwrite concurrent work.
|
|
93
|
+
- Validate with focused tests and broader checks proportional to risk before claiming success.
|
|
94
|
+
- Reload/restart/renew only after source changes are saved and auditable.
|
|
95
|
+
- ${settingsGate}
|
|
96
|
+
- Always ask for explicit approval before publishing, pushing, tagging, or releasing.`;
|
|
97
|
+
}
|
|
98
|
+
_buildAutonomyPrompt() {
|
|
99
|
+
const autoLearn = this.deps.getSettingsManager().getAutoLearnSettings();
|
|
100
|
+
const autonomy = this.deps.getSettingsManager().getAutonomySettings();
|
|
101
|
+
if (!autoLearn.enabled && autonomy.mode !== "full") {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const reflection = autoLearn.reflectionReview ?? autonomy.mode !== "off";
|
|
105
|
+
const model = autoLearn.model?.trim() || "active";
|
|
106
|
+
if (autonomy.mode === "full") {
|
|
107
|
+
return `Pi autonomy policy (mode full, standing autonomy):
|
|
108
|
+
- Setting-authorized background learners may run after long sessions or corrective/complex turns using model ${model}; they may act without asking first inside this standing grant.
|
|
109
|
+
- Standing grant: write high-confidence durable memory, create/patch user/project skills, create/patch small user/project extensions/tools, tune autonomy/autoLearn settings, edit the authorized selfModification.sourcePath, run validation, and leave audit/rollback evidence.
|
|
110
|
+
- Hard stops still require explicit foreground approval: publish/npm release, git push, tag creation, credential/provider-auth changes, destructive user-data deletion, network-exposed services, or expanding authority beyond this policy.
|
|
111
|
+
- Treat current-turn evidence as a cue, not proof; prefer deterministic or longitudinal corroboration for durable behavior changes.
|
|
112
|
+
- Active-task work remains primary: autonomy runs must not interrupt user-visible execution or claim task completion without evidence.`;
|
|
113
|
+
}
|
|
114
|
+
return `Pi autonomy policy (mode ${autonomy.mode}):
|
|
115
|
+
- Setting-authorized background learners may run after long sessions${reflection ? " or corrective/complex turns" : ""} using model ${model}.
|
|
116
|
+
- Background learning may query durable memory and run bounded learning tools.
|
|
117
|
+
- Auto-apply is limited to high-confidence durable memory when explicitly configured; tooling, skill, prompt, extension, settings, and core-source changes stay proposal/approval-gated.
|
|
118
|
+
- Treat current-turn evidence as a cue, not proof; prefer longitudinal corroboration before changing durable behavior.
|
|
119
|
+
- Active-task work remains primary: learning runs must not interrupt user-visible execution or claim task completion.`;
|
|
120
|
+
}
|
|
121
|
+
_buildSystemPromptOptionsForToolNames(toolNames) {
|
|
122
|
+
const validToolNames = toolNames.filter((name) => this.deps.hasTool(name));
|
|
123
|
+
const toolSnippets = {};
|
|
124
|
+
const promptGuidelines = [];
|
|
125
|
+
for (const name of validToolNames) {
|
|
126
|
+
const snippet = this.deps.getToolPromptSnippet(name);
|
|
127
|
+
if (snippet) {
|
|
128
|
+
toolSnippets[name] = snippet;
|
|
129
|
+
}
|
|
130
|
+
const toolGuidelines = this.deps.getToolPromptGuidelines(name);
|
|
131
|
+
if (toolGuidelines) {
|
|
132
|
+
promptGuidelines.push(...toolGuidelines);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const loaderSystemPrompt = this.deps.getResourceLoader().getSystemPrompt();
|
|
136
|
+
const loaderAppendSystemPrompt = this.deps.getResourceLoader().getAppendSystemPrompt();
|
|
137
|
+
const appendSystemPromptParts = [
|
|
138
|
+
// R6: situational soul — the active profile's identity prefix, switched atomically with the
|
|
139
|
+
// profile's capabilities/model. Most prominent, so it comes first.
|
|
140
|
+
this._buildSituationSoulPrompt(),
|
|
141
|
+
// Always-on untrusted-content boundary contract (gives the <untrusted_content> fences meaning).
|
|
142
|
+
UNTRUSTED_BOUNDARY_SYSTEM_RULE,
|
|
143
|
+
this._buildSelfModificationPrompt(),
|
|
144
|
+
this._buildAutonomyPrompt(),
|
|
145
|
+
// Memory subsystem: static, frozen-per-session block (e.g. file-store MEMORY.md/USER.md).
|
|
146
|
+
this.deps.getMemoryManager().buildSystemPromptBlock() || undefined,
|
|
147
|
+
...loaderAppendSystemPrompt,
|
|
148
|
+
].filter((part) => Boolean(part));
|
|
149
|
+
const appendSystemPrompt = appendSystemPromptParts.length > 0 ? appendSystemPromptParts.join("\n\n") : undefined;
|
|
150
|
+
// Only surface skills the active profile permits — the agent must not be told about (or able
|
|
151
|
+
// to invoke) a skill its profile blocks.
|
|
152
|
+
const loadedSkills = this.deps.getResourceLoader().getActiveSkills();
|
|
153
|
+
const loadedContextFiles = this.deps.getResourceLoader().getAgentsFiles().agentsFiles;
|
|
154
|
+
return {
|
|
155
|
+
cwd: this.deps.getCwd(),
|
|
156
|
+
skills: loadedSkills,
|
|
157
|
+
contextFiles: loadedContextFiles,
|
|
158
|
+
customPrompt: loaderSystemPrompt,
|
|
159
|
+
appendSystemPrompt,
|
|
160
|
+
selectedTools: validToolNames,
|
|
161
|
+
toolSnippets,
|
|
162
|
+
promptGuidelines,
|
|
163
|
+
extensions: [...this.deps.getActiveExtensions()],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
rebuildSystemPrompt(toolNames) {
|
|
167
|
+
this._baseSystemPromptOptions = this._buildSystemPromptOptionsForToolNames(toolNames);
|
|
168
|
+
return buildSystemPrompt(this._baseSystemPromptOptions);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Build a system prompt for a specific tool surface WITHOUT touching the session's base prompt
|
|
172
|
+
* state. Used for a router-swapped turn (G4): the routed model runs against a filtered tool set,
|
|
173
|
+
* so it must also receive a system prompt whose tool guidelines/snippets match that filtered
|
|
174
|
+
* surface — but the change is per-turn, so it must not mutate `_baseSystemPromptOptions` (which
|
|
175
|
+
* later turns and extension events read).
|
|
176
|
+
*/
|
|
177
|
+
buildSystemPromptForToolNames(toolNames) {
|
|
178
|
+
return buildSystemPrompt(this._buildSystemPromptOptionsForToolNames(toolNames));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=system-prompt-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt-builder.js","sourceRoot":"","sources":["../../src/core/system-prompt-builder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Session system-prompt construction.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the assembly of the\n * session's base system prompt from live session state — the active profile's situational soul, the\n * self-modification and autonomy guardrail blocks, the memory block, the loader's custom/append\n * prompts, and the per-tool snippet/guideline surface — into the {@link BuildSystemPromptOptions}\n * that the pure {@link buildSystemPrompt} renderer (core/system-prompt.ts, a different job: the\n * stateless string builder) consumes. Holds the last-built `_baseSystemPromptOptions` so a\n * before_agent_start extension hook can read it. Takes narrow accessor deps (each read fresh, since\n * several collaborators — tool registries, memory manager, extension runner — are reassigned across\n * the session lifecycle) rather than the whole AgentSession.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport type { Extension } from \"./extensions/types.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { UNTRUSTED_BOUNDARY_SYSTEM_RULE } from \"./security/untrusted-boundary.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { type BuildSystemPromptOptions, buildSystemPrompt } from \"./system-prompt.ts\";\n\nexport interface SystemPromptBuilderDeps {\n\t/** The session's working directory (read fresh; base for self-modification source resolution). */\n\tgetCwd(): string;\n\t/** The session's settings manager — soul, self-modification, autonomy, and auto-learn settings. */\n\tgetSettingsManager(): SettingsManager;\n\t/** The session's resource loader — custom/append system prompts, active skills, agents files. */\n\tgetResourceLoader(): ResourceLoader;\n\t/** The session's memory manager — the static, frozen-per-session memory system-prompt block. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Whether a tool name is currently registered on the session. */\n\thasTool(name: string): boolean;\n\t/** The one-line prompt snippet registered for a tool, if any. */\n\tgetToolPromptSnippet(name: string): string | undefined;\n\t/** The extra guideline bullets registered for a tool, if any. */\n\tgetToolPromptGuidelines(name: string): string[] | undefined;\n\t/** The session's currently active extensions. */\n\tgetActiveExtensions(): ReadonlyArray<Extension>;\n}\n\nexport class SystemPromptBuilder {\n\tprivate readonly deps: SystemPromptBuilderDeps;\n\tprivate _baseSystemPromptOptions!: BuildSystemPromptOptions;\n\n\tconstructor(deps: SystemPromptBuilderDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/** The options used to render the last base prompt — read by a before_agent_start extension hook. */\n\tgetBaseSystemPromptOptions(): BuildSystemPromptOptions {\n\t\treturn this._baseSystemPromptOptions;\n\t}\n\n\tnormalizePromptSnippet(text: string | undefined): string | undefined {\n\t\tif (!text) return undefined;\n\t\tconst oneLine = text\n\t\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t.trim();\n\t\treturn oneLine.length > 0 ? oneLine : undefined;\n\t}\n\n\tnormalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\t\tif (!guidelines || guidelines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst unique = new Set<string>();\n\t\tfor (const guideline of guidelines) {\n\t\t\tconst normalized = guideline.trim();\n\t\t\tif (normalized.length > 0) {\n\t\t\t\tunique.add(normalized);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(unique);\n\t}\n\n\t/**\n\t * R6: the active profile's situational soul, wrapped so the model reads it as its identity for this\n\t * situation. Empty when no active profile defines a soul.\n\t */\n\tprivate _buildSituationSoulPrompt(): string | undefined {\n\t\tconst soul = this.deps.getSettingsManager().getActiveProfileSoul();\n\t\tif (!soul) return undefined;\n\t\treturn `<situation_soul>\\n${soul}\\n</situation_soul>`;\n\t}\n\n\tprivate _buildSelfModificationPrompt(): string | undefined {\n\t\tconst settings = this.deps.getSettingsManager().getSelfModificationSettings();\n\t\tif (!settings.enabled) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Resolve from an ordered candidate list first (portable WSL/Termux switching\n\t\t// from settings alone), then fall back to the legacy single sourcePath.\n\t\tconst rawCandidates = [\n\t\t\t...(Array.isArray(settings.sourcePaths) ? settings.sourcePaths : []),\n\t\t\t...(settings.sourcePath ? [settings.sourcePath] : []),\n\t\t]\n\t\t\t.map((candidate) => candidate?.trim())\n\t\t\t.filter((candidate): candidate is string => Boolean(candidate));\n\n\t\tif (rawCandidates.length === 0) {\n\t\t\treturn `Pi self-modification guardrails (local setting active, source missing):\n- Self-modification is enabled, but no \\`selfModification.sourcePaths\\`/\\`selfModification.sourcePath\\` value is set.\n- Do not modify Pi core or runtime output. Ask the user to set \\`selfModification.sourcePaths\\` to the pi-adaptative source checkout before proceeding.`;\n\t\t}\n\n\t\tconst resolvedCandidates = rawCandidates.map((candidate) =>\n\t\t\tresolvePath(candidate, this.deps.getCwd(), { trim: true }),\n\t\t);\n\t\tconst sourcePath =\n\t\t\tresolvedCandidates.find(\n\t\t\t\t(candidate) => existsSync(candidate) && existsSync(resolvePath(\"package.json\", candidate)),\n\t\t\t) ?? resolvedCandidates[0];\n\t\tconst sourceLooksValid = existsSync(sourcePath) && existsSync(resolvePath(\"package.json\", sourcePath));\n\t\tconst sourceStatus = sourceLooksValid\n\t\t\t? sourcePath\n\t\t\t: `${sourcePath} (missing or not a source checkout; ask the user to correct \\`selfModification.sourcePaths\\` before editing)`;\n\t\tconst autonomy = this.deps.getSettingsManager().getAutonomySettings();\n\t\tconst settingsGate =\n\t\t\tautonomy.mode === \"full\"\n\t\t\t\t? \"In autonomy.mode=full, autonomy/autoLearn setting tuning is covered by the standing autonomy grant; ask before changing credentials, provider auth, package sources, or unrelated preferences.\"\n\t\t\t\t: \"Ask for explicit approval before changing global settings.\";\n\t\treturn `Pi self-modification guardrails (local setting active):\n- Authorized pi-adaptative source path: ${sourceStatus}\n- Only modify Pi core/harness source under the authorized source path; never patch installed node_modules or generated runtime output as the source of truth.\n- Before changing Pi itself, restate the objective and scope, inspect relevant source/docs/examples, and make the smallest auditable change.\n- Preserve user changes: check git status before and after, avoid unrelated edits, and do not overwrite concurrent work.\n- Validate with focused tests and broader checks proportional to risk before claiming success.\n- Reload/restart/renew only after source changes are saved and auditable.\n- ${settingsGate}\n- Always ask for explicit approval before publishing, pushing, tagging, or releasing.`;\n\t}\n\n\tprivate _buildAutonomyPrompt(): string | undefined {\n\t\tconst autoLearn = this.deps.getSettingsManager().getAutoLearnSettings();\n\t\tconst autonomy = this.deps.getSettingsManager().getAutonomySettings();\n\t\tif (!autoLearn.enabled && autonomy.mode !== \"full\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst reflection = autoLearn.reflectionReview ?? autonomy.mode !== \"off\";\n\t\tconst model = autoLearn.model?.trim() || \"active\";\n\t\tif (autonomy.mode === \"full\") {\n\t\t\treturn `Pi autonomy policy (mode full, standing autonomy):\n- Setting-authorized background learners may run after long sessions or corrective/complex turns using model ${model}; they may act without asking first inside this standing grant.\n- Standing grant: write high-confidence durable memory, create/patch user/project skills, create/patch small user/project extensions/tools, tune autonomy/autoLearn settings, edit the authorized selfModification.sourcePath, run validation, and leave audit/rollback evidence.\n- Hard stops still require explicit foreground approval: publish/npm release, git push, tag creation, credential/provider-auth changes, destructive user-data deletion, network-exposed services, or expanding authority beyond this policy.\n- Treat current-turn evidence as a cue, not proof; prefer deterministic or longitudinal corroboration for durable behavior changes.\n- Active-task work remains primary: autonomy runs must not interrupt user-visible execution or claim task completion without evidence.`;\n\t\t}\n\t\treturn `Pi autonomy policy (mode ${autonomy.mode}):\n- Setting-authorized background learners may run after long sessions${reflection ? \" or corrective/complex turns\" : \"\"} using model ${model}.\n- Background learning may query durable memory and run bounded learning tools.\n- Auto-apply is limited to high-confidence durable memory when explicitly configured; tooling, skill, prompt, extension, settings, and core-source changes stay proposal/approval-gated.\n- Treat current-turn evidence as a cue, not proof; prefer longitudinal corroboration before changing durable behavior.\n- Active-task work remains primary: learning runs must not interrupt user-visible execution or claim task completion.`;\n\t}\n\n\tprivate _buildSystemPromptOptionsForToolNames(toolNames: string[]): BuildSystemPromptOptions {\n\t\tconst validToolNames = toolNames.filter((name) => this.deps.hasTool(name));\n\t\tconst toolSnippets: Record<string, string> = {};\n\t\tconst promptGuidelines: string[] = [];\n\t\tfor (const name of validToolNames) {\n\t\t\tconst snippet = this.deps.getToolPromptSnippet(name);\n\t\t\tif (snippet) {\n\t\t\t\ttoolSnippets[name] = snippet;\n\t\t\t}\n\n\t\t\tconst toolGuidelines = this.deps.getToolPromptGuidelines(name);\n\t\t\tif (toolGuidelines) {\n\t\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t\t}\n\t\t}\n\n\t\tconst loaderSystemPrompt = this.deps.getResourceLoader().getSystemPrompt();\n\t\tconst loaderAppendSystemPrompt = this.deps.getResourceLoader().getAppendSystemPrompt();\n\t\tconst appendSystemPromptParts = [\n\t\t\t// R6: situational soul — the active profile's identity prefix, switched atomically with the\n\t\t\t// profile's capabilities/model. Most prominent, so it comes first.\n\t\t\tthis._buildSituationSoulPrompt(),\n\t\t\t// Always-on untrusted-content boundary contract (gives the <untrusted_content> fences meaning).\n\t\t\tUNTRUSTED_BOUNDARY_SYSTEM_RULE,\n\t\t\tthis._buildSelfModificationPrompt(),\n\t\t\tthis._buildAutonomyPrompt(),\n\t\t\t// Memory subsystem: static, frozen-per-session block (e.g. file-store MEMORY.md/USER.md).\n\t\t\tthis.deps.getMemoryManager().buildSystemPromptBlock() || undefined,\n\t\t\t...loaderAppendSystemPrompt,\n\t\t].filter((part): part is string => Boolean(part));\n\t\tconst appendSystemPrompt = appendSystemPromptParts.length > 0 ? appendSystemPromptParts.join(\"\\n\\n\") : undefined;\n\t\t// Only surface skills the active profile permits — the agent must not be told about (or able\n\t\t// to invoke) a skill its profile blocks.\n\t\tconst loadedSkills = this.deps.getResourceLoader().getActiveSkills();\n\t\tconst loadedContextFiles = this.deps.getResourceLoader().getAgentsFiles().agentsFiles;\n\n\t\treturn {\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tskills: loadedSkills,\n\t\t\tcontextFiles: loadedContextFiles,\n\t\t\tcustomPrompt: loaderSystemPrompt,\n\t\t\tappendSystemPrompt,\n\t\t\tselectedTools: validToolNames,\n\t\t\ttoolSnippets,\n\t\t\tpromptGuidelines,\n\t\t\textensions: [...this.deps.getActiveExtensions()],\n\t\t};\n\t}\n\n\trebuildSystemPrompt(toolNames: string[]): string {\n\t\tthis._baseSystemPromptOptions = this._buildSystemPromptOptionsForToolNames(toolNames);\n\t\treturn buildSystemPrompt(this._baseSystemPromptOptions);\n\t}\n\n\t/**\n\t * Build a system prompt for a specific tool surface WITHOUT touching the session's base prompt\n\t * state. Used for a router-swapped turn (G4): the routed model runs against a filtered tool set,\n\t * so it must also receive a system prompt whose tool guidelines/snippets match that filtered\n\t * surface — but the change is per-turn, so it must not mutate `_baseSystemPromptOptions` (which\n\t * later turns and extension events read).\n\t */\n\tbuildSystemPromptForToolNames(toolNames: string[]): string {\n\t\treturn buildSystemPrompt(this._buildSystemPromptOptionsForToolNames(toolNames));\n\t}\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tool-call gate: model-router escalation, autonomy gating, extension tool hooks, and the
|
|
3
|
+
* untrusted-content output boundary.
|
|
4
|
+
*
|
|
5
|
+
* Extracted verbatim from agent-session.ts (god-file decomposition). Provides the two agent-core
|
|
6
|
+
* hooks (`beforeToolCall`/`afterToolCall`) as bound arrow-field members the session installs onto its
|
|
7
|
+
* agent. `beforeToolCall` runs the router escalation, then the autonomy tool gate (recording the
|
|
8
|
+
* outcome when a capability envelope is active), then extension `tool_call` handlers. `afterToolCall`
|
|
9
|
+
* runs extension `tool_result` handlers and structurally fences output from untrusted-content sources.
|
|
10
|
+
*/
|
|
11
|
+
import type { Agent } from "@caupulican/pi-agent-core";
|
|
12
|
+
import type { CapabilityEnvelope, GateOutcome } from "./autonomy/contracts.ts";
|
|
13
|
+
import type { ExtensionRunner } from "./extensions/index.ts";
|
|
14
|
+
type BeforeToolCall = NonNullable<Agent["beforeToolCall"]>;
|
|
15
|
+
type AfterToolCall = NonNullable<Agent["afterToolCall"]>;
|
|
16
|
+
export interface ToolGateControllerDeps {
|
|
17
|
+
/** Router escalation: block a tool the active cheap route is not allowed to run. */
|
|
18
|
+
maybeEscalateToolCall(toolName: string, args: unknown): {
|
|
19
|
+
block: true;
|
|
20
|
+
reason: string;
|
|
21
|
+
} | undefined;
|
|
22
|
+
getCwd(): string;
|
|
23
|
+
/** Active foreground capability envelope, if any — presence enables gate-outcome recording. */
|
|
24
|
+
getCapabilityEnvelope(): CapabilityEnvelope | undefined;
|
|
25
|
+
/** Record an autonomy gate outcome (only when a capability envelope is active). */
|
|
26
|
+
recordGateOutcome(outcome: GateOutcome): void;
|
|
27
|
+
getExtensionRunner(): ExtensionRunner;
|
|
28
|
+
}
|
|
29
|
+
export declare class ToolGateController {
|
|
30
|
+
private readonly deps;
|
|
31
|
+
constructor(deps: ToolGateControllerDeps);
|
|
32
|
+
readonly beforeToolCall: BeforeToolCall;
|
|
33
|
+
readonly afterToolCall: AfterToolCall;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=tool-gate-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-gate-controller.d.ts","sourceRoot":"","sources":["../../src/core/tool-gate-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,KAAK,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAC3D,KAAK,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACtC,oFAAoF;IACpF,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACpG,MAAM,IAAI,MAAM,CAAC;IACjB,iGAA+F;IAC/F,qBAAqB,IAAI,kBAAkB,GAAG,SAAS,CAAC;IACxD,mFAAmF;IACnF,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9C,kBAAkB,IAAI,eAAe,CAAC;CACtC;AAED,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAE9C,YAAY,IAAI,EAAE,sBAAsB,EAEvC;IAED,QAAQ,CAAC,cAAc,EAAE,cAAc,CA4CrC;IAEF,QAAQ,CAAC,aAAa,EAAE,aAAa,CAsCnC;CACF","sourcesContent":["/**\n * Agent tool-call gate: model-router escalation, autonomy gating, extension tool hooks, and the\n * untrusted-content output boundary.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Provides the two agent-core\n * hooks (`beforeToolCall`/`afterToolCall`) as bound arrow-field members the session installs onto its\n * agent. `beforeToolCall` runs the router escalation, then the autonomy tool gate (recording the\n * outcome when a capability envelope is active), then extension `tool_call` handlers. `afterToolCall`\n * runs extension `tool_result` handlers and structurally fences output from untrusted-content sources.\n */\n\nimport type { Agent } from \"@caupulican/pi-agent-core\";\nimport type { CapabilityEnvelope, GateOutcome } from \"./autonomy/contracts.ts\";\nimport { evaluateToolGate } from \"./autonomy/gates.ts\";\nimport type { ExtensionRunner } from \"./extensions/index.ts\";\nimport { classifyToolTrust, wrapUntrustedText } from \"./security/untrusted-boundary.ts\";\n\ntype BeforeToolCall = NonNullable<Agent[\"beforeToolCall\"]>;\ntype AfterToolCall = NonNullable<Agent[\"afterToolCall\"]>;\n\nexport interface ToolGateControllerDeps {\n\t/** Router escalation: block a tool the active cheap route is not allowed to run. */\n\tmaybeEscalateToolCall(toolName: string, args: unknown): { block: true; reason: string } | undefined;\n\tgetCwd(): string;\n\t/** Active foreground capability envelope, if any — presence enables gate-outcome recording. */\n\tgetCapabilityEnvelope(): CapabilityEnvelope | undefined;\n\t/** Record an autonomy gate outcome (only when a capability envelope is active). */\n\trecordGateOutcome(outcome: GateOutcome): void;\n\tgetExtensionRunner(): ExtensionRunner;\n}\n\nexport class ToolGateController {\n\tprivate readonly deps: ToolGateControllerDeps;\n\n\tconstructor(deps: ToolGateControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\treadonly beforeToolCall: BeforeToolCall = async ({ toolCall, args }) => {\n\t\tconst escalation = this.deps.maybeEscalateToolCall(toolCall.name, args);\n\t\tif (escalation) {\n\t\t\treturn escalation;\n\t\t}\n\n\t\t// Autonomy tool gating\n\t\tconst envelope = this.deps.getCapabilityEnvelope();\n\t\tconst gateResult = evaluateToolGate({\n\t\t\ttoolName: toolCall.name,\n\t\t\targs,\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tenvelope,\n\t\t});\n\n\t\tif (envelope) {\n\t\t\tthis.deps.recordGateOutcome(gateResult);\n\t\t}\n\n\t\tif (gateResult.outcome === \"block\" || gateResult.outcome === \"ask-user\") {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: `Tool execution blocked by autonomy gate [${gateResult.gate}]: ${gateResult.message} (${gateResult.reasonCode})`,\n\t\t\t};\n\t\t}\n\n\t\tconst runner = this.deps.getExtensionRunner();\n\t\tif (!runner.hasHandlers(\"tool_call\")) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\ttry {\n\t\t\treturn await runner.emitToolCall({\n\t\t\t\ttype: \"tool_call\",\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tthrow new Error(`Extension failed, blocking execution: ${String(err)}`);\n\t\t}\n\t};\n\n\treadonly afterToolCall: AfterToolCall = async ({ toolCall, args, result, isError }) => {\n\t\tconst runner = this.deps.getExtensionRunner();\n\t\tlet content = result.content;\n\t\tlet details = result.details;\n\t\tlet resolvedIsError = isError;\n\n\t\tif (runner.hasHandlers(\"tool_result\")) {\n\t\t\tconst hookResult = await runner.emitToolResult({\n\t\t\t\ttype: \"tool_result\",\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\tinput: args as Record<string, unknown>,\n\t\t\t\tcontent,\n\t\t\t\tdetails,\n\t\t\t\tisError,\n\t\t\t});\n\t\t\tif (hookResult) {\n\t\t\t\tcontent = hookResult.content ?? content;\n\t\t\t\tdetails = hookResult.details;\n\t\t\t\tresolvedIsError = hookResult.isError ?? isError;\n\t\t\t}\n\t\t}\n\n\t\t// Untrusted-content boundary: structurally fence output from attacker-controllable sources\n\t\t// (web/search, subagents, recall, third-party tools) so injection payloads are framed as data.\n\t\t// First-party tools (read/grep/find/ls/edit/write/bash) are trusted and pass through unchanged.\n\t\tif (classifyToolTrust(toolCall.name) === \"untrusted\") {\n\t\t\tconst source = `tool:${toolCall.name}`;\n\t\t\tconst wrapped = content.map((block) =>\n\t\t\t\tblock.type === \"text\" ? { ...block, text: wrapUntrustedText(block.text, source) } : block,\n\t\t\t);\n\t\t\tcontent = wrapped;\n\t\t}\n\n\t\tif (content === result.content && details === result.details && resolvedIsError === isError) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn { content, details, isError: resolvedIsError };\n\t};\n}\n"]}
|