pulseed 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/state/state-manager-goal-state.d.ts +40 -0
- package/dist/base/state/state-manager-goal-state.d.ts.map +1 -0
- package/dist/base/state/state-manager-goal-state.js +235 -0
- package/dist/base/state/state-manager-goal-state.js.map +1 -0
- package/dist/base/state/state-manager.d.ts +0 -5
- package/dist/base/state/state-manager.d.ts.map +1 -1
- package/dist/base/state/state-manager.js +27 -273
- package/dist/base/state/state-manager.js.map +1 -1
- package/dist/base/types/goal-activation.d.ts +25 -0
- package/dist/base/types/goal-activation.d.ts.map +1 -0
- package/dist/base/types/goal-activation.js +9 -0
- package/dist/base/types/goal-activation.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interface/chat/chat-event-state.d.ts +10 -0
- package/dist/interface/chat/chat-event-state.d.ts.map +1 -1
- package/dist/interface/chat/chat-event-state.js +184 -9
- package/dist/interface/chat/chat-event-state.js.map +1 -1
- package/dist/interface/chat/chat-events.d.ts +3 -1
- package/dist/interface/chat/chat-events.d.ts.map +1 -1
- package/dist/interface/chat/chat-history.d.ts +129 -0
- package/dist/interface/chat/chat-history.d.ts.map +1 -1
- package/dist/interface/chat/chat-history.js +135 -0
- package/dist/interface/chat/chat-history.js.map +1 -1
- package/dist/interface/chat/chat-runner-command-helpers.d.ts +50 -0
- package/dist/interface/chat/chat-runner-command-helpers.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-command-helpers.js +189 -0
- package/dist/interface/chat/chat-runner-command-helpers.js.map +1 -0
- package/dist/interface/chat/chat-runner-commands.d.ts +76 -0
- package/dist/interface/chat/chat-runner-commands.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-commands.js +814 -0
- package/dist/interface/chat/chat-runner-commands.js.map +1 -0
- package/dist/interface/chat/chat-runner-event-bridge.d.ts +53 -0
- package/dist/interface/chat/chat-runner-event-bridge.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-event-bridge.js +311 -0
- package/dist/interface/chat/chat-runner-event-bridge.js.map +1 -0
- package/dist/interface/chat/chat-runner-routes.d.ts +67 -0
- package/dist/interface/chat/chat-runner-routes.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-routes.js +594 -0
- package/dist/interface/chat/chat-runner-routes.js.map +1 -0
- package/dist/interface/chat/chat-runner-runtime.d.ts +37 -0
- package/dist/interface/chat/chat-runner-runtime.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-runtime.js +236 -0
- package/dist/interface/chat/chat-runner-runtime.js.map +1 -0
- package/dist/interface/chat/chat-runner-state.d.ts +20 -0
- package/dist/interface/chat/chat-runner-state.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-state.js +157 -0
- package/dist/interface/chat/chat-runner-state.js.map +1 -0
- package/dist/interface/chat/chat-runner-support.d.ts +15 -0
- package/dist/interface/chat/chat-runner-support.d.ts.map +1 -0
- package/dist/interface/chat/chat-runner-support.js +116 -0
- package/dist/interface/chat/chat-runner-support.js.map +1 -0
- package/dist/interface/chat/chat-runner.d.ts +13 -133
- package/dist/interface/chat/chat-runner.d.ts.map +1 -1
- package/dist/interface/chat/chat-runner.js +242 -1974
- package/dist/interface/chat/chat-runner.js.map +1 -1
- package/dist/interface/chat/chat-session-store.d.ts +32 -0
- package/dist/interface/chat/chat-session-store.d.ts.map +1 -1
- package/dist/interface/chat/chat-session-store.js +100 -10
- package/dist/interface/chat/chat-session-store.js.map +1 -1
- package/dist/interface/chat/chat-verifier.d.ts +3 -1
- package/dist/interface/chat/chat-verifier.d.ts.map +1 -1
- package/dist/interface/chat/chat-verifier.js +2 -2
- package/dist/interface/chat/chat-verifier.js.map +1 -1
- package/dist/interface/chat/cross-platform-session.d.ts +1 -0
- package/dist/interface/chat/cross-platform-session.d.ts.map +1 -1
- package/dist/interface/chat/cross-platform-session.js +23 -2
- package/dist/interface/chat/cross-platform-session.js.map +1 -1
- package/dist/interface/chat/event-subscriber.d.ts.map +1 -1
- package/dist/interface/chat/event-subscriber.js +41 -0
- package/dist/interface/chat/event-subscriber.js.map +1 -1
- package/dist/interface/chat/failure-recovery.d.ts +11 -0
- package/dist/interface/chat/failure-recovery.d.ts.map +1 -0
- package/dist/interface/chat/failure-recovery.js +115 -0
- package/dist/interface/chat/failure-recovery.js.map +1 -0
- package/dist/interface/chat/ingress-router.d.ts +0 -16
- package/dist/interface/chat/ingress-router.d.ts.map +1 -1
- package/dist/interface/chat/ingress-router.js +12 -51
- package/dist/interface/chat/ingress-router.js.map +1 -1
- package/dist/interface/chat/tend-command.d.ts +8 -0
- package/dist/interface/chat/tend-command.d.ts.map +1 -1
- package/dist/interface/chat/tend-command.js +82 -4
- package/dist/interface/chat/tend-command.js.map +1 -1
- package/dist/interface/cli/cli-command-registry.d.ts.map +1 -1
- package/dist/interface/cli/cli-command-registry.js +4 -0
- package/dist/interface/cli/cli-command-registry.js.map +1 -1
- package/dist/interface/cli/commands/daemon-shared.d.ts +32 -0
- package/dist/interface/cli/commands/daemon-shared.d.ts.map +1 -0
- package/dist/interface/cli/commands/daemon-shared.js +120 -0
- package/dist/interface/cli/commands/daemon-shared.js.map +1 -0
- package/dist/interface/cli/commands/daemon.d.ts +2 -2
- package/dist/interface/cli/commands/daemon.d.ts.map +1 -1
- package/dist/interface/cli/commands/daemon.js +4 -120
- package/dist/interface/cli/commands/daemon.js.map +1 -1
- package/dist/interface/cli/commands/runtime.d.ts +3 -0
- package/dist/interface/cli/commands/runtime.d.ts.map +1 -0
- package/dist/interface/cli/commands/runtime.js +231 -0
- package/dist/interface/cli/commands/runtime.js.map +1 -0
- package/dist/interface/cli/commands/schedule/history.d.ts.map +1 -1
- package/dist/interface/cli/commands/schedule/history.js +5 -1
- package/dist/interface/cli/commands/schedule/history.js.map +1 -1
- package/dist/interface/cli/commands/schedule.js +34 -4
- package/dist/interface/cli/commands/schedule.js.map +1 -1
- package/dist/interface/cli/utils.d.ts.map +1 -1
- package/dist/interface/cli/utils.js +4 -0
- package/dist/interface/cli/utils.js.map +1 -1
- package/dist/interface/tui/app.d.ts.map +1 -1
- package/dist/interface/tui/app.js +35 -1
- package/dist/interface/tui/app.js.map +1 -1
- package/dist/interface/tui/chat/scroll.d.ts +3 -0
- package/dist/interface/tui/chat/scroll.d.ts.map +1 -1
- package/dist/interface/tui/chat/scroll.js +15 -0
- package/dist/interface/tui/chat/scroll.js.map +1 -1
- package/dist/interface/tui/chat/suggestions.d.ts.map +1 -1
- package/dist/interface/tui/chat/suggestions.js +118 -4
- package/dist/interface/tui/chat/suggestions.js.map +1 -1
- package/dist/interface/tui/chat/types.d.ts +1 -1
- package/dist/interface/tui/chat/types.d.ts.map +1 -1
- package/dist/interface/tui/chat/viewport.d.ts.map +1 -1
- package/dist/interface/tui/chat/viewport.js +8 -2
- package/dist/interface/tui/chat/viewport.js.map +1 -1
- package/dist/interface/tui/chat-surface.d.ts +2 -0
- package/dist/interface/tui/chat-surface.d.ts.map +1 -1
- package/dist/interface/tui/chat-surface.js +11 -0
- package/dist/interface/tui/chat-surface.js.map +1 -1
- package/dist/interface/tui/chat.d.ts.map +1 -1
- package/dist/interface/tui/chat.js +15 -7
- package/dist/interface/tui/chat.js.map +1 -1
- package/dist/interface/tui/clipboard.d.ts +6 -1
- package/dist/interface/tui/clipboard.d.ts.map +1 -1
- package/dist/interface/tui/clipboard.js +24 -5
- package/dist/interface/tui/clipboard.js.map +1 -1
- package/dist/interface/tui/entry-approval.d.ts +8 -0
- package/dist/interface/tui/entry-approval.d.ts.map +1 -0
- package/dist/interface/tui/entry-approval.js +59 -0
- package/dist/interface/tui/entry-approval.js.map +1 -0
- package/dist/interface/tui/entry-daemon.d.ts +12 -0
- package/dist/interface/tui/entry-daemon.d.ts.map +1 -0
- package/dist/interface/tui/entry-daemon.js +74 -0
- package/dist/interface/tui/entry-daemon.js.map +1 -0
- package/dist/interface/tui/entry-deps.d.ts +22 -0
- package/dist/interface/tui/entry-deps.d.ts.map +1 -0
- package/dist/interface/tui/entry-deps.js +409 -0
- package/dist/interface/tui/entry-deps.js.map +1 -0
- package/dist/interface/tui/entry.d.ts +2 -4
- package/dist/interface/tui/entry.d.ts.map +1 -1
- package/dist/interface/tui/entry.js +15 -550
- package/dist/interface/tui/entry.js.map +1 -1
- package/dist/interface/tui/flicker/MouseTracking.d.ts +1 -1
- package/dist/interface/tui/flicker/MouseTracking.d.ts.map +1 -1
- package/dist/interface/tui/flicker/MouseTracking.js +8 -4
- package/dist/interface/tui/flicker/MouseTracking.js.map +1 -1
- package/dist/interface/tui/fullscreen-chat-render.d.ts +127 -0
- package/dist/interface/tui/fullscreen-chat-render.d.ts.map +1 -0
- package/dist/interface/tui/fullscreen-chat-render.js +667 -0
- package/dist/interface/tui/fullscreen-chat-render.js.map +1 -0
- package/dist/interface/tui/fullscreen-chat.d.ts +1 -29
- package/dist/interface/tui/fullscreen-chat.d.ts.map +1 -1
- package/dist/interface/tui/fullscreen-chat.js +306 -411
- package/dist/interface/tui/fullscreen-chat.js.map +1 -1
- package/dist/interface/tui/help-overlay.d.ts.map +1 -1
- package/dist/interface/tui/help-overlay.js +1 -1
- package/dist/interface/tui/help-overlay.js.map +1 -1
- package/dist/interface/tui/intent-recognizer.js +2 -2
- package/dist/interface/tui/intent-recognizer.js.map +1 -1
- package/dist/interface/tui/markdown-renderer.d.ts.map +1 -1
- package/dist/interface/tui/markdown-renderer.js +40 -12
- package/dist/interface/tui/markdown-renderer.js.map +1 -1
- package/dist/interface/tui/test-entry.js +1 -1
- package/dist/interface/tui/test-entry.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.js +1 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.js +35 -13
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-dogfood-benchmark.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-dogfood-benchmark.js +7 -4
- package/dist/orchestrator/execution/agent-loop/agent-loop-dogfood-benchmark.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-router.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-router.js +2 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-router.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-runtime.d.ts +2 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-runtime.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-runtime.js +31 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-tool-runtime.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.js +42 -2
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.js +3 -1
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/core-loop-control-tools.d.ts +19 -0
- package/dist/orchestrator/execution/agent-loop/core-loop-control-tools.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/core-loop-control-tools.js +164 -14
- package/dist/orchestrator/execution/agent-loop/core-loop-control-tools.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/index.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/index.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/index.js +1 -0
- package/dist/orchestrator/execution/agent-loop/index.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/kaggle-training-benchmark.d.ts +34 -0
- package/dist/orchestrator/execution/agent-loop/kaggle-training-benchmark.d.ts.map +1 -0
- package/dist/orchestrator/execution/agent-loop/kaggle-training-benchmark.js +54 -0
- package/dist/orchestrator/execution/agent-loop/kaggle-training-benchmark.js.map +1 -0
- package/dist/orchestrator/execution/reflection-generator.d.ts +1 -0
- package/dist/orchestrator/execution/reflection-generator.d.ts.map +1 -1
- package/dist/orchestrator/execution/reflection-generator.js +10 -1
- package/dist/orchestrator/execution/reflection-generator.js.map +1 -1
- package/dist/orchestrator/execution/task/task-context-enricher.d.ts +2 -0
- package/dist/orchestrator/execution/task/task-context-enricher.d.ts.map +1 -1
- package/dist/orchestrator/execution/task/task-context-enricher.js +9 -4
- package/dist/orchestrator/execution/task/task-context-enricher.js.map +1 -1
- package/dist/orchestrator/execution/task/task-execution-helpers-internal.d.ts +5 -0
- package/dist/orchestrator/execution/task/task-execution-helpers-internal.d.ts.map +1 -0
- package/dist/orchestrator/execution/task/task-execution-helpers-internal.js +6 -0
- package/dist/orchestrator/execution/task/task-execution-helpers-internal.js.map +1 -0
- package/dist/orchestrator/execution/task/task-generation.d.ts.map +1 -1
- package/dist/orchestrator/execution/task/task-generation.js +8 -3
- package/dist/orchestrator/execution/task/task-generation.js.map +1 -1
- package/dist/orchestrator/execution/task/task-lifecycle-runner.d.ts +73 -0
- package/dist/orchestrator/execution/task/task-lifecycle-runner.d.ts.map +1 -0
- package/dist/orchestrator/execution/task/task-lifecycle-runner.js +184 -0
- package/dist/orchestrator/execution/task/task-lifecycle-runner.js.map +1 -0
- package/dist/orchestrator/execution/task/task-lifecycle.d.ts +7 -7
- package/dist/orchestrator/execution/task/task-lifecycle.d.ts.map +1 -1
- package/dist/orchestrator/execution/task/task-lifecycle.js +37 -181
- package/dist/orchestrator/execution/task/task-lifecycle.js.map +1 -1
- package/dist/orchestrator/execution/task/task-verifier-internal.d.ts +2 -0
- package/dist/orchestrator/execution/task/task-verifier-internal.d.ts.map +1 -0
- package/dist/orchestrator/execution/task/task-verifier-internal.js +2 -0
- package/dist/orchestrator/execution/task/task-verifier-internal.js.map +1 -0
- package/dist/orchestrator/goal/goal-negotiator.d.ts.map +1 -1
- package/dist/orchestrator/goal/goal-negotiator.js +23 -3
- package/dist/orchestrator/goal/goal-negotiator.js.map +1 -1
- package/dist/orchestrator/loop/core-loop/contracts.d.ts +1 -0
- package/dist/orchestrator/loop/core-loop/contracts.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop/contracts.js.map +1 -1
- package/dist/orchestrator/loop/core-loop/iteration-kernel-knowledge.d.ts +7 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-knowledge.d.ts.map +1 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-knowledge.js +43 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-knowledge.js.map +1 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-wait.d.ts +14 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-wait.d.ts.map +1 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-wait.js +41 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel-wait.js.map +1 -0
- package/dist/orchestrator/loop/core-loop/iteration-kernel.d.ts +3 -2
- package/dist/orchestrator/loop/core-loop/iteration-kernel.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop/iteration-kernel.js +16 -87
- package/dist/orchestrator/loop/core-loop/iteration-kernel.js.map +1 -1
- package/dist/orchestrator/loop/core-loop/phase-policy.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop/phase-policy.js +8 -5
- package/dist/orchestrator/loop/core-loop/phase-policy.js.map +1 -1
- package/dist/orchestrator/loop/core-loop/task-cycle-stall.d.ts +9 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-stall.d.ts.map +1 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-stall.js +297 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-stall.js.map +1 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-wait.d.ts +11 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-wait.d.ts.map +1 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-wait.js +176 -0
- package/dist/orchestrator/loop/core-loop/task-cycle-wait.js.map +1 -0
- package/dist/orchestrator/loop/core-loop/task-cycle.d.ts +3 -15
- package/dist/orchestrator/loop/core-loop/task-cycle.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop/task-cycle.js +10 -444
- package/dist/orchestrator/loop/core-loop/task-cycle.js.map +1 -1
- package/dist/orchestrator/loop/core-loop.d.ts +3 -0
- package/dist/orchestrator/loop/core-loop.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop.js +4 -0
- package/dist/orchestrator/loop/core-loop.js.map +1 -1
- package/dist/orchestrator/strategy/portfolio-manager.d.ts +3 -2
- package/dist/orchestrator/strategy/portfolio-manager.d.ts.map +1 -1
- package/dist/orchestrator/strategy/portfolio-manager.js +16 -11
- package/dist/orchestrator/strategy/portfolio-manager.js.map +1 -1
- package/dist/orchestrator/strategy/portfolio-rebalance.d.ts +1 -1
- package/dist/orchestrator/strategy/portfolio-rebalance.d.ts.map +1 -1
- package/dist/orchestrator/strategy/portfolio-rebalance.js +31 -9
- package/dist/orchestrator/strategy/portfolio-rebalance.js.map +1 -1
- package/dist/orchestrator/strategy/strategy-manager-base.d.ts +12 -2
- package/dist/orchestrator/strategy/strategy-manager-base.d.ts.map +1 -1
- package/dist/orchestrator/strategy/strategy-manager-base.js +23 -7
- package/dist/orchestrator/strategy/strategy-manager-base.js.map +1 -1
- package/dist/orchestrator/strategy/strategy-manager.d.ts +1 -11
- package/dist/orchestrator/strategy/strategy-manager.d.ts.map +1 -1
- package/dist/orchestrator/strategy/strategy-manager.js +78 -19
- package/dist/orchestrator/strategy/strategy-manager.js.map +1 -1
- package/dist/platform/code-search/candidate-normalizer.d.ts +3 -0
- package/dist/platform/code-search/candidate-normalizer.d.ts.map +1 -0
- package/dist/platform/code-search/candidate-normalizer.js +61 -0
- package/dist/platform/code-search/candidate-normalizer.js.map +1 -0
- package/dist/platform/code-search/candidate.d.ts +25 -0
- package/dist/platform/code-search/candidate.d.ts.map +1 -0
- package/dist/platform/code-search/candidate.js +61 -0
- package/dist/platform/code-search/candidate.js.map +1 -0
- package/dist/platform/code-search/contracts.d.ts +275 -0
- package/dist/platform/code-search/contracts.d.ts.map +1 -0
- package/dist/platform/code-search/contracts.js +22 -0
- package/dist/platform/code-search/contracts.js.map +1 -0
- package/dist/platform/code-search/eval/fixtures.d.ts +14 -0
- package/dist/platform/code-search/eval/fixtures.d.ts.map +1 -0
- package/dist/platform/code-search/eval/fixtures.js +24 -0
- package/dist/platform/code-search/eval/fixtures.js.map +1 -0
- package/dist/platform/code-search/eval/metrics.d.ts +10 -0
- package/dist/platform/code-search/eval/metrics.d.ts.map +1 -0
- package/dist/platform/code-search/eval/metrics.js +20 -0
- package/dist/platform/code-search/eval/metrics.js.map +1 -0
- package/dist/platform/code-search/eval/runner.d.ts +3 -0
- package/dist/platform/code-search/eval/runner.d.ts.map +1 -0
- package/dist/platform/code-search/eval/runner.js +13 -0
- package/dist/platform/code-search/eval/runner.js.map +1 -0
- package/dist/platform/code-search/fusion.d.ts +6 -0
- package/dist/platform/code-search/fusion.d.ts.map +1 -0
- package/dist/platform/code-search/fusion.js +12 -0
- package/dist/platform/code-search/fusion.js.map +1 -0
- package/dist/platform/code-search/generated-detector.d.ts +15 -0
- package/dist/platform/code-search/generated-detector.d.ts.map +1 -0
- package/dist/platform/code-search/generated-detector.js +42 -0
- package/dist/platform/code-search/generated-detector.js.map +1 -0
- package/dist/platform/code-search/indexes/call-graph.d.ts +3 -0
- package/dist/platform/code-search/indexes/call-graph.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/call-graph.js +13 -0
- package/dist/platform/code-search/indexes/call-graph.js.map +1 -0
- package/dist/platform/code-search/indexes/config-index.d.ts +3 -0
- package/dist/platform/code-search/indexes/config-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/config-index.js +7 -0
- package/dist/platform/code-search/indexes/config-index.js.map +1 -0
- package/dist/platform/code-search/indexes/file-index.d.ts +5 -0
- package/dist/platform/code-search/indexes/file-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/file-index.js +106 -0
- package/dist/platform/code-search/indexes/file-index.js.map +1 -0
- package/dist/platform/code-search/indexes/index-store.d.ts +6 -0
- package/dist/platform/code-search/indexes/index-store.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/index-store.js +14 -0
- package/dist/platform/code-search/indexes/index-store.js.map +1 -0
- package/dist/platform/code-search/indexes/indexer.d.ts +3 -0
- package/dist/platform/code-search/indexes/indexer.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/indexer.js +27 -0
- package/dist/platform/code-search/indexes/indexer.js.map +1 -0
- package/dist/platform/code-search/indexes/package-graph.d.ts +3 -0
- package/dist/platform/code-search/indexes/package-graph.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/package-graph.js +26 -0
- package/dist/platform/code-search/indexes/package-graph.js.map +1 -0
- package/dist/platform/code-search/indexes/repo-map-index.d.ts +3 -0
- package/dist/platform/code-search/indexes/repo-map-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/repo-map-index.js +26 -0
- package/dist/platform/code-search/indexes/repo-map-index.js.map +1 -0
- package/dist/platform/code-search/indexes/semantic-index.d.ts +3 -0
- package/dist/platform/code-search/indexes/semantic-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/semantic-index.js +4 -0
- package/dist/platform/code-search/indexes/semantic-index.js.map +1 -0
- package/dist/platform/code-search/indexes/symbol-index.d.ts +3 -0
- package/dist/platform/code-search/indexes/symbol-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/symbol-index.js +84 -0
- package/dist/platform/code-search/indexes/symbol-index.js.map +1 -0
- package/dist/platform/code-search/indexes/test-index.d.ts +3 -0
- package/dist/platform/code-search/indexes/test-index.d.ts.map +1 -0
- package/dist/platform/code-search/indexes/test-index.js +22 -0
- package/dist/platform/code-search/indexes/test-index.js.map +1 -0
- package/dist/platform/code-search/orchestrator.d.ts +9 -0
- package/dist/platform/code-search/orchestrator.d.ts.map +1 -0
- package/dist/platform/code-search/orchestrator.js +81 -0
- package/dist/platform/code-search/orchestrator.js.map +1 -0
- package/dist/platform/code-search/path-policy.d.ts +6 -0
- package/dist/platform/code-search/path-policy.d.ts.map +1 -0
- package/dist/platform/code-search/path-policy.js +60 -0
- package/dist/platform/code-search/path-policy.js.map +1 -0
- package/dist/platform/code-search/progressive-reader.d.ts +8 -0
- package/dist/platform/code-search/progressive-reader.d.ts.map +1 -0
- package/dist/platform/code-search/progressive-reader.js +173 -0
- package/dist/platform/code-search/progressive-reader.js.map +1 -0
- package/dist/platform/code-search/query-planner.d.ts +4 -0
- package/dist/platform/code-search/query-planner.d.ts.map +1 -0
- package/dist/platform/code-search/query-planner.js +107 -0
- package/dist/platform/code-search/query-planner.js.map +1 -0
- package/dist/platform/code-search/reranker.d.ts +4 -0
- package/dist/platform/code-search/reranker.d.ts.map +1 -0
- package/dist/platform/code-search/reranker.js +57 -0
- package/dist/platform/code-search/reranker.js.map +1 -0
- package/dist/platform/code-search/retrievers/callgraph-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/callgraph-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/callgraph-retriever.js +31 -0
- package/dist/platform/code-search/retrievers/callgraph-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/config-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/config-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/config-retriever.js +23 -0
- package/dist/platform/code-search/retrievers/config-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/lexical-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/lexical-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/lexical-retriever.js +49 -0
- package/dist/platform/code-search/retrievers/lexical-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/package-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/package-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/package-retriever.js +29 -0
- package/dist/platform/code-search/retrievers/package-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/repo-map-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/repo-map-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/repo-map-retriever.js +30 -0
- package/dist/platform/code-search/retrievers/repo-map-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/semantic-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/semantic-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/semantic-retriever.js +18 -0
- package/dist/platform/code-search/retrievers/semantic-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/stacktrace-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/stacktrace-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/stacktrace-retriever.js +30 -0
- package/dist/platform/code-search/retrievers/stacktrace-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/symbol-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/symbol-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/symbol-retriever.js +32 -0
- package/dist/platform/code-search/retrievers/symbol-retriever.js.map +1 -0
- package/dist/platform/code-search/retrievers/test-retriever.d.ts +6 -0
- package/dist/platform/code-search/retrievers/test-retriever.d.ts.map +1 -0
- package/dist/platform/code-search/retrievers/test-retriever.js +30 -0
- package/dist/platform/code-search/retrievers/test-retriever.js.map +1 -0
- package/dist/platform/code-search/session-store.d.ts +11 -0
- package/dist/platform/code-search/session-store.d.ts.map +1 -0
- package/dist/platform/code-search/session-store.js +41 -0
- package/dist/platform/code-search/session-store.js.map +1 -0
- package/dist/platform/code-search/trace.d.ts +9 -0
- package/dist/platform/code-search/trace.d.ts.map +1 -0
- package/dist/platform/code-search/trace.js +25 -0
- package/dist/platform/code-search/trace.js.map +1 -0
- package/dist/platform/code-search/verification-retrieval.d.ts +3 -0
- package/dist/platform/code-search/verification-retrieval.d.ts.map +1 -0
- package/dist/platform/code-search/verification-retrieval.js +33 -0
- package/dist/platform/code-search/verification-retrieval.js.map +1 -0
- package/dist/platform/dream/dream-consolidator/fs-metrics.d.ts +18 -0
- package/dist/platform/dream/dream-consolidator/fs-metrics.d.ts.map +1 -0
- package/dist/platform/dream/dream-consolidator/fs-metrics.js +130 -0
- package/dist/platform/dream/dream-consolidator/fs-metrics.js.map +1 -0
- package/dist/platform/dream/dream-consolidator.d.ts +4 -14
- package/dist/platform/dream/dream-consolidator.d.ts.map +1 -1
- package/dist/platform/dream/dream-consolidator.js +46 -166
- package/dist/platform/dream/dream-consolidator.js.map +1 -1
- package/dist/platform/dream/dream-soil-sync.d.ts +1 -0
- package/dist/platform/dream/dream-soil-sync.d.ts.map +1 -1
- package/dist/platform/dream/dream-soil-sync.js +8 -1
- package/dist/platform/dream/dream-soil-sync.js.map +1 -1
- package/dist/platform/dream/dream-types.d.ts +5 -0
- package/dist/platform/dream/dream-types.d.ts.map +1 -1
- package/dist/platform/dream/dream-types.js +1 -0
- package/dist/platform/dream/dream-types.js.map +1 -1
- package/dist/platform/dream/playbook-memory.d.ts +4 -4
- package/dist/platform/drive/stall-detector/analysis.d.ts +5 -0
- package/dist/platform/drive/stall-detector/analysis.d.ts.map +1 -0
- package/dist/platform/drive/stall-detector/analysis.js +55 -0
- package/dist/platform/drive/stall-detector/analysis.js.map +1 -0
- package/dist/platform/drive/stall-detector/repetitive.d.ts +3 -0
- package/dist/platform/drive/stall-detector/repetitive.d.ts.map +1 -0
- package/dist/platform/drive/stall-detector/repetitive.js +72 -0
- package/dist/platform/drive/stall-detector/repetitive.js.map +1 -0
- package/dist/platform/drive/stall-detector/thresholds.d.ts +10 -0
- package/dist/platform/drive/stall-detector/thresholds.d.ts.map +1 -0
- package/dist/platform/drive/stall-detector/thresholds.js +61 -0
- package/dist/platform/drive/stall-detector/thresholds.js.map +1 -0
- package/dist/platform/drive/stall-detector.d.ts +2 -20
- package/dist/platform/drive/stall-detector.d.ts.map +1 -1
- package/dist/platform/drive/stall-detector.js +9 -202
- package/dist/platform/drive/stall-detector.js.map +1 -1
- package/dist/platform/knowledge/knowledge-manager-agent-memory.d.ts +55 -0
- package/dist/platform/knowledge/knowledge-manager-agent-memory.d.ts.map +1 -0
- package/dist/platform/knowledge/knowledge-manager-agent-memory.js +232 -0
- package/dist/platform/knowledge/knowledge-manager-agent-memory.js.map +1 -0
- package/dist/platform/knowledge/knowledge-manager-internals.d.ts +10 -0
- package/dist/platform/knowledge/knowledge-manager-internals.d.ts.map +1 -0
- package/dist/platform/knowledge/knowledge-manager-internals.js +43 -0
- package/dist/platform/knowledge/knowledge-manager-internals.js.map +1 -0
- package/dist/platform/knowledge/knowledge-manager-store.d.ts +13 -0
- package/dist/platform/knowledge/knowledge-manager-store.d.ts.map +1 -0
- package/dist/platform/knowledge/knowledge-manager-store.js +67 -0
- package/dist/platform/knowledge/knowledge-manager-store.js.map +1 -0
- package/dist/platform/knowledge/knowledge-manager.d.ts +6 -2
- package/dist/platform/knowledge/knowledge-manager.d.ts.map +1 -1
- package/dist/platform/knowledge/knowledge-manager.js +43 -344
- package/dist/platform/knowledge/knowledge-manager.js.map +1 -1
- package/dist/platform/knowledge/memory/memory-lifecycle-storage.d.ts +4 -0
- package/dist/platform/knowledge/memory/memory-lifecycle-storage.d.ts.map +1 -0
- package/dist/platform/knowledge/memory/memory-lifecycle-storage.js +106 -0
- package/dist/platform/knowledge/memory/memory-lifecycle-storage.js.map +1 -0
- package/dist/platform/knowledge/memory/memory-lifecycle.d.ts.map +1 -1
- package/dist/platform/knowledge/memory/memory-lifecycle.js +6 -112
- package/dist/platform/knowledge/memory/memory-lifecycle.js.map +1 -1
- package/dist/platform/observation/capability-detector/prompts.d.ts +18 -0
- package/dist/platform/observation/capability-detector/prompts.d.ts.map +1 -0
- package/dist/platform/observation/capability-detector/prompts.js +80 -0
- package/dist/platform/observation/capability-detector/prompts.js.map +1 -0
- package/dist/platform/observation/capability-detector/recommendations.d.ts +5 -0
- package/dist/platform/observation/capability-detector/recommendations.d.ts.map +1 -0
- package/dist/platform/observation/capability-detector/recommendations.js +76 -0
- package/dist/platform/observation/capability-detector/recommendations.js.map +1 -0
- package/dist/platform/observation/capability-detector/types.d.ts +112 -0
- package/dist/platform/observation/capability-detector/types.d.ts.map +1 -0
- package/dist/platform/observation/capability-detector/types.js +75 -0
- package/dist/platform/observation/capability-detector/types.js.map +1 -0
- package/dist/platform/observation/capability-detector.d.ts +4 -9
- package/dist/platform/observation/capability-detector.d.ts.map +1 -1
- package/dist/platform/observation/capability-detector.js +12 -212
- package/dist/platform/observation/capability-detector.js.map +1 -1
- package/dist/platform/observation/context-provider/collector.d.ts +13 -0
- package/dist/platform/observation/context-provider/collector.d.ts.map +1 -0
- package/dist/platform/observation/context-provider/collector.js +259 -0
- package/dist/platform/observation/context-provider/collector.js.map +1 -0
- package/dist/platform/observation/context-provider/search-terms.d.ts +2 -0
- package/dist/platform/observation/context-provider/search-terms.d.ts.map +1 -0
- package/dist/platform/observation/context-provider/search-terms.js +24 -0
- package/dist/platform/observation/context-provider/search-terms.js.map +1 -0
- package/dist/platform/observation/context-provider/shared.d.ts +17 -0
- package/dist/platform/observation/context-provider/shared.d.ts.map +1 -0
- package/dist/platform/observation/context-provider/shared.js +87 -0
- package/dist/platform/observation/context-provider/shared.js.map +1 -0
- package/dist/platform/observation/context-provider.d.ts +3 -28
- package/dist/platform/observation/context-provider.d.ts.map +1 -1
- package/dist/platform/observation/context-provider.js +7 -358
- package/dist/platform/observation/context-provider.js.map +1 -1
- package/dist/platform/observation/workspace-context.d.ts.map +1 -1
- package/dist/platform/observation/workspace-context.js +27 -0
- package/dist/platform/observation/workspace-context.js.map +1 -1
- package/dist/platform/soil/compiled-memory-projections.d.ts +2 -0
- package/dist/platform/soil/compiled-memory-projections.d.ts.map +1 -1
- package/dist/platform/soil/compiled-memory-projections.js +59 -0
- package/dist/platform/soil/compiled-memory-projections.js.map +1 -1
- package/dist/platform/soil/contracts.d.ts +2 -2
- package/dist/platform/soil/retriever.d.ts +25 -0
- package/dist/platform/soil/retriever.d.ts.map +1 -1
- package/dist/platform/soil/retriever.js +94 -5
- package/dist/platform/soil/retriever.js.map +1 -1
- package/dist/platform/soil/sqlite-repository-helpers.d.ts +80 -0
- package/dist/platform/soil/sqlite-repository-helpers.d.ts.map +1 -0
- package/dist/platform/soil/sqlite-repository-helpers.js +143 -0
- package/dist/platform/soil/sqlite-repository-helpers.js.map +1 -0
- package/dist/platform/soil/sqlite-repository-search.d.ts +8 -0
- package/dist/platform/soil/sqlite-repository-search.d.ts.map +1 -0
- package/dist/platform/soil/sqlite-repository-search.js +367 -0
- package/dist/platform/soil/sqlite-repository-search.js.map +1 -0
- package/dist/platform/soil/sqlite-repository-storage.d.ts +8 -0
- package/dist/platform/soil/sqlite-repository-storage.d.ts.map +1 -0
- package/dist/platform/soil/sqlite-repository-storage.js +278 -0
- package/dist/platform/soil/sqlite-repository-storage.js.map +1 -0
- package/dist/platform/soil/sqlite-repository.d.ts +1 -4
- package/dist/platform/soil/sqlite-repository.d.ts.map +1 -1
- package/dist/platform/soil/sqlite-repository.js +26 -820
- package/dist/platform/soil/sqlite-repository.js.map +1 -1
- package/dist/runtime/daemon/client.d.ts +13 -1
- package/dist/runtime/daemon/client.d.ts.map +1 -1
- package/dist/runtime/daemon/client.js +2 -2
- package/dist/runtime/daemon/client.js.map +1 -1
- package/dist/runtime/daemon/index.d.ts +1 -1
- package/dist/runtime/daemon/index.d.ts.map +1 -1
- package/dist/runtime/daemon/index.js +1 -1
- package/dist/runtime/daemon/index.js.map +1 -1
- package/dist/runtime/daemon/maintenance.d.ts +2 -10
- package/dist/runtime/daemon/maintenance.d.ts.map +1 -1
- package/dist/runtime/daemon/maintenance.js +14 -45
- package/dist/runtime/daemon/maintenance.js.map +1 -1
- package/dist/runtime/daemon/runner-bootstrap.d.ts +25 -0
- package/dist/runtime/daemon/runner-bootstrap.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-bootstrap.js +77 -0
- package/dist/runtime/daemon/runner-bootstrap.js.map +1 -0
- package/dist/runtime/daemon/runner-commands.d.ts +14 -6
- package/dist/runtime/daemon/runner-commands.d.ts.map +1 -1
- package/dist/runtime/daemon/runner-commands.js +63 -17
- package/dist/runtime/daemon/runner-commands.js.map +1 -1
- package/dist/runtime/daemon/runner-goal-cycle.d.ts.map +1 -1
- package/dist/runtime/daemon/runner-goal-cycle.js +3 -5
- package/dist/runtime/daemon/runner-goal-cycle.js.map +1 -1
- package/dist/runtime/daemon/runner-resident-curiosity.d.ts +12 -0
- package/dist/runtime/daemon/runner-resident-curiosity.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-resident-curiosity.js +155 -0
- package/dist/runtime/daemon/runner-resident-curiosity.js.map +1 -0
- package/dist/runtime/daemon/runner-resident-dream.d.ts +20 -0
- package/dist/runtime/daemon/runner-resident-dream.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-resident-dream.js +148 -0
- package/dist/runtime/daemon/runner-resident-dream.js.map +1 -0
- package/dist/runtime/daemon/runner-resident-proactive.d.ts +4 -0
- package/dist/runtime/daemon/runner-resident-proactive.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-resident-proactive.js +113 -0
- package/dist/runtime/daemon/runner-resident-proactive.js.map +1 -0
- package/dist/runtime/daemon/runner-resident-shared.d.ts +40 -0
- package/dist/runtime/daemon/runner-resident-shared.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-resident-shared.js +101 -0
- package/dist/runtime/daemon/runner-resident-shared.js.map +1 -0
- package/dist/runtime/daemon/runner-resident.d.ts +4 -68
- package/dist/runtime/daemon/runner-resident.d.ts.map +1 -1
- package/dist/runtime/daemon/runner-resident.js +4 -506
- package/dist/runtime/daemon/runner-resident.js.map +1 -1
- package/dist/runtime/daemon/runner-runtime.d.ts +12 -0
- package/dist/runtime/daemon/runner-runtime.d.ts.map +1 -0
- package/dist/runtime/daemon/runner-runtime.js +43 -0
- package/dist/runtime/daemon/runner-runtime.js.map +1 -0
- package/dist/runtime/daemon/runner-startup.d.ts.map +1 -1
- package/dist/runtime/daemon/runner-startup.js +23 -3
- package/dist/runtime/daemon/runner-startup.js.map +1 -1
- package/dist/runtime/daemon/runner.d.ts +10 -23
- package/dist/runtime/daemon/runner.d.ts.map +1 -1
- package/dist/runtime/daemon/runner.js +29 -111
- package/dist/runtime/daemon/runner.js.map +1 -1
- package/dist/runtime/daemon/runtime-root.d.ts +5 -0
- package/dist/runtime/daemon/runtime-root.d.ts.map +1 -0
- package/dist/runtime/daemon/runtime-root.js +60 -0
- package/dist/runtime/daemon/runtime-root.js.map +1 -0
- package/dist/runtime/daemon/wait-deadline-resolver.d.ts +5 -2
- package/dist/runtime/daemon/wait-deadline-resolver.d.ts.map +1 -1
- package/dist/runtime/daemon/wait-deadline-resolver.js +55 -35
- package/dist/runtime/daemon/wait-deadline-resolver.js.map +1 -1
- package/dist/runtime/event/dispatcher.d.ts +0 -2
- package/dist/runtime/event/dispatcher.d.ts.map +1 -1
- package/dist/runtime/event/dispatcher.js +0 -4
- package/dist/runtime/event/dispatcher.js.map +1 -1
- package/dist/runtime/event/server-command-handler.d.ts.map +1 -1
- package/dist/runtime/event/server-command-handler.js +47 -3
- package/dist/runtime/event/server-command-handler.js.map +1 -1
- package/dist/runtime/executor/goal-worker.d.ts +3 -1
- package/dist/runtime/executor/goal-worker.d.ts.map +1 -1
- package/dist/runtime/executor/goal-worker.js +3 -1
- package/dist/runtime/executor/goal-worker.js.map +1 -1
- package/dist/runtime/executor/loop-supervisor.d.ts +27 -1
- package/dist/runtime/executor/loop-supervisor.d.ts.map +1 -1
- package/dist/runtime/executor/loop-supervisor.js +218 -13
- package/dist/runtime/executor/loop-supervisor.js.map +1 -1
- package/dist/runtime/gateway/telegram-gateway-adapter.d.ts.map +1 -1
- package/dist/runtime/gateway/telegram-gateway-adapter.js +2 -1
- package/dist/runtime/gateway/telegram-gateway-adapter.js.map +1 -1
- package/dist/runtime/schedule/engine-cron-reflection.d.ts +31 -0
- package/dist/runtime/schedule/engine-cron-reflection.d.ts.map +1 -0
- package/dist/runtime/schedule/engine-cron-reflection.js +229 -0
- package/dist/runtime/schedule/engine-cron-reflection.js.map +1 -0
- package/dist/runtime/schedule/engine-execution.d.ts +47 -0
- package/dist/runtime/schedule/engine-execution.d.ts.map +1 -0
- package/dist/runtime/schedule/engine-execution.js +424 -0
- package/dist/runtime/schedule/engine-execution.js.map +1 -0
- package/dist/runtime/schedule/engine-heartbeat.d.ts +5 -0
- package/dist/runtime/schedule/engine-heartbeat.d.ts.map +1 -0
- package/dist/runtime/schedule/engine-heartbeat.js +104 -0
- package/dist/runtime/schedule/engine-heartbeat.js.map +1 -0
- package/dist/runtime/schedule/engine-layers.d.ts +2 -0
- package/dist/runtime/schedule/engine-layers.d.ts.map +1 -1
- package/dist/runtime/schedule/engine-layers.js +12 -228
- package/dist/runtime/schedule/engine-layers.js.map +1 -1
- package/dist/runtime/schedule/engine-mutations.d.ts +37 -0
- package/dist/runtime/schedule/engine-mutations.d.ts.map +1 -0
- package/dist/runtime/schedule/engine-mutations.js +263 -0
- package/dist/runtime/schedule/engine-mutations.js.map +1 -0
- package/dist/runtime/schedule/engine.d.ts +11 -38
- package/dist/runtime/schedule/engine.d.ts.map +1 -1
- package/dist/runtime/schedule/engine.js +65 -810
- package/dist/runtime/schedule/engine.js.map +1 -1
- package/dist/runtime/schedule/history.d.ts +16 -0
- package/dist/runtime/schedule/history.d.ts.map +1 -1
- package/dist/runtime/schedule/history.js +8 -0
- package/dist/runtime/schedule/history.js.map +1 -1
- package/dist/runtime/schedule/index.d.ts +1 -0
- package/dist/runtime/schedule/index.d.ts.map +1 -1
- package/dist/runtime/schedule/index.js +1 -0
- package/dist/runtime/schedule/index.js.map +1 -1
- package/dist/runtime/schedule/legacy-cron-migration.d.ts +9 -0
- package/dist/runtime/schedule/legacy-cron-migration.d.ts.map +1 -0
- package/dist/runtime/schedule/legacy-cron-migration.js +89 -0
- package/dist/runtime/schedule/legacy-cron-migration.js.map +1 -0
- package/dist/runtime/schedule/wait-projection.d.ts +6 -0
- package/dist/runtime/schedule/wait-projection.d.ts.map +1 -0
- package/dist/runtime/schedule/wait-projection.js +102 -0
- package/dist/runtime/schedule/wait-projection.js.map +1 -0
- package/dist/runtime/session-registry/index.d.ts +3 -0
- package/dist/runtime/session-registry/index.d.ts.map +1 -0
- package/dist/runtime/session-registry/index.js +3 -0
- package/dist/runtime/session-registry/index.js.map +1 -0
- package/dist/runtime/session-registry/registry-helpers.d.ts +34 -0
- package/dist/runtime/session-registry/registry-helpers.d.ts.map +1 -0
- package/dist/runtime/session-registry/registry-helpers.js +241 -0
- package/dist/runtime/session-registry/registry-helpers.js.map +1 -0
- package/dist/runtime/session-registry/registry.d.ts +39 -0
- package/dist/runtime/session-registry/registry.d.ts.map +1 -0
- package/dist/runtime/session-registry/registry.js +532 -0
- package/dist/runtime/session-registry/registry.js.map +1 -0
- package/dist/runtime/session-registry/types.d.ts +985 -0
- package/dist/runtime/session-registry/types.d.ts.map +1 -0
- package/dist/runtime/session-registry/types.js +108 -0
- package/dist/runtime/session-registry/types.js.map +1 -0
- package/dist/runtime/store/background-run-store.d.ts +75 -0
- package/dist/runtime/store/background-run-store.d.ts.map +1 -0
- package/dist/runtime/store/background-run-store.js +157 -0
- package/dist/runtime/store/background-run-store.js.map +1 -0
- package/dist/runtime/store/index.d.ts +2 -0
- package/dist/runtime/store/index.d.ts.map +1 -1
- package/dist/runtime/store/index.js +1 -0
- package/dist/runtime/store/index.js.map +1 -1
- package/dist/runtime/store/runtime-operation-schemas.d.ts +12 -12
- package/dist/runtime/store/runtime-paths.d.ts +2 -0
- package/dist/runtime/store/runtime-paths.d.ts.map +1 -1
- package/dist/runtime/store/runtime-paths.js +6 -0
- package/dist/runtime/store/runtime-paths.js.map +1 -1
- package/dist/runtime/store/runtime-schemas.d.ts +2 -2
- package/dist/runtime/types/daemon.d.ts +13 -0
- package/dist/runtime/types/daemon.d.ts.map +1 -1
- package/dist/runtime/types/daemon.js +3 -0
- package/dist/runtime/types/daemon.js.map +1 -1
- package/dist/runtime/types/schedule.d.ts +65 -0
- package/dist/runtime/types/schedule.d.ts.map +1 -1
- package/dist/runtime/types/schedule.js +5 -0
- package/dist/runtime/types/schedule.js.map +1 -1
- package/dist/tools/builtin/exports.d.ts +5 -0
- package/dist/tools/builtin/exports.d.ts.map +1 -1
- package/dist/tools/builtin/exports.js +5 -0
- package/dist/tools/builtin/exports.js.map +1 -1
- package/dist/tools/builtin/factory.d.ts +2 -0
- package/dist/tools/builtin/factory.d.ts.map +1 -1
- package/dist/tools/builtin/factory.js +26 -1
- package/dist/tools/builtin/factory.js.map +1 -1
- package/dist/tools/fs/FileValidationTool/protected-path-policy.d.ts +1 -0
- package/dist/tools/fs/FileValidationTool/protected-path-policy.d.ts.map +1 -1
- package/dist/tools/fs/FileValidationTool/protected-path-policy.js +17 -4
- package/dist/tools/fs/FileValidationTool/protected-path-policy.js.map +1 -1
- package/dist/tools/fs/GlobTool/GlobTool.js +2 -2
- package/dist/tools/fs/GlobTool/GlobTool.js.map +1 -1
- package/dist/tools/fs/GrepTool/GrepTool.js +2 -2
- package/dist/tools/fs/GrepTool/GrepTool.js.map +1 -1
- package/dist/tools/fs/ListDirTool/ListDirTool.js +1 -1
- package/dist/tools/fs/ListDirTool/ListDirTool.js.map +1 -1
- package/dist/tools/fs/ReadTool/ReadTool.js +2 -2
- package/dist/tools/fs/ReadTool/ReadTool.js.map +1 -1
- package/dist/tools/kaggle/KaggleExperimentTools.d.ts +395 -0
- package/dist/tools/kaggle/KaggleExperimentTools.d.ts.map +1 -0
- package/dist/tools/kaggle/KaggleExperimentTools.js +923 -0
- package/dist/tools/kaggle/KaggleExperimentTools.js.map +1 -0
- package/dist/tools/kaggle/KaggleSubmissionTools.d.ts +241 -0
- package/dist/tools/kaggle/KaggleSubmissionTools.d.ts.map +1 -0
- package/dist/tools/kaggle/KaggleSubmissionTools.js +558 -0
- package/dist/tools/kaggle/KaggleSubmissionTools.js.map +1 -0
- package/dist/tools/kaggle/KaggleWorkspacePrepareTool.d.ts +105 -0
- package/dist/tools/kaggle/KaggleWorkspacePrepareTool.d.ts.map +1 -0
- package/dist/tools/kaggle/KaggleWorkspacePrepareTool.js +135 -0
- package/dist/tools/kaggle/KaggleWorkspacePrepareTool.js.map +1 -0
- package/dist/tools/kaggle/index.d.ts +6 -0
- package/dist/tools/kaggle/index.d.ts.map +1 -0
- package/dist/tools/kaggle/index.js +6 -0
- package/dist/tools/kaggle/index.js.map +1 -0
- package/dist/tools/kaggle/metrics.d.ts +89 -0
- package/dist/tools/kaggle/metrics.d.ts.map +1 -0
- package/dist/tools/kaggle/metrics.js +51 -0
- package/dist/tools/kaggle/metrics.js.map +1 -0
- package/dist/tools/kaggle/paths.d.ts +15 -0
- package/dist/tools/kaggle/paths.d.ts.map +1 -0
- package/dist/tools/kaggle/paths.js +142 -0
- package/dist/tools/kaggle/paths.js.map +1 -0
- package/dist/tools/network/GitHubCliTool/GitHubCliTool.d.ts +2 -2
- package/dist/tools/query/CodeReadContextTool/CodeReadContextTool.d.ts +801 -0
- package/dist/tools/query/CodeReadContextTool/CodeReadContextTool.d.ts.map +1 -0
- package/dist/tools/query/CodeReadContextTool/CodeReadContextTool.js +147 -0
- package/dist/tools/query/CodeReadContextTool/CodeReadContextTool.js.map +1 -0
- package/dist/tools/query/CodeReadContextTool/constants.d.ts +5 -0
- package/dist/tools/query/CodeReadContextTool/constants.d.ts.map +1 -0
- package/dist/tools/query/CodeReadContextTool/constants.js +5 -0
- package/dist/tools/query/CodeReadContextTool/constants.js.map +1 -0
- package/dist/tools/query/CodeReadContextTool/prompt.d.ts +2 -0
- package/dist/tools/query/CodeReadContextTool/prompt.d.ts.map +1 -0
- package/dist/tools/query/CodeReadContextTool/prompt.js +6 -0
- package/dist/tools/query/CodeReadContextTool/prompt.js.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/CodeSearchRepairTool.d.ts +125 -0
- package/dist/tools/query/CodeSearchRepairTool/CodeSearchRepairTool.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/CodeSearchRepairTool.js +118 -0
- package/dist/tools/query/CodeSearchRepairTool/CodeSearchRepairTool.js.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/constants.d.ts +5 -0
- package/dist/tools/query/CodeSearchRepairTool/constants.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/constants.js +5 -0
- package/dist/tools/query/CodeSearchRepairTool/constants.js.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/prompt.d.ts +2 -0
- package/dist/tools/query/CodeSearchRepairTool/prompt.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchRepairTool/prompt.js +5 -0
- package/dist/tools/query/CodeSearchRepairTool/prompt.js.map +1 -0
- package/dist/tools/query/CodeSearchTool/CodeSearchTool.d.ts +123 -0
- package/dist/tools/query/CodeSearchTool/CodeSearchTool.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchTool/CodeSearchTool.js +117 -0
- package/dist/tools/query/CodeSearchTool/CodeSearchTool.js.map +1 -0
- package/dist/tools/query/CodeSearchTool/constants.d.ts +5 -0
- package/dist/tools/query/CodeSearchTool/constants.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchTool/constants.js +5 -0
- package/dist/tools/query/CodeSearchTool/constants.js.map +1 -0
- package/dist/tools/query/CodeSearchTool/prompt.d.ts +2 -0
- package/dist/tools/query/CodeSearchTool/prompt.d.ts.map +1 -0
- package/dist/tools/query/CodeSearchTool/prompt.js +6 -0
- package/dist/tools/query/CodeSearchTool/prompt.js.map +1 -0
- package/dist/tools/query/SoilQueryTool/SoilQueryTool.d.ts.map +1 -1
- package/dist/tools/query/SoilQueryTool/SoilQueryTool.js +43 -9
- package/dist/tools/query/SoilQueryTool/SoilQueryTool.js.map +1 -1
- package/dist/tools/query/code-search-root.d.ts +8 -0
- package/dist/tools/query/code-search-root.d.ts.map +1 -0
- package/dist/tools/query/code-search-root.js +41 -0
- package/dist/tools/query/code-search-root.js.map +1 -0
- package/dist/tools/query/runtime-session-tools.d.ts +560 -0
- package/dist/tools/query/runtime-session-tools.d.ts.map +1 -0
- package/dist/tools/query/runtime-session-tools.js +1015 -0
- package/dist/tools/query/runtime-session-tools.js.map +1 -0
- package/dist/tools/runtime/LongRunningRuntimeTools.d.ts +821 -0
- package/dist/tools/runtime/LongRunningRuntimeTools.d.ts.map +1 -0
- package/dist/tools/runtime/LongRunningRuntimeTools.js +845 -0
- package/dist/tools/runtime/LongRunningRuntimeTools.js.map +1 -0
- package/dist/tools/system/ProcessSessionTool/ProcessSessionTool.d.ts +1 -0
- package/dist/tools/system/ProcessSessionTool/ProcessSessionTool.d.ts.map +1 -1
- package/dist/tools/system/ProcessSessionTool/ProcessSessionTool.js +11 -0
- package/dist/tools/system/ProcessSessionTool/ProcessSessionTool.js.map +1 -1
- package/dist/tools/system/ShellTool/ShellTool.d.ts.map +1 -1
- package/dist/tools/system/ShellTool/ShellTool.js +2 -1
- package/dist/tools/system/ShellTool/ShellTool.js.map +1 -1
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/package.json +2 -1
- package/dist/base/types/cron.d.ts +0 -2
- package/dist/base/types/cron.d.ts.map +0 -1
- package/dist/base/types/cron.js +0 -3
- package/dist/base/types/cron.js.map +0 -1
- package/dist/runtime/cron-scheduler.d.ts +0 -13
- package/dist/runtime/cron-scheduler.d.ts.map +0 -1
- package/dist/runtime/cron-scheduler.js +0 -90
- package/dist/runtime/cron-scheduler.js.map +0 -1
- package/dist/runtime/types/cron.d.ts +0 -59
- package/dist/runtime/types/cron.d.ts.map +0 -1
- package/dist/runtime/types/cron.js +0 -13
- package/dist/runtime/types/cron.js.map +0 -1
|
@@ -2,81 +2,36 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Central coordinator for 1-shot chat execution (Tier 1).
|
|
4
4
|
// Bypasses TaskLifecycle — calls adapter.execute() directly.
|
|
5
|
-
import { execFile } from "node:child_process";
|
|
6
|
-
import * as fsp from "node:fs/promises";
|
|
7
|
-
import * as path from "node:path";
|
|
8
5
|
import { getPulseedDirPath } from "../../base/utils/paths.js";
|
|
9
6
|
import { getSelfIdentityResponseForBaseDir } from "../../base/config/identity-loader.js";
|
|
10
|
-
import { loadProviderConfig } from "../../base/llm/provider-config.js";
|
|
11
|
-
import { TaskSchema } from "../../base/types/task.js";
|
|
12
7
|
import { ChatHistory } from "./chat-history.js";
|
|
13
8
|
import { ChatSessionCatalog, ChatSessionSelectorError, } from "./chat-session-store.js";
|
|
14
9
|
import { buildChatContext, resolveGitRoot } from "../../platform/observation/context-provider.js";
|
|
15
10
|
import { buildChatAgentLoopSystemPrompt, buildStaticSystemPrompt, createChatGroundingGateway } from "./grounding.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { buildStandaloneIngressMessage, createIngressRouter, } from "./ingress-router.js";
|
|
11
|
+
import { createIngressRouter, } from "./ingress-router.js";
|
|
12
|
+
import { classifyInterruptRedirect, collectGitDiffArtifact, previewActivityText } from "./chat-runner-support.js";
|
|
13
|
+
import { COMMAND_HELP, ChatRunnerCommandHandler, } from "./chat-runner-commands.js";
|
|
14
|
+
import { ChatRunnerEventBridge } from "./chat-runner-event-bridge.js";
|
|
15
|
+
import { buildRuntimeControlContextFromIngress, buildStandaloneIngressMessageFromContext, formatRoute, getRouteCapabilities, loadedSessionToChatSession, resolveChatResumeSelector, } from "./chat-runner-runtime.js";
|
|
16
|
+
import { executeAdapterRoute, executeAgentLoopRoute, executeRuntimeControlRoute, executeToolLoopRoute, resolveSessionExecutionPolicy, } from "./chat-runner-routes.js";
|
|
23
17
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
/exit Exit chat mode
|
|
40
|
-
|
|
41
|
-
Goals and tasks
|
|
42
|
-
/status [goal-id] Show active goal status, or one goal when an id is provided
|
|
43
|
-
/goals List goals
|
|
44
|
-
/tasks [goal-id] List tasks for a goal; uses the only active goal when unambiguous
|
|
45
|
-
/task <task-id> [goal-id]
|
|
46
|
-
Show one task; searches goals when no goal id is provided
|
|
47
|
-
/track Promote session to Tier 2 goal pursuit (not yet implemented)
|
|
48
|
-
/tend Generate a goal from chat history and start autonomous daemon execution
|
|
49
|
-
|
|
50
|
-
Configuration
|
|
51
|
-
/config Show provider configuration with secrets masked
|
|
52
|
-
/model Show the active provider/model/adapter
|
|
53
|
-
/permissions [args] Show or update session execution policy
|
|
54
|
-
/plugins List installed plugins when plugin metadata is available
|
|
55
|
-
/usage [scope] Show usage summary (session, goal <id>, daemon <goal-id>, schedule [7d|24h|2w])
|
|
56
|
-
|
|
57
|
-
Review and branching
|
|
58
|
-
/review Show current diff summary and verification context
|
|
59
|
-
/fork [title] Fork the current chat session into a new session
|
|
60
|
-
/undo Remove the latest chat turn from session history
|
|
61
|
-
|
|
62
|
-
Deferred
|
|
63
|
-
/retry is intentionally not supported yet.`;
|
|
64
|
-
// ─── Helpers ───
|
|
65
|
-
function checkGitChanges(cwd) {
|
|
66
|
-
return new Promise((resolve) => {
|
|
67
|
-
execFile("git", ["diff", "HEAD", "--stat"], { cwd, timeout: 5_000 }, (err, stdout, stderr) => {
|
|
68
|
-
resolve(err ? null : (stdout + stderr).trim());
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function previewActivityText(value, maxChars = ACTIVITY_PREVIEW_CHARS) {
|
|
73
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
74
|
-
return normalized.length > maxChars ? `${normalized.slice(0, maxChars)}...` : normalized;
|
|
75
|
-
}
|
|
76
|
-
function formatToolActivity(action, toolName, detail) {
|
|
77
|
-
const preview = detail ? previewActivityText(detail) : "";
|
|
78
|
-
return preview ? `${action} tool: ${toolName} - ${preview}` : `${action} tool: ${toolName}`;
|
|
18
|
+
function normalizePinnedReplyTarget(replyTarget) {
|
|
19
|
+
if (!replyTarget)
|
|
20
|
+
return null;
|
|
21
|
+
const channel = replyTarget.channel ?? replyTarget.surface;
|
|
22
|
+
if (!channel)
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
channel,
|
|
26
|
+
target_id: replyTarget.conversation_id ?? replyTarget.identity_key ?? replyTarget.response_channel ?? null,
|
|
27
|
+
thread_id: replyTarget.message_id ?? null,
|
|
28
|
+
metadata: {
|
|
29
|
+
...replyTarget,
|
|
30
|
+
...(replyTarget.metadata ?? {}),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
79
33
|
}
|
|
34
|
+
const standaloneIngressRouter = createIngressRouter();
|
|
80
35
|
function resolveSelfIdentityResponse(input, baseDir) {
|
|
81
36
|
const normalized = input.trim().toLowerCase().replace(/\s+/g, "");
|
|
82
37
|
if (!normalized)
|
|
@@ -91,43 +46,52 @@ function resolveSelfIdentityResponse(input, baseDir) {
|
|
|
91
46
|
return null;
|
|
92
47
|
return getSelfIdentityResponseForBaseDir(baseDir, isEnglishIdentityQuestion ? "en" : "ja");
|
|
93
48
|
}
|
|
94
|
-
// ─── ChatRunner ───
|
|
95
49
|
export class ChatRunner {
|
|
96
50
|
deps;
|
|
97
51
|
groundingGateway;
|
|
52
|
+
eventBridge;
|
|
53
|
+
commandHandler;
|
|
98
54
|
history = null;
|
|
99
55
|
sessionCwd = null;
|
|
100
|
-
/** True when startSession() has been called — enables session persistence across execute() calls. */
|
|
101
56
|
sessionActive = false;
|
|
102
|
-
/** Deferred tools activated by ToolSearch results — included in tool definitions for subsequent turns. */
|
|
103
57
|
activatedTools = new Set();
|
|
104
|
-
/** Cached static system prompt — reused across turns; dynamic context is rebuilt each turn. */
|
|
105
58
|
cachedStaticSystemPrompt = null;
|
|
106
|
-
/** Pending /tend state awaiting user confirmation (Y/n). */
|
|
107
59
|
pendingTend = null;
|
|
108
|
-
/** Active EventSubscriber instances keyed by goalId. */
|
|
109
60
|
activeSubscribers = new Map();
|
|
110
|
-
/**
|
|
111
|
-
* Callback invoked when a /tend daemon notification arrives.
|
|
112
|
-
* Can be set after construction (e.g. from a React component via useEffect).
|
|
113
|
-
*/
|
|
114
61
|
onNotification = undefined;
|
|
115
62
|
onEvent = undefined;
|
|
116
63
|
nativeAgentLoopStatePath = null;
|
|
117
64
|
runtimeControlContext = null;
|
|
118
65
|
sessionExecutionPolicy = null;
|
|
66
|
+
lastSelectedRoute = null;
|
|
119
67
|
constructor(deps) {
|
|
120
68
|
this.deps = deps;
|
|
121
69
|
this.groundingGateway = createChatGroundingGateway({
|
|
122
70
|
stateManager: deps.stateManager,
|
|
123
71
|
pluginLoader: deps.pluginLoader,
|
|
124
72
|
});
|
|
73
|
+
this.eventBridge = new ChatRunnerEventBridge(() => this.onEvent ?? this.deps.onEvent);
|
|
74
|
+
this.commandHandler = new ChatRunnerCommandHandler({
|
|
75
|
+
deps: this.deps,
|
|
76
|
+
onNotification: this.onNotification,
|
|
77
|
+
getHistory: () => this.history,
|
|
78
|
+
setHistory: (history) => { this.history = history; },
|
|
79
|
+
getSessionCwd: () => this.sessionCwd,
|
|
80
|
+
setSessionCwd: (cwd) => { this.sessionCwd = cwd; },
|
|
81
|
+
setSessionActive: (active) => { this.sessionActive = active; },
|
|
82
|
+
getNativeAgentLoopStatePath: () => this.nativeAgentLoopStatePath,
|
|
83
|
+
setNativeAgentLoopStatePath: (path) => { this.nativeAgentLoopStatePath = path; },
|
|
84
|
+
getRuntimeControlContext: () => this.runtimeControlContext,
|
|
85
|
+
getPendingTend: () => this.pendingTend,
|
|
86
|
+
setPendingTend: (value) => { this.pendingTend = value; },
|
|
87
|
+
getLastSelectedRoute: () => this.lastSelectedRoute,
|
|
88
|
+
getSessionExecutionPolicy: () => this.getSessionExecutionPolicy(),
|
|
89
|
+
emitEvent: (event) => this.eventBridge.emitEvent(event),
|
|
90
|
+
getActiveSubscribers: () => this.activeSubscribers,
|
|
91
|
+
setSessionExecutionPolicy: (policy) => { this.sessionExecutionPolicy = policy; },
|
|
92
|
+
resetSessionExecutionPolicy: () => { this.sessionExecutionPolicy = null; },
|
|
93
|
+
});
|
|
125
94
|
}
|
|
126
|
-
/**
|
|
127
|
-
* Initialize a persistent session for interactive (multi-turn) mode.
|
|
128
|
-
* Must be called before the first execute() to share history across turns.
|
|
129
|
-
* If not called, execute() auto-creates a new session per call (Phase 1a behavior).
|
|
130
|
-
*/
|
|
131
95
|
startSession(cwd) {
|
|
132
96
|
const gitRoot = resolveGitRoot(cwd);
|
|
133
97
|
const sessionId = crypto.randomUUID();
|
|
@@ -135,13 +99,13 @@ export class ChatRunner {
|
|
|
135
99
|
this.sessionCwd = gitRoot;
|
|
136
100
|
this.sessionActive = true;
|
|
137
101
|
this.nativeAgentLoopStatePath = `chat/agentloop/${sessionId}.state.json`;
|
|
138
|
-
this.history.
|
|
102
|
+
this.history.resetAgentLoopState(this.nativeAgentLoopStatePath);
|
|
139
103
|
this.sessionExecutionPolicy = null;
|
|
140
104
|
}
|
|
141
105
|
startSessionFromLoadedSession(session) {
|
|
142
|
-
const chatSession =
|
|
106
|
+
const chatSession = loadedSessionToChatSession(session);
|
|
143
107
|
this.history = ChatHistory.fromSession(this.deps.stateManager, chatSession);
|
|
144
|
-
this.sessionCwd = session.cwd;
|
|
108
|
+
this.sessionCwd = resolveGitRoot(session.cwd);
|
|
145
109
|
this.sessionActive = true;
|
|
146
110
|
this.nativeAgentLoopStatePath = session.agentLoopStatePath ?? `chat/agentloop/${session.id}.state.json`;
|
|
147
111
|
this.history.setAgentLoopStatePath(this.nativeAgentLoopStatePath);
|
|
@@ -153,6 +117,65 @@ export class ChatRunner {
|
|
|
153
117
|
getCurrentSessionMessages() {
|
|
154
118
|
return this.history?.getMessages() ?? [];
|
|
155
119
|
}
|
|
120
|
+
hasActiveTurn() {
|
|
121
|
+
return this.eventBridge.hasActiveTurn();
|
|
122
|
+
}
|
|
123
|
+
async interruptAndRedirect(input, cwd, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
124
|
+
const activeTurn = this.eventBridge.getActiveTurn();
|
|
125
|
+
if (!activeTurn) {
|
|
126
|
+
return this.execute(input, cwd, timeoutMs);
|
|
127
|
+
}
|
|
128
|
+
const start = Date.now();
|
|
129
|
+
const redirect = classifyInterruptRedirect(input);
|
|
130
|
+
if (redirect === "background") {
|
|
131
|
+
return this.eventBridge.emitEphemeralAssistantResult(input, [
|
|
132
|
+
"Continuing this same turn in the background is not available yet.",
|
|
133
|
+
"",
|
|
134
|
+
"The active turn is still running in the foreground.",
|
|
135
|
+
"Use /tend for daemon-backed work, or send a narrower follow-up request.",
|
|
136
|
+
].join("\n"), true, start);
|
|
137
|
+
}
|
|
138
|
+
activeTurn.interruptRequested = true;
|
|
139
|
+
if (!activeTurn.abortController.signal.aborted) {
|
|
140
|
+
activeTurn.abortController.abort();
|
|
141
|
+
}
|
|
142
|
+
this.eventBridge.emitCheckpoint("Interrupt requested", `Redirect: ${previewActivityText(input, 120)}`, activeTurn.context, "interrupt");
|
|
143
|
+
const stopped = await this.eventBridge.waitForActiveTurn(activeTurn, 2_000);
|
|
144
|
+
if (!stopped) {
|
|
145
|
+
return this.eventBridge.emitEphemeralAssistantResult(input, "Interrupt requested. The active turn will stop at the next safe point.", false, start);
|
|
146
|
+
}
|
|
147
|
+
let output;
|
|
148
|
+
if (redirect === "diff") {
|
|
149
|
+
const diff = await collectGitDiffArtifact(activeTurn.cwd);
|
|
150
|
+
if (diff) {
|
|
151
|
+
const context = this.eventBridge.createEventContext();
|
|
152
|
+
this.eventBridge.emitDiffArtifact(diff, context);
|
|
153
|
+
output = "Interrupted the active turn. Current diff is shown above.";
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
output = "Interrupted the active turn. No working-tree changes were detected.";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else if (redirect === "review") {
|
|
160
|
+
const review = await this.commandHandler.handleCommand("/review", activeTurn.cwd);
|
|
161
|
+
output = `Interrupted the active turn and switched to review-only mode.\n\n${review?.output ?? "Review unavailable."}`;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
output = [
|
|
165
|
+
"Interrupted the active turn.",
|
|
166
|
+
"",
|
|
167
|
+
"Recent activity",
|
|
168
|
+
...(activeTurn.recentEvents.length > 0
|
|
169
|
+
? activeTurn.recentEvents.slice(-6).map((event) => `- ${event}`)
|
|
170
|
+
: ["- No activity was captured before the interrupt."]),
|
|
171
|
+
"",
|
|
172
|
+
"Next actions",
|
|
173
|
+
"- Ask for the exact continuation you want.",
|
|
174
|
+
"- Ask to show diff or switch to review if files may have changed.",
|
|
175
|
+
].join("\n");
|
|
176
|
+
}
|
|
177
|
+
return this.eventBridge.emitEphemeralAssistantResult(input, output, true, start);
|
|
178
|
+
}
|
|
156
179
|
setRuntimeControlContext(context) {
|
|
157
180
|
this.runtimeControlContext = context;
|
|
158
181
|
}
|
|
@@ -160,1142 +183,77 @@ export class ChatRunner {
|
|
|
160
183
|
if (!selectedRoute) {
|
|
161
184
|
throw new Error("executeIngressMessage requires selectedRoute; use CrossPlatformChatSessionManager for ingress route selection.");
|
|
162
185
|
}
|
|
163
|
-
const runtimeControlContext =
|
|
186
|
+
const runtimeControlContext = buildRuntimeControlContextFromIngress(ingress, this.runtimeControlContext, this.deps);
|
|
164
187
|
return this.execute(ingress.text, cwd, timeoutMs, {
|
|
165
188
|
selectedRoute,
|
|
166
189
|
runtimeControlContext,
|
|
167
190
|
goalId: ingress.goal_id,
|
|
168
191
|
});
|
|
169
192
|
}
|
|
170
|
-
resolveRouteFromIngress(ingress) {
|
|
171
|
-
return standaloneIngressRouter.selectRoute(ingress, this.getRouteCapabilities());
|
|
172
|
-
}
|
|
173
|
-
resolveRouteFromInput(input, runtimeControlContext) {
|
|
174
|
-
return this.resolveRouteFromIngress(this.buildStandaloneIngressMessage(input, runtimeControlContext));
|
|
175
|
-
}
|
|
176
|
-
getRouteCapabilities() {
|
|
177
|
-
return {
|
|
178
|
-
hasLightweightLlm: this.deps.llmClient !== undefined,
|
|
179
|
-
hasAgentLoop: this.deps.chatAgentLoopRunner !== undefined,
|
|
180
|
-
hasToolLoop: this.deps.llmClient !== undefined,
|
|
181
|
-
hasRuntimeControlService: this.deps.runtimeControlService !== undefined,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
buildStandaloneIngressMessage(input, runtimeControlContext) {
|
|
185
|
-
const channel = runtimeControlContext?.replyTarget?.surface === "tui"
|
|
186
|
-
? "tui"
|
|
187
|
-
: runtimeControlContext?.replyTarget?.surface === "cli"
|
|
188
|
-
? "cli"
|
|
189
|
-
: runtimeControlContext?.replyTarget?.surface === "gateway"
|
|
190
|
-
? "plugin_gateway"
|
|
191
|
-
: "cli";
|
|
192
|
-
const runtimeApprovalFn = runtimeControlContext?.approvalFn
|
|
193
|
-
?? this.deps.runtimeControlApprovalFn
|
|
194
|
-
?? this.deps.approvalFn;
|
|
195
|
-
const replyTarget = runtimeControlContext?.replyTarget ?? this.deps.runtimeReplyTarget;
|
|
196
|
-
const replyTargetInput = replyTarget
|
|
197
|
-
? {
|
|
198
|
-
...(replyTarget.surface ? { surface: replyTarget.surface } : {}),
|
|
199
|
-
channel,
|
|
200
|
-
...(replyTarget.platform ? { platform: replyTarget.platform } : {}),
|
|
201
|
-
...(replyTarget.conversation_id ? { conversation_id: replyTarget.conversation_id } : {}),
|
|
202
|
-
...(replyTarget.message_id ? { message_id: replyTarget.message_id } : {}),
|
|
203
|
-
...(replyTarget.response_channel ? { response_channel: replyTarget.response_channel } : {}),
|
|
204
|
-
...(replyTarget.outbox_topic ? { outbox_topic: replyTarget.outbox_topic } : {}),
|
|
205
|
-
...(replyTarget.identity_key ? { identity_key: replyTarget.identity_key } : {}),
|
|
206
|
-
...(replyTarget.user_id ? { user_id: replyTarget.user_id } : {}),
|
|
207
|
-
...(replyTarget.deliveryMode === "reply" || replyTarget.deliveryMode === "notify" || replyTarget.deliveryMode === "thread_reply"
|
|
208
|
-
? { deliveryMode: replyTarget.deliveryMode }
|
|
209
|
-
: {}),
|
|
210
|
-
...(replyTarget.metadata ? { metadata: replyTarget.metadata } : {}),
|
|
211
|
-
}
|
|
212
|
-
: undefined;
|
|
213
|
-
return buildStandaloneIngressMessage({
|
|
214
|
-
text: input,
|
|
215
|
-
channel,
|
|
216
|
-
platform: runtimeControlContext?.replyTarget?.platform ?? this.deps.runtimeReplyTarget?.platform,
|
|
217
|
-
identity_key: runtimeControlContext?.replyTarget?.identity_key ?? this.deps.runtimeReplyTarget?.identity_key,
|
|
218
|
-
conversation_id: runtimeControlContext?.replyTarget?.conversation_id ?? this.deps.runtimeReplyTarget?.conversation_id,
|
|
219
|
-
user_id: runtimeControlContext?.replyTarget?.user_id ?? this.deps.runtimeReplyTarget?.user_id,
|
|
220
|
-
actor: runtimeControlContext?.actor ?? this.deps.runtimeControlActor,
|
|
221
|
-
replyTarget: replyTargetInput,
|
|
222
|
-
runtimeControl: {
|
|
223
|
-
allowed: true,
|
|
224
|
-
approvalMode: "interactive",
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
buildRuntimeControlContextFromIngress(ingress) {
|
|
229
|
-
if (!ingress.actor && !ingress.replyTarget)
|
|
230
|
-
return null;
|
|
231
|
-
const interactiveApproval = this.runtimeControlContext?.approvalFn
|
|
232
|
-
?? this.deps.runtimeControlApprovalFn
|
|
233
|
-
?? this.deps.approvalFn;
|
|
234
|
-
return {
|
|
235
|
-
actor: ingress.actor,
|
|
236
|
-
replyTarget: ingress.replyTarget,
|
|
237
|
-
approvalFn: ingress.runtimeControl.approvalMode === "preapproved"
|
|
238
|
-
? async () => true
|
|
239
|
-
: ingress.runtimeControl.approvalMode === "interactive"
|
|
240
|
-
? interactiveApproval
|
|
241
|
-
: undefined,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
loadedSessionToChatSession(session) {
|
|
245
|
-
return {
|
|
246
|
-
id: session.id,
|
|
247
|
-
cwd: session.cwd,
|
|
248
|
-
createdAt: session.createdAt,
|
|
249
|
-
updatedAt: session.updatedAt,
|
|
250
|
-
messages: [...session.messages],
|
|
251
|
-
...(session.compactionSummary ? { compactionSummary: session.compactionSummary } : {}),
|
|
252
|
-
...(session.title ? { title: session.title } : {}),
|
|
253
|
-
...(session.agentLoopStatePath ? { agentLoopStatePath: session.agentLoopStatePath } : {}),
|
|
254
|
-
...(session.agentLoopStatus === "running" || session.agentLoopStatus === "completed" || session.agentLoopStatus === "failed"
|
|
255
|
-
? { agentLoopStatus: session.agentLoopStatus }
|
|
256
|
-
: {}),
|
|
257
|
-
...(session.agentLoopResumable ? { agentLoopResumable: true } : {}),
|
|
258
|
-
...(session.agentLoopUpdatedAt ? { agentLoopUpdatedAt: session.agentLoopUpdatedAt } : {}),
|
|
259
|
-
...(session.agentLoop ? { agentLoop: session.agentLoop } : {}),
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
formatSessionsList(entries) {
|
|
263
|
-
if (entries.length === 0)
|
|
264
|
-
return "No chat sessions found.";
|
|
265
|
-
const lines = entries.map((entry) => {
|
|
266
|
-
const title = entry.title ? ` "${entry.title}"` : "";
|
|
267
|
-
const resumable = entry.agentLoopResumable ? " resumable" : "";
|
|
268
|
-
return `${entry.id}${title} - ${entry.messageCount} message(s), updated ${entry.updatedAt}, cwd ${entry.cwd}${resumable}`;
|
|
269
|
-
});
|
|
270
|
-
return `Chat sessions:\n${lines.join("\n")}`;
|
|
271
|
-
}
|
|
272
|
-
formatHistory(session) {
|
|
273
|
-
const title = session.title ? ` "${session.title}"` : "";
|
|
274
|
-
if (session.messages.length === 0) {
|
|
275
|
-
return `Session ${session.id}${title} has no messages.`;
|
|
276
|
-
}
|
|
277
|
-
const lines = session.messages.map((message) => {
|
|
278
|
-
const role = message.role === "assistant" ? "Assistant" : "User";
|
|
279
|
-
return `${role}: ${message.content}`;
|
|
280
|
-
});
|
|
281
|
-
return `Session ${session.id}${title} (${session.cwd})\n${lines.join("\n")}`;
|
|
282
|
-
}
|
|
283
|
-
async loadGoals() {
|
|
284
|
-
const goalIds = await this.deps.stateManager.listGoalIds();
|
|
285
|
-
const goals = await Promise.all(goalIds.map((id) => this.deps.stateManager.loadGoal(id)));
|
|
286
|
-
return goals.filter((goal) => goal !== null);
|
|
287
|
-
}
|
|
288
|
-
async listAllGoalIds() {
|
|
289
|
-
const activeIds = await this.deps.stateManager.listGoalIds();
|
|
290
|
-
const archivedIds = await this.deps.stateManager.listArchivedGoals();
|
|
291
|
-
const recoverableArchivedIds = await this.listRecoverableArchivedGoalIds();
|
|
292
|
-
return [...new Set([...activeIds, ...archivedIds, ...recoverableArchivedIds])];
|
|
293
|
-
}
|
|
294
|
-
resolveStatePath(baseDir, ...segments) {
|
|
295
|
-
const base = path.resolve(baseDir);
|
|
296
|
-
const resolved = path.resolve(base, ...segments);
|
|
297
|
-
if (!resolved.startsWith(base + path.sep))
|
|
298
|
-
return null;
|
|
299
|
-
return resolved;
|
|
300
|
-
}
|
|
301
|
-
async listRecoverableArchivedGoalIds() {
|
|
302
|
-
const stateManager = this.deps.stateManager;
|
|
303
|
-
if (typeof stateManager.getBaseDir !== "function")
|
|
304
|
-
return [];
|
|
305
|
-
const archiveDir = this.resolveStatePath(stateManager.getBaseDir(), "archive");
|
|
306
|
-
if (archiveDir === null)
|
|
307
|
-
return [];
|
|
308
|
-
let entries = [];
|
|
309
|
-
try {
|
|
310
|
-
entries = await fsp.readdir(archiveDir, { withFileTypes: true });
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
return [];
|
|
314
|
-
}
|
|
315
|
-
const goalIds = [];
|
|
316
|
-
for (const entry of entries) {
|
|
317
|
-
if (!entry.isDirectory() || entry.name === ".staging")
|
|
318
|
-
continue;
|
|
319
|
-
try {
|
|
320
|
-
await fsp.access(path.join(archiveDir, entry.name, "goal", "goal.json"));
|
|
321
|
-
goalIds.push(entry.name);
|
|
322
|
-
}
|
|
323
|
-
catch {
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return goalIds;
|
|
328
|
-
}
|
|
329
|
-
activeGoals(goals) {
|
|
330
|
-
return goals.filter((goal) => goal.status === "active" || goal.status === "waiting" || goal.loop_status === "running");
|
|
331
|
-
}
|
|
332
|
-
formatGoalLine(goal) {
|
|
333
|
-
const dimensions = goal.dimensions.length === 0
|
|
334
|
-
? "no dimensions"
|
|
335
|
-
: goal.dimensions
|
|
336
|
-
.slice(0, 3)
|
|
337
|
-
.map((dimension) => `${dimension.name}: ${String(dimension.current_value)} target ${JSON.stringify(dimension.threshold)}`)
|
|
338
|
-
.join("; ");
|
|
339
|
-
return `${goal.id} - ${goal.title} [${goal.status}, loop ${goal.loop_status}] ${dimensions}`;
|
|
340
|
-
}
|
|
341
|
-
async handleStatus(args, start) {
|
|
342
|
-
if (args) {
|
|
343
|
-
const goal = await this.deps.stateManager.loadGoal(args);
|
|
344
|
-
if (!goal) {
|
|
345
|
-
return { success: false, output: `Goal not found: ${args}`, elapsed_ms: Date.now() - start };
|
|
346
|
-
}
|
|
347
|
-
const lines = [
|
|
348
|
-
`Goal status: ${goal.title}`,
|
|
349
|
-
`ID: ${goal.id}`,
|
|
350
|
-
`Status: ${goal.status}`,
|
|
351
|
-
`Loop: ${goal.loop_status}`,
|
|
352
|
-
`Updated: ${goal.updated_at}`,
|
|
353
|
-
`Children: ${goal.children_ids.length}`,
|
|
354
|
-
`Dimensions:`,
|
|
355
|
-
...goal.dimensions.map((dimension) => `- ${dimension.name}: current=${String(dimension.current_value)}, threshold=${JSON.stringify(dimension.threshold)}, confidence=${dimension.confidence}`),
|
|
356
|
-
];
|
|
357
|
-
return { success: true, output: lines.join("\n"), elapsed_ms: Date.now() - start };
|
|
358
|
-
}
|
|
359
|
-
const goals = await this.loadGoals();
|
|
360
|
-
const active = this.activeGoals(goals);
|
|
361
|
-
if (active.length === 0) {
|
|
362
|
-
return { success: true, output: "No active goals found.", elapsed_ms: Date.now() - start };
|
|
363
|
-
}
|
|
364
|
-
return {
|
|
365
|
-
success: true,
|
|
366
|
-
output: `Active goals:\n${active.map((goal) => this.formatGoalLine(goal)).join("\n")}`,
|
|
367
|
-
elapsed_ms: Date.now() - start,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
async handleGoals(start) {
|
|
371
|
-
const goals = await this.loadGoals();
|
|
372
|
-
if (goals.length === 0) {
|
|
373
|
-
return { success: true, output: "No goals found.", elapsed_ms: Date.now() - start };
|
|
374
|
-
}
|
|
375
|
-
return {
|
|
376
|
-
success: true,
|
|
377
|
-
output: `Goals:\n${goals.map((goal) => this.formatGoalLine(goal)).join("\n")}`,
|
|
378
|
-
elapsed_ms: Date.now() - start,
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
async readTasksFromDir(tasksDir) {
|
|
382
|
-
let entries = [];
|
|
383
|
-
try {
|
|
384
|
-
entries = await fsp.readdir(tasksDir);
|
|
385
|
-
}
|
|
386
|
-
catch {
|
|
387
|
-
return [];
|
|
388
|
-
}
|
|
389
|
-
const tasks = [];
|
|
390
|
-
for (const entry of entries) {
|
|
391
|
-
if (!entry.endsWith(".json") || entry === "task-history.json" || entry === "last-failure-context.json")
|
|
392
|
-
continue;
|
|
393
|
-
let raw;
|
|
394
|
-
try {
|
|
395
|
-
raw = JSON.parse(await fsp.readFile(path.join(tasksDir, entry), "utf-8"));
|
|
396
|
-
}
|
|
397
|
-
catch {
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
const parsed = TaskSchema.safeParse(raw);
|
|
401
|
-
if (parsed.success)
|
|
402
|
-
tasks.push(parsed.data);
|
|
403
|
-
}
|
|
404
|
-
return tasks.sort((a, b) => (a.created_at < b.created_at ? 1 : -1));
|
|
405
|
-
}
|
|
406
|
-
async readTasksForGoal(goalId) {
|
|
407
|
-
const stateManager = this.deps.stateManager;
|
|
408
|
-
if (typeof stateManager.getBaseDir !== "function")
|
|
409
|
-
return [];
|
|
410
|
-
const baseDir = stateManager.getBaseDir();
|
|
411
|
-
const activeTasksDir = this.resolveStatePath(baseDir, "tasks", goalId);
|
|
412
|
-
const archiveTasksDir = this.resolveStatePath(baseDir, "archive", goalId, "tasks");
|
|
413
|
-
if (activeTasksDir === null || archiveTasksDir === null)
|
|
414
|
-
return [];
|
|
415
|
-
const activeTasks = await this.readTasksFromDir(activeTasksDir);
|
|
416
|
-
if (activeTasks.length > 0)
|
|
417
|
-
return activeTasks;
|
|
418
|
-
return this.readTasksFromDir(archiveTasksDir);
|
|
419
|
-
}
|
|
420
|
-
async resolveGoalForTasks(selector) {
|
|
421
|
-
if (selector)
|
|
422
|
-
return { goalId: selector };
|
|
423
|
-
const active = this.activeGoals(await this.loadGoals());
|
|
424
|
-
if (active.length === 1)
|
|
425
|
-
return { goalId: active[0].id };
|
|
426
|
-
if (active.length === 0)
|
|
427
|
-
return { error: "No active goals found. Use /tasks <goal-id>." };
|
|
428
|
-
return { error: "Multiple active goals found. Use /tasks <goal-id>." };
|
|
429
|
-
}
|
|
430
|
-
formatTaskLine(task) {
|
|
431
|
-
const verdict = task.verification_verdict ? `, verdict ${task.verification_verdict}` : "";
|
|
432
|
-
return `${task.id} - ${task.status}${verdict}: ${task.work_description}`;
|
|
433
|
-
}
|
|
434
|
-
async handleTasks(args, start) {
|
|
435
|
-
const resolved = await this.resolveGoalForTasks(args);
|
|
436
|
-
if (resolved.error || !resolved.goalId) {
|
|
437
|
-
return { success: false, output: resolved.error ?? "Usage: /tasks <goal-id>", elapsed_ms: Date.now() - start };
|
|
438
|
-
}
|
|
439
|
-
const tasks = await this.readTasksForGoal(resolved.goalId);
|
|
440
|
-
if (tasks.length === 0) {
|
|
441
|
-
return { success: true, output: `No tasks found for goal "${resolved.goalId}".`, elapsed_ms: Date.now() - start };
|
|
442
|
-
}
|
|
443
|
-
return {
|
|
444
|
-
success: true,
|
|
445
|
-
output: `Tasks for goal ${resolved.goalId}:\n${tasks.map((task) => this.formatTaskLine(task)).join("\n")}`,
|
|
446
|
-
elapsed_ms: Date.now() - start,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
parseTaskArgs(args) {
|
|
450
|
-
const parts = args.split(/\s+/).filter(Boolean);
|
|
451
|
-
const goalFlagIndex = parts.indexOf("--goal");
|
|
452
|
-
if (goalFlagIndex >= 0) {
|
|
453
|
-
const goalId = parts[goalFlagIndex + 1];
|
|
454
|
-
parts.splice(goalFlagIndex, goalId ? 2 : 1);
|
|
455
|
-
return { taskId: parts[0], goalId };
|
|
456
|
-
}
|
|
457
|
-
return { taskId: parts[0], goalId: parts[1] };
|
|
458
|
-
}
|
|
459
|
-
async findTask(taskId, goalId) {
|
|
460
|
-
const goalIds = goalId ? [goalId] : await this.listAllGoalIds();
|
|
461
|
-
const matches = [];
|
|
462
|
-
for (const candidateGoalId of goalIds) {
|
|
463
|
-
let raw = null;
|
|
464
|
-
try {
|
|
465
|
-
raw = await this.deps.stateManager.readRaw(`tasks/${candidateGoalId}/${taskId}.json`);
|
|
466
|
-
}
|
|
467
|
-
catch {
|
|
468
|
-
raw = null;
|
|
469
|
-
}
|
|
470
|
-
if (!raw) {
|
|
471
|
-
const tasks = await this.readTasksForGoal(candidateGoalId);
|
|
472
|
-
const matched = tasks.find((task) => task.id === taskId || task.id.startsWith(taskId));
|
|
473
|
-
if (matched)
|
|
474
|
-
matches.push({ goalId: candidateGoalId, task: matched });
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
const parsed = TaskSchema.safeParse(raw);
|
|
478
|
-
if (parsed.success)
|
|
479
|
-
matches.push({ goalId: candidateGoalId, task: parsed.data });
|
|
480
|
-
}
|
|
481
|
-
return { task: matches.length === 1 ? matches[0].task : undefined, matches };
|
|
482
|
-
}
|
|
483
|
-
formatTask(task) {
|
|
484
|
-
const lines = [
|
|
485
|
-
`Task: ${task.id}`,
|
|
486
|
-
`Goal: ${task.goal_id}`,
|
|
487
|
-
`Status: ${task.status}`,
|
|
488
|
-
`Category: ${task.task_category}`,
|
|
489
|
-
`Created: ${task.created_at}`,
|
|
490
|
-
`Work: ${task.work_description}`,
|
|
491
|
-
`Approach: ${task.approach}`,
|
|
492
|
-
];
|
|
493
|
-
if (task.started_at)
|
|
494
|
-
lines.push(`Started: ${task.started_at}`);
|
|
495
|
-
if (task.completed_at)
|
|
496
|
-
lines.push(`Completed: ${task.completed_at}`);
|
|
497
|
-
if (task.verification_verdict)
|
|
498
|
-
lines.push(`Verification: ${task.verification_verdict}`);
|
|
499
|
-
if (task.verification_evidence?.length)
|
|
500
|
-
lines.push(`Evidence: ${task.verification_evidence.join("; ")}`);
|
|
501
|
-
if (task.success_criteria.length > 0) {
|
|
502
|
-
lines.push("Success criteria:");
|
|
503
|
-
lines.push(...task.success_criteria.map((criterion) => `- ${criterion.description}`));
|
|
504
|
-
}
|
|
505
|
-
return lines.join("\n");
|
|
506
|
-
}
|
|
507
|
-
async handleTask(args, start) {
|
|
508
|
-
const { taskId, goalId } = this.parseTaskArgs(args);
|
|
509
|
-
if (!taskId) {
|
|
510
|
-
return { success: false, output: "Usage: /task <task-id> [goal-id]", elapsed_ms: Date.now() - start };
|
|
511
|
-
}
|
|
512
|
-
const found = await this.findTask(taskId, goalId);
|
|
513
|
-
if (found.matches.length > 1) {
|
|
514
|
-
return {
|
|
515
|
-
success: false,
|
|
516
|
-
output: `Task selector "${taskId}" matched multiple goals. Use /task ${taskId} <goal-id>.\n${found.matches.map((match) => `- ${match.goalId}`).join("\n")}`,
|
|
517
|
-
elapsed_ms: Date.now() - start,
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
if (!found.task) {
|
|
521
|
-
const suffix = goalId ? ` for goal "${goalId}"` : "";
|
|
522
|
-
return { success: false, output: `Task not found: ${taskId}${suffix}`, elapsed_ms: Date.now() - start };
|
|
523
|
-
}
|
|
524
|
-
return { success: true, output: this.formatTask(found.task), elapsed_ms: Date.now() - start };
|
|
525
|
-
}
|
|
526
|
-
providerConfigBaseDir() {
|
|
527
|
-
const stateManager = this.deps.stateManager;
|
|
528
|
-
return typeof stateManager.getBaseDir === "function" ? stateManager.getBaseDir() : getPulseedDirPath();
|
|
529
|
-
}
|
|
530
|
-
async readProviderConfigSummary() {
|
|
531
|
-
const config = await loadProviderConfig({
|
|
532
|
-
baseDir: this.providerConfigBaseDir(),
|
|
533
|
-
saveMigration: false,
|
|
534
|
-
});
|
|
535
|
-
return {
|
|
536
|
-
provider: config.provider,
|
|
537
|
-
model: config.model,
|
|
538
|
-
adapter: config.adapter,
|
|
539
|
-
light_model: config.light_model,
|
|
540
|
-
base_url: config.base_url,
|
|
541
|
-
codex_cli_path: config.codex_cli_path,
|
|
542
|
-
has_api_key: Boolean(config.api_key),
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
formatConfig(config) {
|
|
546
|
-
return Object.entries(config)
|
|
547
|
-
.filter(([, value]) => value !== undefined)
|
|
548
|
-
.map(([key, value]) => `${key}: ${typeof value === "string" && /key|token|secret/i.test(key) ? "[masked]" : String(value)}`)
|
|
549
|
-
.join("\n");
|
|
550
|
-
}
|
|
551
|
-
async handleConfig(start) {
|
|
552
|
-
const config = await this.readProviderConfigSummary();
|
|
553
|
-
return { success: true, output: `Provider configuration:\n${this.formatConfig(config)}`, elapsed_ms: Date.now() - start };
|
|
554
|
-
}
|
|
555
|
-
async handleModel(start) {
|
|
556
|
-
const config = await this.readProviderConfigSummary();
|
|
557
|
-
return {
|
|
558
|
-
success: true,
|
|
559
|
-
output: `Model: ${config.model}\nProvider: ${config.provider}\nAdapter: ${config.adapter}`,
|
|
560
|
-
elapsed_ms: Date.now() - start,
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
async handlePlugins(start) {
|
|
564
|
-
if (!this.deps.pluginLoader) {
|
|
565
|
-
return { success: true, output: "Plugin information is not available in this chat session.", elapsed_ms: Date.now() - start };
|
|
566
|
-
}
|
|
567
|
-
try {
|
|
568
|
-
const plugins = await this.deps.pluginLoader.loadAll();
|
|
569
|
-
if (plugins.length === 0) {
|
|
570
|
-
return { success: true, output: "No plugins found.", elapsed_ms: Date.now() - start };
|
|
571
|
-
}
|
|
572
|
-
return {
|
|
573
|
-
success: true,
|
|
574
|
-
output: `Plugins:\n${plugins.map((plugin) => `${plugin.name} - ${plugin.type ?? "unknown"} - ${plugin.enabled === false ? "disabled" : "enabled"}`).join("\n")}`,
|
|
575
|
-
elapsed_ms: Date.now() - start,
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
catch (err) {
|
|
579
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
580
|
-
return { success: true, output: `Plugin information is unavailable: ${message}`, elapsed_ms: Date.now() - start };
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
zeroUsageCounter() {
|
|
584
|
-
return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
585
|
-
}
|
|
586
|
-
normalizeUsageCounter(usage) {
|
|
587
|
-
const inputTokens = Number.isFinite(usage.inputTokens) ? Math.max(0, Math.floor(usage.inputTokens)) : 0;
|
|
588
|
-
const outputTokens = Number.isFinite(usage.outputTokens) ? Math.max(0, Math.floor(usage.outputTokens)) : 0;
|
|
589
|
-
const totalTokens = Number.isFinite(usage.totalTokens)
|
|
590
|
-
? Math.max(0, Math.floor(usage.totalTokens))
|
|
591
|
-
: inputTokens + outputTokens;
|
|
592
|
-
return { inputTokens, outputTokens, totalTokens };
|
|
593
|
-
}
|
|
594
|
-
usageFromLLMResponse(response) {
|
|
595
|
-
const inputTokens = response.usage?.input_tokens ?? 0;
|
|
596
|
-
const outputTokens = response.usage?.output_tokens ?? 0;
|
|
597
|
-
return {
|
|
598
|
-
inputTokens,
|
|
599
|
-
outputTokens,
|
|
600
|
-
totalTokens: inputTokens + outputTokens,
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
addUsageCounter(target, delta) {
|
|
604
|
-
const normalizedDelta = this.normalizeUsageCounter(delta);
|
|
605
|
-
target.inputTokens += normalizedDelta.inputTokens;
|
|
606
|
-
target.outputTokens += normalizedDelta.outputTokens;
|
|
607
|
-
target.totalTokens += normalizedDelta.totalTokens;
|
|
608
|
-
}
|
|
609
|
-
hasUsage(usage) {
|
|
610
|
-
return usage.totalTokens > 0 || usage.inputTokens > 0 || usage.outputTokens > 0;
|
|
611
|
-
}
|
|
612
|
-
formatUsageCounter(prefix, usage) {
|
|
613
|
-
return [
|
|
614
|
-
`${prefix} input tokens: ${usage.inputTokens}`,
|
|
615
|
-
`${prefix} output tokens: ${usage.outputTokens}`,
|
|
616
|
-
`${prefix} total tokens: ${usage.totalTokens}`,
|
|
617
|
-
];
|
|
618
|
-
}
|
|
619
|
-
parseUsagePeriodMs(period) {
|
|
620
|
-
const match = /^(\d+)([dhw])$/i.exec(period.trim());
|
|
621
|
-
if (!match) {
|
|
622
|
-
throw new Error("period must be one of 24h, 7d, 2w");
|
|
623
|
-
}
|
|
624
|
-
const value = Number(match[1]);
|
|
625
|
-
const unit = match[2]?.toLowerCase();
|
|
626
|
-
if (!Number.isFinite(value) || value <= 0) {
|
|
627
|
-
throw new Error("period value must be positive");
|
|
628
|
-
}
|
|
629
|
-
if (unit === "h")
|
|
630
|
-
return value * 60 * 60 * 1000;
|
|
631
|
-
if (unit === "w")
|
|
632
|
-
return value * 7 * 24 * 60 * 60 * 1000;
|
|
633
|
-
return value * 24 * 60 * 60 * 1000;
|
|
634
|
-
}
|
|
635
|
-
async collectGoalUsage(goalId) {
|
|
636
|
-
const baseDir = this.deps.stateManager.getBaseDir();
|
|
637
|
-
const ledgerDir = path.join(baseDir, "tasks", goalId, "ledger");
|
|
638
|
-
let entries = [];
|
|
639
|
-
try {
|
|
640
|
-
entries = await fsp.readdir(ledgerDir);
|
|
641
|
-
}
|
|
642
|
-
catch (err) {
|
|
643
|
-
if (err.code !== "ENOENT")
|
|
644
|
-
throw err;
|
|
645
|
-
return { goalId, totalTokens: 0, taskCount: 0, terminalTaskCount: 0 };
|
|
646
|
-
}
|
|
647
|
-
let totalTokens = 0;
|
|
648
|
-
let taskCount = 0;
|
|
649
|
-
let terminalTaskCount = 0;
|
|
650
|
-
for (const entry of entries) {
|
|
651
|
-
if (!entry.endsWith(".json"))
|
|
652
|
-
continue;
|
|
653
|
-
taskCount += 1;
|
|
654
|
-
try {
|
|
655
|
-
const raw = await fsp.readFile(path.join(ledgerDir, entry), "utf-8");
|
|
656
|
-
const parsed = JSON.parse(raw);
|
|
657
|
-
if (typeof parsed.summary?.tokens_used === "number") {
|
|
658
|
-
totalTokens += parsed.summary.tokens_used;
|
|
659
|
-
}
|
|
660
|
-
if (parsed.summary?.latest_event_type === "succeeded"
|
|
661
|
-
|| parsed.summary?.latest_event_type === "failed"
|
|
662
|
-
|| parsed.summary?.latest_event_type === "abandoned") {
|
|
663
|
-
terminalTaskCount += 1;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
catch {
|
|
667
|
-
// Ignore malformed records.
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
return { goalId, totalTokens, taskCount, terminalTaskCount };
|
|
671
|
-
}
|
|
672
|
-
async collectScheduleUsage(period) {
|
|
673
|
-
const periodMs = this.parseUsagePeriodMs(period);
|
|
674
|
-
const since = Date.now() - periodMs;
|
|
675
|
-
const historyPath = path.join(this.deps.stateManager.getBaseDir(), "schedule-history.json");
|
|
676
|
-
let raw;
|
|
677
|
-
try {
|
|
678
|
-
raw = JSON.parse(await fsp.readFile(historyPath, "utf-8"));
|
|
679
|
-
}
|
|
680
|
-
catch (err) {
|
|
681
|
-
if (err.code === "ENOENT") {
|
|
682
|
-
return { period, runs: 0, totalTokens: 0 };
|
|
683
|
-
}
|
|
684
|
-
throw err;
|
|
685
|
-
}
|
|
686
|
-
if (!Array.isArray(raw)) {
|
|
687
|
-
return { period, runs: 0, totalTokens: 0 };
|
|
688
|
-
}
|
|
689
|
-
let runs = 0;
|
|
690
|
-
let totalTokens = 0;
|
|
691
|
-
for (const record of raw) {
|
|
692
|
-
if (!record || typeof record !== "object")
|
|
693
|
-
continue;
|
|
694
|
-
const finishedAt = record["finished_at"];
|
|
695
|
-
const firedAt = typeof finishedAt === "string" ? Date.parse(finishedAt) : Number.NaN;
|
|
696
|
-
if (!Number.isFinite(firedAt) || firedAt < since)
|
|
697
|
-
continue;
|
|
698
|
-
runs += 1;
|
|
699
|
-
const tokensUsed = record["tokens_used"];
|
|
700
|
-
if (typeof tokensUsed === "number" && Number.isFinite(tokensUsed)) {
|
|
701
|
-
totalTokens += tokensUsed;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
return { period, runs, totalTokens };
|
|
705
|
-
}
|
|
706
|
-
async handleUsage(args, start) {
|
|
707
|
-
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
708
|
-
const scope = tokens[0]?.toLowerCase();
|
|
709
|
-
if (!scope || scope === "session") {
|
|
710
|
-
if (!this.history) {
|
|
711
|
-
return { success: false, output: "No active chat session. Start a session and run work before /usage.", elapsed_ms: Date.now() - start };
|
|
712
|
-
}
|
|
713
|
-
const session = this.history.getSessionData();
|
|
714
|
-
const totals = this.normalizeUsageCounter(session.usage?.totals ?? this.zeroUsageCounter());
|
|
715
|
-
const lines = [
|
|
716
|
-
`Usage summary (session ${session.id})`,
|
|
717
|
-
...this.formatUsageCounter("Session", totals),
|
|
718
|
-
];
|
|
719
|
-
const phaseEntries = Object.entries(session.usage?.byPhase ?? {})
|
|
720
|
-
.map(([phase, usage]) => ({ phase, usage: this.normalizeUsageCounter(usage) }))
|
|
721
|
-
.filter((entry) => this.hasUsage(entry.usage))
|
|
722
|
-
.sort((left, right) => right.usage.totalTokens - left.usage.totalTokens);
|
|
723
|
-
if (phaseEntries.length > 0) {
|
|
724
|
-
lines.push("");
|
|
725
|
-
lines.push("By phase:");
|
|
726
|
-
for (const entry of phaseEntries) {
|
|
727
|
-
lines.push(`- ${entry.phase}: ${entry.usage.totalTokens} (in=${entry.usage.inputTokens}, out=${entry.usage.outputTokens})`);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
return { success: true, output: lines.join("\n"), elapsed_ms: Date.now() - start };
|
|
731
|
-
}
|
|
732
|
-
if (scope === "goal" || scope === "daemon") {
|
|
733
|
-
const goalId = tokens[1] ?? this.deps.goalId;
|
|
734
|
-
if (!goalId) {
|
|
735
|
-
return { success: false, output: "Usage: /usage goal <goal-id>", elapsed_ms: Date.now() - start };
|
|
736
|
-
}
|
|
737
|
-
const summary = await this.collectGoalUsage(goalId);
|
|
738
|
-
const lines = [
|
|
739
|
-
`Usage summary (${scope} scope)`,
|
|
740
|
-
`Goal: ${summary.goalId}`,
|
|
741
|
-
`Tasks observed: ${summary.taskCount}`,
|
|
742
|
-
`Terminal tasks: ${summary.terminalTaskCount}`,
|
|
743
|
-
`Total tokens: ${summary.totalTokens}`,
|
|
744
|
-
];
|
|
745
|
-
return { success: true, output: lines.join("\n"), elapsed_ms: Date.now() - start };
|
|
746
|
-
}
|
|
747
|
-
if (scope === "schedule") {
|
|
748
|
-
const period = tokens[1] ?? "7d";
|
|
749
|
-
try {
|
|
750
|
-
const summary = await this.collectScheduleUsage(period);
|
|
751
|
-
const lines = [
|
|
752
|
-
`Usage summary (schedule, ${summary.period})`,
|
|
753
|
-
`Runs: ${summary.runs}`,
|
|
754
|
-
`Total tokens: ${summary.totalTokens}`,
|
|
755
|
-
];
|
|
756
|
-
return { success: true, output: lines.join("\n"), elapsed_ms: Date.now() - start };
|
|
757
|
-
}
|
|
758
|
-
catch (err) {
|
|
759
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
760
|
-
return { success: false, output: `Usage: /usage schedule [24h|7d|2w]\nError: ${message}`, elapsed_ms: Date.now() - start };
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
return {
|
|
764
|
-
success: false,
|
|
765
|
-
output: "Usage: /usage [session|goal <goal-id>|daemon <goal-id>|schedule [24h|7d|2w]]",
|
|
766
|
-
elapsed_ms: Date.now() - start,
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
deterministicChatSummary(messages) {
|
|
770
|
-
const lines = messages.map((message) => `${message.role}: ${message.content.replace(/\s+/g, " ").trim()}`);
|
|
771
|
-
return lines.join("\n").slice(0, 4_000);
|
|
772
|
-
}
|
|
773
|
-
async summarizeChatForCompaction(messages, existingSummary) {
|
|
774
|
-
const content = [
|
|
775
|
-
existingSummary ? `Previous summary:\n${existingSummary}` : "",
|
|
776
|
-
`Messages to summarize:\n${messages.map((message) => `${message.role}: ${message.content}`).join("\n")}`,
|
|
777
|
-
].filter(Boolean).join("\n\n");
|
|
778
|
-
if (this.deps.llmClient) {
|
|
779
|
-
try {
|
|
780
|
-
const response = await this.deps.llmClient.sendMessage([
|
|
781
|
-
{ role: "user", content: `Summarize this chat history for later continuation. Preserve decisions, open tasks, constraints, and user preferences. Keep it concise.\n\n${content}` },
|
|
782
|
-
], { max_tokens: 700, model_tier: "light" });
|
|
783
|
-
if (response.content.trim())
|
|
784
|
-
return { summary: response.content.trim(), usedLlm: true };
|
|
785
|
-
}
|
|
786
|
-
catch {
|
|
787
|
-
// Fall back to deterministic summary below.
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
const fallback = [
|
|
791
|
-
existingSummary ? `Previous summary:\n${existingSummary}` : "",
|
|
792
|
-
"Extractive summary:",
|
|
793
|
-
this.deterministicChatSummary(messages),
|
|
794
|
-
].filter(Boolean).join("\n\n");
|
|
795
|
-
return { summary: fallback, usedLlm: false };
|
|
796
|
-
}
|
|
797
|
-
async handleCompact(start) {
|
|
798
|
-
if (!this.history) {
|
|
799
|
-
return { success: false, output: "No active chat session to compact.", elapsed_ms: Date.now() - start };
|
|
800
|
-
}
|
|
801
|
-
const session = this.history.getSessionData();
|
|
802
|
-
if (session.messages.length <= 4) {
|
|
803
|
-
return { success: true, output: "Chat history is already compact. No messages were removed.", elapsed_ms: Date.now() - start };
|
|
804
|
-
}
|
|
805
|
-
const olderMessages = session.messages.slice(0, -4);
|
|
806
|
-
const { summary, usedLlm } = await this.summarizeChatForCompaction(olderMessages, session.compactionSummary);
|
|
807
|
-
const { before, after } = await this.history.compact(summary, 4);
|
|
808
|
-
const method = usedLlm ? "LLM summary" : "deterministic summary";
|
|
809
|
-
return {
|
|
810
|
-
success: true,
|
|
811
|
-
output: `Compacted chat history with ${method}. Persisted ${before} message(s) down to ${after}; the latest user/assistant turns were kept.`,
|
|
812
|
-
elapsed_ms: Date.now() - start,
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
async handleCommand(input) {
|
|
816
|
-
const trimmed = input.trim();
|
|
817
|
-
if (!trimmed.startsWith("/"))
|
|
818
|
-
return null;
|
|
819
|
-
const cmd = trimmed.toLowerCase().split(/\s+/)[0];
|
|
820
|
-
const start = Date.now();
|
|
821
|
-
if (cmd === "/help") {
|
|
822
|
-
return { success: true, output: COMMAND_HELP, elapsed_ms: Date.now() - start };
|
|
823
|
-
}
|
|
824
|
-
if (cmd === "/clear") {
|
|
825
|
-
await this.history?.clear();
|
|
826
|
-
return { success: true, output: "Conversation history cleared.", elapsed_ms: Date.now() - start };
|
|
827
|
-
}
|
|
828
|
-
if (cmd === "/sessions") {
|
|
829
|
-
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
830
|
-
const sessions = await catalog.listSessions();
|
|
831
|
-
return { success: true, output: this.formatSessionsList(sessions), elapsed_ms: Date.now() - start };
|
|
832
|
-
}
|
|
833
|
-
if (cmd === "/history") {
|
|
834
|
-
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
835
|
-
const selector = trimmed.slice("/history".length).trim();
|
|
836
|
-
const session = selector
|
|
837
|
-
? await catalog.loadSessionBySelector(selector)
|
|
838
|
-
: this.history
|
|
839
|
-
? await catalog.loadSession(this.history.getSessionId())
|
|
840
|
-
: null;
|
|
841
|
-
if (!session) {
|
|
842
|
-
return { success: false, output: "No chat session history found.", elapsed_ms: Date.now() - start };
|
|
843
|
-
}
|
|
844
|
-
return { success: true, output: this.formatHistory(session), elapsed_ms: Date.now() - start };
|
|
845
|
-
}
|
|
846
|
-
if (cmd === "/title") {
|
|
847
|
-
const title = trimmed.slice("/title".length).trim();
|
|
848
|
-
if (!title) {
|
|
849
|
-
return { success: false, output: "Usage: /title <title>", elapsed_ms: Date.now() - start };
|
|
850
|
-
}
|
|
851
|
-
if (!this.history) {
|
|
852
|
-
return { success: false, output: "No active chat session to rename.", elapsed_ms: Date.now() - start };
|
|
853
|
-
}
|
|
854
|
-
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
855
|
-
this.history.setTitle(title);
|
|
856
|
-
await this.history.persist();
|
|
857
|
-
await catalog.renameSession(this.history.getSessionId(), title);
|
|
858
|
-
return { success: true, output: `Renamed chat session to "${title}".`, elapsed_ms: Date.now() - start };
|
|
859
|
-
}
|
|
860
|
-
if (cmd === "/cleanup") {
|
|
861
|
-
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
862
|
-
const dryRun = trimmed.includes("--dry-run");
|
|
863
|
-
const report = await catalog.cleanupSessions({
|
|
864
|
-
dryRun,
|
|
865
|
-
activeSessionId: this.history?.getSessionId(),
|
|
866
|
-
});
|
|
867
|
-
const verb = dryRun ? "would remove" : "removed";
|
|
868
|
-
return {
|
|
869
|
-
success: true,
|
|
870
|
-
output: `Chat session cleanup ${verb} ${report.removedSessionIds.length} session(s).`,
|
|
871
|
-
elapsed_ms: Date.now() - start,
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
|
-
if (cmd === "/compact") {
|
|
875
|
-
return this.handleCompact(start);
|
|
876
|
-
}
|
|
877
|
-
if (cmd === "/status") {
|
|
878
|
-
return this.handleStatus(trimmed.slice("/status".length).trim(), start);
|
|
879
|
-
}
|
|
880
|
-
if (cmd === "/goals") {
|
|
881
|
-
return this.handleGoals(start);
|
|
882
|
-
}
|
|
883
|
-
if (cmd === "/tasks") {
|
|
884
|
-
return this.handleTasks(trimmed.slice("/tasks".length).trim(), start);
|
|
885
|
-
}
|
|
886
|
-
if (cmd === "/task") {
|
|
887
|
-
return this.handleTask(trimmed.slice("/task".length).trim(), start);
|
|
888
|
-
}
|
|
889
|
-
if (cmd === "/config") {
|
|
890
|
-
return this.handleConfig(start);
|
|
891
|
-
}
|
|
892
|
-
if (cmd === "/model") {
|
|
893
|
-
return this.handleModel(start);
|
|
894
|
-
}
|
|
895
|
-
if (cmd === "/permissions") {
|
|
896
|
-
return this.handlePermissions(trimmed.slice("/permissions".length).trim(), start);
|
|
897
|
-
}
|
|
898
|
-
if (cmd === "/plugins") {
|
|
899
|
-
return this.handlePlugins(start);
|
|
900
|
-
}
|
|
901
|
-
if (cmd === "/usage") {
|
|
902
|
-
return this.handleUsage(trimmed.slice("/usage".length).trim(), start);
|
|
903
|
-
}
|
|
904
|
-
if (cmd === "/review") {
|
|
905
|
-
return this.handleReview(start);
|
|
906
|
-
}
|
|
907
|
-
if (cmd === "/fork") {
|
|
908
|
-
return this.handleFork(trimmed.slice("/fork".length).trim(), start);
|
|
909
|
-
}
|
|
910
|
-
if (cmd === "/undo") {
|
|
911
|
-
return this.handleUndo(start);
|
|
912
|
-
}
|
|
913
|
-
if (cmd === "/exit") {
|
|
914
|
-
return { success: true, output: "Exiting chat mode.", elapsed_ms: Date.now() - start };
|
|
915
|
-
}
|
|
916
|
-
if (cmd === "/track") {
|
|
917
|
-
return this.handleTrack(start);
|
|
918
|
-
}
|
|
919
|
-
if (cmd === "/tend") {
|
|
920
|
-
const args = trimmed.slice("/tend".length).trim();
|
|
921
|
-
return this.handleTend(args, start);
|
|
922
|
-
}
|
|
923
|
-
// Check if this is a confirmation response for a pending /tend
|
|
924
|
-
if (this.pendingTend !== null) {
|
|
925
|
-
return this.handleTendConfirmation(trimmed, start);
|
|
926
|
-
}
|
|
927
|
-
return {
|
|
928
|
-
success: false,
|
|
929
|
-
output: `Unknown command: ${input.trim()}. Type /help for available commands.`,
|
|
930
|
-
elapsed_ms: Date.now() - start,
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
async handleTrack(start) {
|
|
934
|
-
if (!this.deps.escalationHandler) {
|
|
935
|
-
return {
|
|
936
|
-
success: false,
|
|
937
|
-
output: "Escalation not available — missing LLM configuration",
|
|
938
|
-
elapsed_ms: Date.now() - start,
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
if (!this.history || this.history.getMessages().length === 0) {
|
|
942
|
-
return {
|
|
943
|
-
success: false,
|
|
944
|
-
output: "No conversation to escalate. Chat first, then /track.",
|
|
945
|
-
elapsed_ms: Date.now() - start,
|
|
946
|
-
};
|
|
947
|
-
}
|
|
948
|
-
try {
|
|
949
|
-
const result = await this.deps.escalationHandler.escalateToGoal(this.history);
|
|
950
|
-
return {
|
|
951
|
-
success: true,
|
|
952
|
-
output: `Goal created: ${result.title} (ID: ${result.goalId})\nRun: pulseed run --goal ${result.goalId} --yes`,
|
|
953
|
-
elapsed_ms: Date.now() - start,
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
catch (err) {
|
|
957
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
958
|
-
return {
|
|
959
|
-
success: false,
|
|
960
|
-
output: `Escalation failed: ${message}`,
|
|
961
|
-
elapsed_ms: Date.now() - start,
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
async handlePermissions(args, start) {
|
|
966
|
-
const policy = await this.getSessionExecutionPolicy();
|
|
967
|
-
if (!args) {
|
|
968
|
-
return {
|
|
969
|
-
success: true,
|
|
970
|
-
output: summarizeExecutionPolicy(policy),
|
|
971
|
-
elapsed_ms: Date.now() - start,
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
const tokens = args.toLowerCase().split(/\s+/).filter(Boolean);
|
|
975
|
-
let nextPolicy = policy;
|
|
976
|
-
for (let index = 0; index < tokens.length; index++) {
|
|
977
|
-
const token = tokens[index];
|
|
978
|
-
if (token === "read-only" || token === "readonly" || token === "read_only") {
|
|
979
|
-
nextPolicy = withExecutionPolicyOverrides(nextPolicy, { sandboxMode: "read_only" });
|
|
980
|
-
continue;
|
|
981
|
-
}
|
|
982
|
-
if (token === "workspace-write" || token === "workspace_write") {
|
|
983
|
-
nextPolicy = withExecutionPolicyOverrides(nextPolicy, { sandboxMode: "workspace_write" });
|
|
984
|
-
continue;
|
|
985
|
-
}
|
|
986
|
-
if (token === "full-access" || token === "danger-full-access" || token === "danger_full_access") {
|
|
987
|
-
nextPolicy = withExecutionPolicyOverrides(nextPolicy, { sandboxMode: "danger_full_access" });
|
|
988
|
-
continue;
|
|
989
|
-
}
|
|
990
|
-
if (token === "network" && tokens[index + 1]) {
|
|
991
|
-
nextPolicy = withExecutionPolicyOverrides(nextPolicy, { networkAccess: tokens[index + 1] === "on" });
|
|
992
|
-
index += 1;
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
|
-
if (token === "approval" && tokens[index + 1]) {
|
|
996
|
-
const approvalPolicy = tokens[index + 1];
|
|
997
|
-
if (approvalPolicy === "never" || approvalPolicy === "on_request" || approvalPolicy === "untrusted") {
|
|
998
|
-
nextPolicy = withExecutionPolicyOverrides(nextPolicy, { approvalPolicy });
|
|
999
|
-
index += 1;
|
|
1000
|
-
continue;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
return {
|
|
1004
|
-
success: false,
|
|
1005
|
-
output: "Usage: /permissions [read-only|workspace-write|full-access] [network on|off] [approval on_request|never|untrusted]",
|
|
1006
|
-
elapsed_ms: Date.now() - start,
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
1009
|
-
this.sessionExecutionPolicy = nextPolicy;
|
|
1010
|
-
return {
|
|
1011
|
-
success: true,
|
|
1012
|
-
output: summarizeExecutionPolicy(nextPolicy),
|
|
1013
|
-
elapsed_ms: Date.now() - start,
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
async handleReview(start) {
|
|
1017
|
-
const cwd = this.sessionCwd ?? process.cwd();
|
|
1018
|
-
const diffStat = await checkGitChanges(cwd);
|
|
1019
|
-
const reviewPolicy = withExecutionPolicyOverrides(await this.getSessionExecutionPolicy(), {
|
|
1020
|
-
sandboxMode: "read_only",
|
|
1021
|
-
approvalPolicy: "never",
|
|
1022
|
-
});
|
|
1023
|
-
if (this.deps.reviewAgentLoopRunner) {
|
|
1024
|
-
const review = await this.deps.reviewAgentLoopRunner.execute({
|
|
1025
|
-
cwd,
|
|
1026
|
-
diffStat,
|
|
1027
|
-
executionPolicy: reviewPolicy,
|
|
1028
|
-
});
|
|
1029
|
-
return { success: review.success, output: review.output, elapsed_ms: Date.now() - start };
|
|
1030
|
-
}
|
|
1031
|
-
const output = [
|
|
1032
|
-
"Review summary",
|
|
1033
|
-
diffStat ? diffStat : "No uncommitted changes detected.",
|
|
1034
|
-
"",
|
|
1035
|
-
"Execution policy",
|
|
1036
|
-
summarizeExecutionPolicy(reviewPolicy),
|
|
1037
|
-
].join("\n");
|
|
1038
|
-
return { success: true, output, elapsed_ms: Date.now() - start };
|
|
1039
|
-
}
|
|
1040
|
-
async handleFork(title, start) {
|
|
1041
|
-
const cwd = this.sessionCwd ?? process.cwd();
|
|
1042
|
-
const sessionId = crypto.randomUUID();
|
|
1043
|
-
const baseSession = this.history?.getSessionData() ?? {
|
|
1044
|
-
id: sessionId,
|
|
1045
|
-
cwd,
|
|
1046
|
-
createdAt: new Date().toISOString(),
|
|
1047
|
-
updatedAt: new Date().toISOString(),
|
|
1048
|
-
messages: [],
|
|
1049
|
-
};
|
|
1050
|
-
const now = new Date().toISOString();
|
|
1051
|
-
const forkedSession = {
|
|
1052
|
-
...baseSession,
|
|
1053
|
-
id: sessionId,
|
|
1054
|
-
createdAt: now,
|
|
1055
|
-
updatedAt: now,
|
|
1056
|
-
title: title || (baseSession.title ? `${baseSession.title} (fork)` : "Forked session"),
|
|
1057
|
-
};
|
|
1058
|
-
this.history = ChatHistory.fromSession(this.deps.stateManager, forkedSession);
|
|
1059
|
-
this.sessionCwd = cwd;
|
|
1060
|
-
this.sessionActive = true;
|
|
1061
|
-
this.nativeAgentLoopStatePath = `chat/agentloop/${sessionId}.state.json`;
|
|
1062
|
-
this.history.setAgentLoopStatePath(this.nativeAgentLoopStatePath);
|
|
1063
|
-
await this.history.persist();
|
|
1064
|
-
return {
|
|
1065
|
-
success: true,
|
|
1066
|
-
output: `Forked chat session as ${sessionId}.`,
|
|
1067
|
-
elapsed_ms: Date.now() - start,
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
async handleUndo(start) {
|
|
1071
|
-
if (!this.history) {
|
|
1072
|
-
return { success: false, output: "No active chat session to undo.", elapsed_ms: Date.now() - start };
|
|
1073
|
-
}
|
|
1074
|
-
const removed = await this.history.removeLastTurn();
|
|
1075
|
-
if (removed === 0) {
|
|
1076
|
-
return { success: false, output: "No chat turn to undo.", elapsed_ms: Date.now() - start };
|
|
1077
|
-
}
|
|
1078
|
-
return {
|
|
1079
|
-
success: true,
|
|
1080
|
-
output: `Removed ${removed} message(s) from chat history. File changes were not reverted.`,
|
|
1081
|
-
elapsed_ms: Date.now() - start,
|
|
1082
|
-
};
|
|
1083
|
-
}
|
|
1084
|
-
async handleTend(args, start) {
|
|
1085
|
-
if (!this.deps.llmClient) {
|
|
1086
|
-
return {
|
|
1087
|
-
success: false,
|
|
1088
|
-
output: "Tend not available — missing LLM configuration",
|
|
1089
|
-
elapsed_ms: Date.now() - start,
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
if (!this.deps.goalNegotiator) {
|
|
1093
|
-
return {
|
|
1094
|
-
success: false,
|
|
1095
|
-
output: "Tend not available — missing goal negotiator",
|
|
1096
|
-
elapsed_ms: Date.now() - start,
|
|
1097
|
-
};
|
|
1098
|
-
}
|
|
1099
|
-
if (!this.deps.daemonClient) {
|
|
1100
|
-
return {
|
|
1101
|
-
success: false,
|
|
1102
|
-
output: "Tend not available — daemon client not configured. Start the daemon with 'pulseed daemon start' first.",
|
|
1103
|
-
elapsed_ms: Date.now() - start,
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
const history = this.history?.getMessages() ?? [];
|
|
1107
|
-
const tendDeps = {
|
|
1108
|
-
llmClient: this.deps.llmClient,
|
|
1109
|
-
goalNegotiator: this.deps.goalNegotiator,
|
|
1110
|
-
daemonClient: this.deps.daemonClient,
|
|
1111
|
-
stateManager: this.deps.stateManager,
|
|
1112
|
-
chatHistory: history,
|
|
1113
|
-
};
|
|
1114
|
-
const tendCommand = new TendCommand();
|
|
1115
|
-
const result = await tendCommand.execute(args, tendDeps);
|
|
1116
|
-
if (result.needsConfirmation && result.goalId) {
|
|
1117
|
-
this.pendingTend = { goalId: result.goalId, maxIterations: result.maxIterations };
|
|
1118
|
-
return {
|
|
1119
|
-
success: true,
|
|
1120
|
-
output: result.confirmation ?? result.message,
|
|
1121
|
-
elapsed_ms: Date.now() - start,
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
return {
|
|
1125
|
-
success: result.success,
|
|
1126
|
-
output: result.message,
|
|
1127
|
-
elapsed_ms: Date.now() - start,
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
|
-
async handleTendConfirmation(input, start) {
|
|
1131
|
-
const pending = this.pendingTend;
|
|
1132
|
-
this.pendingTend = null;
|
|
1133
|
-
const normalized = input.trim().toLowerCase();
|
|
1134
|
-
const confirmed = normalized === "" || normalized === "y" || normalized === "yes";
|
|
1135
|
-
if (!confirmed) {
|
|
1136
|
-
// Bug 2: treat any non-y/yes/empty/n/no input as cancellation too
|
|
1137
|
-
return {
|
|
1138
|
-
success: true,
|
|
1139
|
-
output: "Tend cancelled. Continue chatting to refine your goal, then try /tend again.",
|
|
1140
|
-
elapsed_ms: Date.now() - start,
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
if (!this.deps.daemonClient) {
|
|
1144
|
-
return {
|
|
1145
|
-
success: false,
|
|
1146
|
-
output: "Daemon client not available.",
|
|
1147
|
-
elapsed_ms: Date.now() - start,
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
const { goalId, maxIterations } = pending;
|
|
1151
|
-
let subscriber = null;
|
|
1152
|
-
if (this.deps.daemonBaseUrl && !this.activeSubscribers.has(goalId)) {
|
|
1153
|
-
subscriber = new EventSubscriber(this.deps.daemonBaseUrl, goalId, "normal");
|
|
1154
|
-
this.activeSubscribers.set(goalId, subscriber);
|
|
1155
|
-
subscriber.on("notification", (notification) => {
|
|
1156
|
-
const n = notification;
|
|
1157
|
-
this.deps.onNotification?.(n.message);
|
|
1158
|
-
this.onNotification?.(n.message);
|
|
1159
|
-
});
|
|
1160
|
-
subscriber.on("chat_event", (event) => {
|
|
1161
|
-
this.emitEvent(event);
|
|
1162
|
-
});
|
|
1163
|
-
try {
|
|
1164
|
-
await subscriber.subscribeReady();
|
|
1165
|
-
}
|
|
1166
|
-
catch (err) {
|
|
1167
|
-
subscriber.unsubscribe();
|
|
1168
|
-
this.activeSubscribers.delete(goalId);
|
|
1169
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1170
|
-
return {
|
|
1171
|
-
success: false,
|
|
1172
|
-
output: `Daemon event stream unavailable: ${msg}. Goal was not started.`,
|
|
1173
|
-
elapsed_ms: Date.now() - start,
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
try {
|
|
1178
|
-
await this.deps.daemonClient.startGoal(goalId);
|
|
1179
|
-
}
|
|
1180
|
-
catch (err) {
|
|
1181
|
-
if (subscriber) {
|
|
1182
|
-
subscriber.unsubscribe();
|
|
1183
|
-
this.activeSubscribers.delete(goalId);
|
|
1184
|
-
}
|
|
1185
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1186
|
-
return {
|
|
1187
|
-
success: false,
|
|
1188
|
-
output: `Daemon unavailable: ${msg}. Start the daemon with 'pulseed daemon start' first.`,
|
|
1189
|
-
elapsed_ms: Date.now() - start,
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
|
-
const iterNote = maxIterations !== undefined ? ` (max ${maxIterations} iterations)` : "";
|
|
1193
|
-
const shortId = goalId.length > 12 ? goalId.slice(0, 12) : goalId;
|
|
1194
|
-
return {
|
|
1195
|
-
success: true,
|
|
1196
|
-
output: `[tend] ${shortId}: Started — daemon is now tending your goal${iterNote}.\nRun 'pulseed status' to check progress.`,
|
|
1197
|
-
elapsed_ms: Date.now() - start,
|
|
1198
|
-
};
|
|
1199
|
-
}
|
|
1200
|
-
/**
|
|
1201
|
-
* Execute a single chat turn.
|
|
1202
|
-
*
|
|
1203
|
-
* Flow:
|
|
1204
|
-
* 1. Intercept slash commands before adapter dispatch
|
|
1205
|
-
* 2. Resolve git root → create ChatHistory
|
|
1206
|
-
* 3. Build chat context and assemble prompt
|
|
1207
|
-
* 4. Persist user message BEFORE calling adapter (crash-safe)
|
|
1208
|
-
* 5. Execute via adapter
|
|
1209
|
-
* 6. Verify changes (git diff + tests); retry up to MAX_VERIFY_RETRIES if tests fail
|
|
1210
|
-
* 7. Persist assistant response only after the final assistant text is complete
|
|
1211
|
-
*/
|
|
1212
193
|
async execute(input, cwd, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
|
|
1213
|
-
const eventContext = this.createEventContext();
|
|
1214
|
-
const
|
|
194
|
+
const eventContext = this.eventBridge.createEventContext();
|
|
195
|
+
const resolvedCwd = resolveGitRoot(cwd);
|
|
196
|
+
const activeTurn = this.eventBridge.beginActiveTurn(eventContext, resolvedCwd);
|
|
197
|
+
const resumeCommand = this.commandHandler.parseResumeCommand(input);
|
|
1215
198
|
const resumeOnly = resumeCommand !== null;
|
|
1216
199
|
const runtimeControlContext = options.runtimeControlContext ?? this.runtimeControlContext;
|
|
1217
200
|
const executionGoalId = options.goalId ?? this.deps.goalId;
|
|
1218
|
-
|
|
1219
|
-
const commandResult = resumeOnly ? null : await this.handleCommand(input);
|
|
201
|
+
const commandResult = resumeOnly ? null : await this.commandHandler.handleCommand(input, resolvedCwd);
|
|
1220
202
|
if (commandResult !== null) {
|
|
1221
|
-
|
|
1222
|
-
this.emitEvent({
|
|
1223
|
-
type: "assistant_final",
|
|
1224
|
-
text: commandResult.output,
|
|
1225
|
-
persisted: false,
|
|
1226
|
-
...this.eventBase(eventContext),
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
this.emitLifecycleEndEvent(commandResult.success ? "completed" : "error", commandResult.elapsed_ms, eventContext, false);
|
|
1230
|
-
return commandResult;
|
|
203
|
+
return this.finalizeNonPersistentResult(commandResult, eventContext);
|
|
1231
204
|
}
|
|
1232
|
-
// Intercept plain Y/n responses (and any other input) when a /tend confirmation is pending
|
|
1233
205
|
if (this.pendingTend !== null && !resumeOnly) {
|
|
1234
|
-
const confirmationResult = await this.handleTendConfirmation(input.trim(), Date.now());
|
|
1235
|
-
|
|
1236
|
-
this.emitEvent({
|
|
1237
|
-
type: "assistant_final",
|
|
1238
|
-
text: confirmationResult.output,
|
|
1239
|
-
persisted: false,
|
|
1240
|
-
...this.eventBase(eventContext),
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
this.emitLifecycleEndEvent(confirmationResult.success ? "completed" : "error", confirmationResult.elapsed_ms, eventContext, false);
|
|
1244
|
-
return confirmationResult;
|
|
206
|
+
const confirmationResult = await this.commandHandler.handleTendConfirmation(input.trim(), Date.now());
|
|
207
|
+
return this.finalizeNonPersistentResult(confirmationResult, eventContext);
|
|
1245
208
|
}
|
|
1246
209
|
if (resumeOnly && resumeCommand.selector) {
|
|
1247
210
|
try {
|
|
211
|
+
const selectorResolution = await resolveChatResumeSelector(resumeCommand.selector, this.deps);
|
|
212
|
+
if (selectorResolution.nonResumableMessage) {
|
|
213
|
+
return this.finalizeNonPersistentResult({
|
|
214
|
+
success: false,
|
|
215
|
+
output: selectorResolution.nonResumableMessage,
|
|
216
|
+
elapsed_ms: 0,
|
|
217
|
+
}, eventContext);
|
|
218
|
+
}
|
|
1248
219
|
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
1249
|
-
const session = await catalog.loadSessionBySelector(
|
|
220
|
+
const session = await catalog.loadSessionBySelector(selectorResolution.chatSelector);
|
|
1250
221
|
if (!session) {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
persisted: false,
|
|
1257
|
-
...this.eventBase(eventContext),
|
|
1258
|
-
});
|
|
1259
|
-
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1260
|
-
return { success: false, output, elapsed_ms };
|
|
222
|
+
return this.finalizeNonPersistentResult({
|
|
223
|
+
success: false,
|
|
224
|
+
output: `No chat session matched selector "${selectorResolution.chatSelector}".`,
|
|
225
|
+
elapsed_ms: 0,
|
|
226
|
+
}, eventContext);
|
|
1261
227
|
}
|
|
1262
228
|
this.startSessionFromLoadedSession(session);
|
|
1263
229
|
}
|
|
1264
230
|
catch (err) {
|
|
1265
|
-
const elapsed_ms = 0;
|
|
1266
231
|
const output = err instanceof ChatSessionSelectorError ? err.message : `Failed to load chat session: ${err instanceof Error ? err.message : String(err)}`;
|
|
1267
|
-
this.
|
|
1268
|
-
type: "assistant_final",
|
|
1269
|
-
text: output,
|
|
1270
|
-
persisted: false,
|
|
1271
|
-
...this.eventBase(eventContext),
|
|
1272
|
-
});
|
|
1273
|
-
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1274
|
-
return { success: false, output, elapsed_ms };
|
|
232
|
+
return this.finalizeNonPersistentResult({ success: false, output, elapsed_ms: 0 }, eventContext);
|
|
1275
233
|
}
|
|
1276
234
|
}
|
|
1277
|
-
// Reuse session (interactive mode) or create a fresh one per call (1-shot mode)
|
|
1278
235
|
if (!this.sessionActive) {
|
|
1279
|
-
const gitRoot = resolveGitRoot(cwd);
|
|
1280
236
|
const sessionId = crypto.randomUUID();
|
|
1281
|
-
this.history = new ChatHistory(this.deps.stateManager, sessionId,
|
|
237
|
+
this.history = new ChatHistory(this.deps.stateManager, sessionId, resolvedCwd);
|
|
1282
238
|
this.nativeAgentLoopStatePath = `chat/agentloop/${sessionId}.state.json`;
|
|
1283
|
-
this.history.
|
|
239
|
+
this.history.resetAgentLoopState(this.nativeAgentLoopStatePath);
|
|
1284
240
|
}
|
|
1285
|
-
const executionCwd = this.sessionCwd ??
|
|
1286
|
-
const gitRoot = this.sessionCwd ??
|
|
1287
|
-
|
|
241
|
+
const executionCwd = this.sessionCwd ?? resolvedCwd;
|
|
242
|
+
const gitRoot = this.sessionCwd ?? resolvedCwd;
|
|
243
|
+
activeTurn.cwd = gitRoot;
|
|
1288
244
|
const history = this.history;
|
|
1289
|
-
this.
|
|
245
|
+
const pinnedReplyTarget = normalizePinnedReplyTarget(runtimeControlContext?.replyTarget ?? this.deps.runtimeReplyTarget ?? null);
|
|
246
|
+
if (pinnedReplyTarget) {
|
|
247
|
+
history.setNotificationReplyTarget(pinnedReplyTarget);
|
|
248
|
+
}
|
|
249
|
+
this.eventBridge.emitEvent({
|
|
1290
250
|
type: "lifecycle_start",
|
|
1291
251
|
input,
|
|
1292
|
-
...this.eventBase(eventContext),
|
|
252
|
+
...this.eventBridge.eventBase(eventContext),
|
|
1293
253
|
});
|
|
1294
|
-
// Persist-before-execute: user message written to disk before model or adapter execution.
|
|
1295
254
|
if (!resumeOnly) {
|
|
1296
255
|
await history.appendUserMessage(input);
|
|
1297
256
|
}
|
|
1298
|
-
// Build static grounding once per session; dynamic context is rebuilt each turn.
|
|
1299
257
|
if (this.cachedStaticSystemPrompt === null) {
|
|
1300
258
|
try {
|
|
1301
259
|
this.cachedStaticSystemPrompt = buildStaticSystemPrompt(this.providerConfigBaseDir());
|
|
@@ -1304,11 +262,9 @@ export class ChatRunner {
|
|
|
1304
262
|
this.cachedStaticSystemPrompt = "";
|
|
1305
263
|
}
|
|
1306
264
|
}
|
|
1307
|
-
// Build conversation history from prior turns (last 10), including any manual compaction summary.
|
|
1308
265
|
const messages = history.getMessages();
|
|
1309
266
|
const compactionSummary = history.getSessionData().compactionSummary;
|
|
1310
267
|
const priorTurns = resumeOnly ? messages.slice(-10) : messages.slice(0, -1).slice(-10);
|
|
1311
|
-
let historyBlock = "";
|
|
1312
268
|
const historySections = [];
|
|
1313
269
|
if (compactionSummary) {
|
|
1314
270
|
historySections.push(`Compacted previous conversation summary:\n${compactionSummary}`);
|
|
@@ -1317,28 +273,26 @@ export class ChatRunner {
|
|
|
1317
273
|
const lines = priorTurns.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${m.content}`).join("\n");
|
|
1318
274
|
historySections.push(`Previous conversation:\n${lines}`);
|
|
1319
275
|
}
|
|
1320
|
-
|
|
1321
|
-
historyBlock = `${historySections.join("\n\n")}\n\nCurrent message:\n`;
|
|
1322
|
-
}
|
|
276
|
+
const historyBlock = historySections.length > 0 ? `${historySections.join("\n\n")}\n\nCurrent message:\n` : "";
|
|
1323
277
|
const selectedRoute = resumeOnly
|
|
1324
278
|
? null
|
|
1325
279
|
: (options.selectedRoute ?? this.resolveRouteFromInput(input, runtimeControlContext));
|
|
1326
|
-
|
|
280
|
+
this.lastSelectedRoute = selectedRoute;
|
|
281
|
+
this.eventBridge.emitIntent(input, selectedRoute, eventContext);
|
|
1327
282
|
const start = Date.now();
|
|
1328
283
|
const assistantBuffer = { text: "" };
|
|
1329
|
-
const turnUsage = this.zeroUsageCounter();
|
|
1330
284
|
const identityResponse = resumeOnly ? null : resolveSelfIdentityResponse(input, this.providerConfigBaseDir());
|
|
1331
285
|
if (identityResponse !== null) {
|
|
1332
286
|
const elapsed_ms = Date.now() - start;
|
|
1333
287
|
await history.appendAssistantMessage(identityResponse);
|
|
1334
|
-
this.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
1335
|
-
this.emitEvent({
|
|
288
|
+
this.eventBridge.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
289
|
+
this.eventBridge.emitEvent({
|
|
1336
290
|
type: "assistant_final",
|
|
1337
291
|
text: identityResponse,
|
|
1338
292
|
persisted: true,
|
|
1339
|
-
...this.eventBase(eventContext),
|
|
293
|
+
...this.eventBridge.eventBase(eventContext),
|
|
1340
294
|
});
|
|
1341
|
-
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
295
|
+
this.eventBridge.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1342
296
|
return {
|
|
1343
297
|
success: true,
|
|
1344
298
|
output: identityResponse,
|
|
@@ -1346,78 +300,26 @@ export class ChatRunner {
|
|
|
1346
300
|
};
|
|
1347
301
|
}
|
|
1348
302
|
if (selectedRoute?.kind === "runtime_control") {
|
|
1349
|
-
|
|
303
|
+
this.eventBridge.emitCheckpoint("Runtime control selected", `${selectedRoute.intent.kind} request recognized.`, eventContext, "route");
|
|
304
|
+
const runtimeControlResult = await executeRuntimeControlRoute(this.routeHost(), selectedRoute, runtimeControlContext, executionCwd, start);
|
|
1350
305
|
if (runtimeControlResult.success) {
|
|
1351
306
|
await history.appendAssistantMessage(runtimeControlResult.output);
|
|
1352
|
-
this.
|
|
1353
|
-
this.
|
|
307
|
+
this.eventBridge.emitCheckpoint("Runtime control completed", "The runtime-control operation produced a result.", eventContext, "complete");
|
|
308
|
+
this.eventBridge.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
309
|
+
this.eventBridge.emitEvent({
|
|
1354
310
|
type: "assistant_final",
|
|
1355
311
|
text: runtimeControlResult.output,
|
|
1356
312
|
persisted: true,
|
|
1357
|
-
...this.eventBase(eventContext),
|
|
313
|
+
...this.eventBridge.eventBase(eventContext),
|
|
1358
314
|
});
|
|
1359
|
-
this.emitLifecycleEndEvent("completed", runtimeControlResult.elapsed_ms, eventContext, true);
|
|
315
|
+
this.eventBridge.emitLifecycleEndEvent("completed", runtimeControlResult.elapsed_ms, eventContext, true);
|
|
1360
316
|
}
|
|
1361
317
|
else {
|
|
1362
|
-
this.emitLifecycleErrorEvent(runtimeControlResult.output, assistantBuffer.text, eventContext);
|
|
1363
|
-
this.emitLifecycleEndEvent("error", runtimeControlResult.elapsed_ms, eventContext, false);
|
|
318
|
+
runtimeControlResult.output = this.eventBridge.emitLifecycleErrorEvent(runtimeControlResult.output, assistantBuffer.text, eventContext);
|
|
319
|
+
this.eventBridge.emitLifecycleEndEvent("error", runtimeControlResult.elapsed_ms, eventContext, false);
|
|
1364
320
|
}
|
|
1365
321
|
return runtimeControlResult;
|
|
1366
322
|
}
|
|
1367
|
-
if (selectedRoute?.kind === "direct_answer") {
|
|
1368
|
-
try {
|
|
1369
|
-
this.emitActivity("lifecycle", "Calling model...", eventContext, "lifecycle:model");
|
|
1370
|
-
const directResponse = await this.sendLLMMessage(this.deps.llmClient, [{ role: "user", content: directPrompt }], {
|
|
1371
|
-
...(this.cachedStaticSystemPrompt ? { system: this.cachedStaticSystemPrompt } : {}),
|
|
1372
|
-
model_tier: selectedRoute.modelTier,
|
|
1373
|
-
max_tokens: selectedRoute.maxTokens,
|
|
1374
|
-
}, assistantBuffer, eventContext);
|
|
1375
|
-
this.addUsageCounter(turnUsage, this.usageFromLLMResponse(directResponse));
|
|
1376
|
-
const elapsed_ms = Date.now() - start;
|
|
1377
|
-
const output = assistantBuffer.text || directResponse.content || "(no response)";
|
|
1378
|
-
if (this.hasUsage(turnUsage)) {
|
|
1379
|
-
history.recordUsage("execution", turnUsage);
|
|
1380
|
-
}
|
|
1381
|
-
await history.appendAssistantMessage(output);
|
|
1382
|
-
this.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
1383
|
-
this.emitEvent({
|
|
1384
|
-
type: "assistant_final",
|
|
1385
|
-
text: output,
|
|
1386
|
-
persisted: true,
|
|
1387
|
-
...this.eventBase(eventContext),
|
|
1388
|
-
});
|
|
1389
|
-
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1390
|
-
return {
|
|
1391
|
-
success: true,
|
|
1392
|
-
output,
|
|
1393
|
-
elapsed_ms,
|
|
1394
|
-
diagnostics: {
|
|
1395
|
-
route: "direct",
|
|
1396
|
-
reason: selectedRoute.reason,
|
|
1397
|
-
modelTier: selectedRoute.modelTier,
|
|
1398
|
-
maxTokens: selectedRoute.maxTokens,
|
|
1399
|
-
},
|
|
1400
|
-
};
|
|
1401
|
-
}
|
|
1402
|
-
catch (err) {
|
|
1403
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1404
|
-
this.emitLifecycleErrorEvent(message, assistantBuffer.text, eventContext);
|
|
1405
|
-
this.emitLifecycleEndEvent("error", Date.now() - start, eventContext, false);
|
|
1406
|
-
return {
|
|
1407
|
-
success: false,
|
|
1408
|
-
output: assistantBuffer.text
|
|
1409
|
-
? `${assistantBuffer.text}\n\n[interrupted: ${message}]`
|
|
1410
|
-
: `Error: ${message}`,
|
|
1411
|
-
elapsed_ms: Date.now() - start,
|
|
1412
|
-
diagnostics: {
|
|
1413
|
-
route: "direct",
|
|
1414
|
-
reason: selectedRoute.reason,
|
|
1415
|
-
modelTier: selectedRoute.modelTier,
|
|
1416
|
-
maxTokens: selectedRoute.maxTokens,
|
|
1417
|
-
},
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
323
|
const usesNativeAgentLoop = resumeOnly || selectedRoute?.kind === "agent_loop";
|
|
1422
324
|
const groundingWorkspaceContext = !resumeOnly && usesNativeAgentLoop
|
|
1423
325
|
? await buildChatContext(input, executionCwd)
|
|
@@ -1425,7 +327,7 @@ export class ChatRunner {
|
|
|
1425
327
|
let systemPrompt = this.cachedStaticSystemPrompt ?? "";
|
|
1426
328
|
if (!resumeOnly) {
|
|
1427
329
|
try {
|
|
1428
|
-
this.emitActivity("lifecycle", "Preparing context...", eventContext, "lifecycle:context");
|
|
330
|
+
this.eventBridge.emitActivity("lifecycle", "Preparing context...", eventContext, "lifecycle:context");
|
|
1429
331
|
if (usesNativeAgentLoop) {
|
|
1430
332
|
systemPrompt = await buildChatAgentLoopSystemPrompt({
|
|
1431
333
|
stateManager: this.deps.stateManager,
|
|
@@ -1453,6 +355,9 @@ export class ChatRunner {
|
|
|
1453
355
|
catch {
|
|
1454
356
|
systemPrompt = this.cachedStaticSystemPrompt ?? "";
|
|
1455
357
|
}
|
|
358
|
+
this.eventBridge.emitCheckpoint("Context gathered", usesNativeAgentLoop
|
|
359
|
+
? "Workspace and agent-loop grounding are ready."
|
|
360
|
+
: "Workspace grounding is ready.", eventContext, "context");
|
|
1456
361
|
}
|
|
1457
362
|
const agentLoopSystemPrompt = [
|
|
1458
363
|
systemPrompt,
|
|
@@ -1466,745 +371,108 @@ export class ChatRunner {
|
|
|
1466
371
|
const prompt = historyBlock ? `${historyBlock}${basePrompt}` : basePrompt;
|
|
1467
372
|
if (resumeOnly && !this.deps.chatAgentLoopRunner) {
|
|
1468
373
|
const elapsed_ms = Date.now() - start;
|
|
1469
|
-
const output = "Resume requires the native chat agentloop runtime.";
|
|
1470
|
-
this.
|
|
1471
|
-
|
|
1472
|
-
text: output,
|
|
1473
|
-
persisted: false,
|
|
1474
|
-
...this.eventBase(eventContext),
|
|
1475
|
-
});
|
|
1476
|
-
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1477
|
-
return {
|
|
1478
|
-
success: false,
|
|
1479
|
-
output,
|
|
1480
|
-
elapsed_ms,
|
|
1481
|
-
};
|
|
374
|
+
const output = this.eventBridge.emitLifecycleErrorEvent("Resume requires the native chat agentloop runtime.", assistantBuffer.text, eventContext);
|
|
375
|
+
this.eventBridge.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
376
|
+
return { success: false, output, elapsed_ms };
|
|
1482
377
|
}
|
|
1483
|
-
const chatAgentLoopRunner = this.deps.chatAgentLoopRunner;
|
|
1484
378
|
if (resumeOnly || selectedRoute?.kind === "agent_loop") {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
output,
|
|
1500
|
-
elapsed_ms,
|
|
1501
|
-
};
|
|
1502
|
-
}
|
|
1503
|
-
this.emitActivity("lifecycle", "Calling model...", eventContext, "lifecycle:model");
|
|
1504
|
-
const result = await chatAgentLoopRunner.execute({
|
|
1505
|
-
message: basePrompt,
|
|
1506
|
-
cwd: executionCwd,
|
|
1507
|
-
goalId: executionGoalId,
|
|
1508
|
-
history: priorTurns.map((m) => ({
|
|
1509
|
-
role: m.role === "assistant" ? "assistant" : "user",
|
|
1510
|
-
content: m.content,
|
|
1511
|
-
})),
|
|
1512
|
-
eventSink: this.createAgentLoopEventSink(eventContext),
|
|
1513
|
-
approvalFn: async (request) => {
|
|
1514
|
-
if (this.deps.approvalFn) {
|
|
1515
|
-
return this.deps.approvalFn(request.reason);
|
|
1516
|
-
}
|
|
1517
|
-
return false;
|
|
1518
|
-
},
|
|
1519
|
-
toolCallContext: {
|
|
1520
|
-
executionPolicy: await this.getSessionExecutionPolicy(),
|
|
1521
|
-
},
|
|
1522
|
-
...(this.nativeAgentLoopStatePath ? { resumeStatePath: this.nativeAgentLoopStatePath } : {}),
|
|
1523
|
-
...(resumeState ? { resumeState } : {}),
|
|
1524
|
-
...(resumeOnly ? { resumeOnly: true } : {}),
|
|
1525
|
-
...(agentLoopSystemPrompt ? { systemPrompt: agentLoopSystemPrompt } : {}),
|
|
1526
|
-
});
|
|
1527
|
-
const elapsed_ms = Date.now() - start;
|
|
1528
|
-
const agentLoopUsage = result.agentLoop?.usage
|
|
1529
|
-
? this.normalizeUsageCounter(result.agentLoop.usage)
|
|
1530
|
-
: this.zeroUsageCounter();
|
|
1531
|
-
if (this.hasUsage(agentLoopUsage)) {
|
|
1532
|
-
history.recordUsage("agentloop", agentLoopUsage);
|
|
1533
|
-
}
|
|
1534
|
-
if (result.output) {
|
|
1535
|
-
this.pushAssistantDelta(result.output, assistantBuffer, eventContext);
|
|
1536
|
-
}
|
|
1537
|
-
if (result.success) {
|
|
1538
|
-
await history.appendAssistantMessage(result.output);
|
|
1539
|
-
this.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
1540
|
-
this.emitEvent({
|
|
1541
|
-
type: "assistant_final",
|
|
1542
|
-
text: result.output,
|
|
1543
|
-
persisted: true,
|
|
1544
|
-
...this.eventBase(eventContext),
|
|
1545
|
-
});
|
|
1546
|
-
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1547
|
-
}
|
|
1548
|
-
else {
|
|
1549
|
-
this.emitLifecycleErrorEvent(result.output || result.error || "Unknown error", assistantBuffer.text, eventContext);
|
|
1550
|
-
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1551
|
-
}
|
|
1552
|
-
return {
|
|
1553
|
-
success: result.success,
|
|
1554
|
-
output: result.output,
|
|
1555
|
-
elapsed_ms,
|
|
1556
|
-
};
|
|
1557
|
-
}
|
|
1558
|
-
catch (err) {
|
|
1559
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1560
|
-
this.emitLifecycleErrorEvent(message, assistantBuffer.text, eventContext);
|
|
1561
|
-
this.emitLifecycleEndEvent("error", Date.now() - start, eventContext, false);
|
|
1562
|
-
return {
|
|
1563
|
-
success: false,
|
|
1564
|
-
output: assistantBuffer.text
|
|
1565
|
-
? `${assistantBuffer.text}\n\n[interrupted: ${message}]`
|
|
1566
|
-
: `Error: ${message}`,
|
|
1567
|
-
elapsed_ms: Date.now() - start,
|
|
1568
|
-
};
|
|
1569
|
-
}
|
|
379
|
+
return executeAgentLoopRoute(this.routeHost(), {
|
|
380
|
+
resumeOnly,
|
|
381
|
+
executionCwd,
|
|
382
|
+
executionGoalId,
|
|
383
|
+
basePrompt,
|
|
384
|
+
priorTurns,
|
|
385
|
+
agentLoopSystemPrompt,
|
|
386
|
+
assistantBuffer,
|
|
387
|
+
eventContext,
|
|
388
|
+
history,
|
|
389
|
+
gitRoot,
|
|
390
|
+
activeAbortSignal: activeTurn.abortController.signal,
|
|
391
|
+
start,
|
|
392
|
+
});
|
|
1570
393
|
}
|
|
1571
|
-
// Prefer the local LLM/tool loop over the external adapter fallback whenever a client is available.
|
|
1572
394
|
if (selectedRoute?.kind === "tool_loop") {
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
text: toolResult.output,
|
|
1584
|
-
persisted: true,
|
|
1585
|
-
...this.eventBase(eventContext),
|
|
1586
|
-
});
|
|
1587
|
-
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1588
|
-
return { success: true, output: toolResult.output, elapsed_ms };
|
|
1589
|
-
}
|
|
1590
|
-
catch (err) {
|
|
1591
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1592
|
-
this.emitLifecycleErrorEvent(message, assistantBuffer.text, eventContext);
|
|
1593
|
-
this.emitLifecycleEndEvent("error", Date.now() - start, eventContext, false);
|
|
1594
|
-
return {
|
|
1595
|
-
success: false,
|
|
1596
|
-
output: assistantBuffer.text
|
|
1597
|
-
? `${assistantBuffer.text}\n\n[interrupted: ${message}]`
|
|
1598
|
-
: `Error: ${message}`,
|
|
1599
|
-
elapsed_ms: Date.now() - start,
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
395
|
+
return executeToolLoopRoute(this.routeHost(), {
|
|
396
|
+
prompt,
|
|
397
|
+
eventContext,
|
|
398
|
+
assistantBuffer,
|
|
399
|
+
systemPrompt: systemPrompt || undefined,
|
|
400
|
+
executionGoalId,
|
|
401
|
+
history,
|
|
402
|
+
gitRoot,
|
|
403
|
+
start,
|
|
404
|
+
});
|
|
1602
405
|
}
|
|
1603
406
|
if (!resumeOnly && selectedRoute && selectedRoute.kind !== "adapter") {
|
|
1604
407
|
const elapsed_ms = Date.now() - start;
|
|
1605
|
-
const output = `Unsupported chat route: ${selectedRoute.kind}
|
|
1606
|
-
this.
|
|
1607
|
-
|
|
1608
|
-
return {
|
|
1609
|
-
success: false,
|
|
1610
|
-
output,
|
|
1611
|
-
elapsed_ms,
|
|
1612
|
-
};
|
|
408
|
+
const output = this.eventBridge.emitLifecycleErrorEvent(`Unsupported chat route: ${selectedRoute.kind}`, assistantBuffer.text, eventContext);
|
|
409
|
+
this.eventBridge.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
410
|
+
return { success: false, output, elapsed_ms };
|
|
1613
411
|
}
|
|
1614
|
-
|
|
412
|
+
return executeAdapterRoute(this.routeHost(), {
|
|
1615
413
|
prompt,
|
|
1616
|
-
timeout_ms: timeoutMs,
|
|
1617
|
-
adapter_type: this.deps.adapter.adapterType,
|
|
1618
414
|
cwd,
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
// Surface adapter errors into output when output is empty
|
|
1627
|
-
if (!result.output && result.error) {
|
|
1628
|
-
result = { ...result, output: `Error: ${result.error}` };
|
|
1629
|
-
}
|
|
1630
|
-
const elapsed_ms = Date.now() - start;
|
|
1631
|
-
if (result.output) {
|
|
1632
|
-
this.pushAssistantDelta(result.output, assistantBuffer, eventContext);
|
|
1633
|
-
}
|
|
1634
|
-
// Verification loop: check if git has uncommitted changes; if so, run tests
|
|
1635
|
-
const gitChanges = await checkGitChanges(gitRoot);
|
|
1636
|
-
if (gitChanges !== null && gitChanges !== "") {
|
|
1637
|
-
let retries = 0;
|
|
1638
|
-
const VERIFY_TIMEOUT_MS = 30_000;
|
|
1639
|
-
this.emitActivity("lifecycle", "Checking result...", eventContext, "lifecycle:checking");
|
|
1640
|
-
let verification = await Promise.race([
|
|
1641
|
-
verifyChatAction(gitRoot, this.deps.toolExecutor),
|
|
1642
|
-
new Promise((resolve) => setTimeout(() => resolve({ passed: true }), VERIFY_TIMEOUT_MS)),
|
|
1643
|
-
]);
|
|
1644
|
-
while (!verification.passed && retries < MAX_VERIFY_RETRIES) {
|
|
1645
|
-
retries++;
|
|
1646
|
-
const retryPrompt = `The previous changes caused test failures. Please fix them.\n\nTest output:\n${verification.testOutput ?? verification.errors.join("\n")}`;
|
|
1647
|
-
const retryTask = { ...task, prompt: retryPrompt };
|
|
1648
|
-
result = await this.deps.adapter.execute(retryTask);
|
|
1649
|
-
verification = await verifyChatAction(gitRoot, this.deps.toolExecutor);
|
|
1650
|
-
}
|
|
1651
|
-
if (!verification.passed) {
|
|
1652
|
-
this.emitLifecycleErrorEvent(`Changes applied but tests are still failing after ${MAX_VERIFY_RETRIES} retries.`, assistantBuffer.text, eventContext);
|
|
1653
|
-
this.emitLifecycleEndEvent("error", Date.now() - start, eventContext, false);
|
|
1654
|
-
return {
|
|
1655
|
-
success: false,
|
|
1656
|
-
output: `${assistantBuffer.text}\n\n[interrupted: tests are still failing after ${MAX_VERIFY_RETRIES} retries]\n\nTest output:\n${verification.testOutput ?? verification.errors.join("\n")}`.trim(),
|
|
1657
|
-
elapsed_ms: Date.now() - start,
|
|
1658
|
-
};
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
if (result.success) {
|
|
1662
|
-
await history.appendAssistantMessage(result.output);
|
|
1663
|
-
this.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
1664
|
-
this.emitEvent({
|
|
1665
|
-
type: "assistant_final",
|
|
1666
|
-
text: result.output,
|
|
1667
|
-
persisted: true,
|
|
1668
|
-
...this.eventBase(eventContext),
|
|
1669
|
-
});
|
|
1670
|
-
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1671
|
-
}
|
|
1672
|
-
else {
|
|
1673
|
-
const partialText = assistantBuffer.text !== result.output ? assistantBuffer.text : "";
|
|
1674
|
-
this.emitLifecycleErrorEvent(result.output || result.error || "Unknown error", partialText, eventContext);
|
|
1675
|
-
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1676
|
-
}
|
|
1677
|
-
return {
|
|
1678
|
-
success: result.success,
|
|
1679
|
-
output: result.output,
|
|
1680
|
-
elapsed_ms,
|
|
1681
|
-
};
|
|
1682
|
-
}
|
|
1683
|
-
async executeRuntimeControlRoute(route, runtimeControlContext, cwd, start) {
|
|
1684
|
-
if (!this.deps.runtimeControlService) {
|
|
1685
|
-
return {
|
|
1686
|
-
success: false,
|
|
1687
|
-
output: "Runtime control is not available in this chat surface yet.",
|
|
1688
|
-
elapsed_ms: Date.now() - start,
|
|
1689
|
-
};
|
|
1690
|
-
}
|
|
1691
|
-
const replyTarget = runtimeControlContext?.replyTarget ?? this.deps.runtimeReplyTarget;
|
|
1692
|
-
const actor = runtimeControlContext?.actor ?? this.deps.runtimeControlActor;
|
|
1693
|
-
const result = await this.deps.runtimeControlService.request({
|
|
1694
|
-
intent: route.intent,
|
|
1695
|
-
cwd,
|
|
1696
|
-
requestedBy: actor ?? {
|
|
1697
|
-
surface: replyTarget?.surface ?? "chat",
|
|
1698
|
-
platform: replyTarget?.platform,
|
|
1699
|
-
conversation_id: replyTarget?.conversation_id,
|
|
1700
|
-
identity_key: replyTarget?.identity_key,
|
|
1701
|
-
user_id: replyTarget?.user_id,
|
|
1702
|
-
},
|
|
1703
|
-
replyTarget: replyTarget ?? { surface: "chat" },
|
|
1704
|
-
approvalFn: runtimeControlContext?.approvalFn
|
|
1705
|
-
?? this.deps.runtimeControlApprovalFn
|
|
1706
|
-
?? this.deps.approvalFn,
|
|
415
|
+
timeoutMs,
|
|
416
|
+
systemPrompt: systemPrompt || undefined,
|
|
417
|
+
eventContext,
|
|
418
|
+
assistantBuffer,
|
|
419
|
+
gitRoot,
|
|
420
|
+
start,
|
|
421
|
+
history,
|
|
1707
422
|
});
|
|
1708
|
-
return {
|
|
1709
|
-
success: result.success,
|
|
1710
|
-
output: result.message,
|
|
1711
|
-
elapsed_ms: Date.now() - start,
|
|
1712
|
-
};
|
|
1713
423
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
* Loops up to MAX_TOOL_LOOPS times to resolve tool calls, then returns final text.
|
|
1717
|
-
*/
|
|
1718
|
-
async executeWithTools(prompt, eventContext, assistantBuffer, systemPrompt, goalId) {
|
|
1719
|
-
const llmClient = this.deps.llmClient;
|
|
1720
|
-
const messages = [{ role: "user", content: prompt }];
|
|
1721
|
-
const toolCallContext = await this.buildToolCallContext(goalId);
|
|
1722
|
-
const usage = this.zeroUsageCounter();
|
|
1723
|
-
for (let loop = 0; loop < MAX_TOOL_LOOPS; loop++) {
|
|
1724
|
-
// Recompute tools each iteration so newly activated deferred tools are included
|
|
1725
|
-
const tools = this.deps.registry
|
|
1726
|
-
? toToolDefinitionsFiltered(this.deps.registry.listAll(), { activatedTools: this.activatedTools })
|
|
1727
|
-
: [];
|
|
1728
|
-
const supportsNativeToolCalling = llmClient.supportsToolCalling?.() !== false;
|
|
1729
|
-
let response;
|
|
1730
|
-
try {
|
|
1731
|
-
this.emitActivity("lifecycle", "Calling model...", eventContext, "lifecycle:model");
|
|
1732
|
-
response = await this.sendLLMMessage(llmClient, messages, {
|
|
1733
|
-
...(supportsNativeToolCalling
|
|
1734
|
-
? { tools, ...(systemPrompt ? { system: systemPrompt } : {}) }
|
|
1735
|
-
: { system: buildPromptedToolProtocolSystemPrompt({ systemPrompt, tools }) }),
|
|
1736
|
-
}, assistantBuffer, eventContext);
|
|
1737
|
-
}
|
|
1738
|
-
catch (err) {
|
|
1739
|
-
console.error("[chat-runner] executeWithTools error:", err);
|
|
1740
|
-
const hint = err instanceof Error ? `: ${err.message}` : "";
|
|
1741
|
-
throw new Error(`Sorry, I encountered an error processing your request${hint}.`);
|
|
1742
|
-
}
|
|
1743
|
-
this.addUsageCounter(usage, this.usageFromLLMResponse(response));
|
|
1744
|
-
const toolCalls = response.tool_calls?.length
|
|
1745
|
-
? response.tool_calls
|
|
1746
|
-
: supportsNativeToolCalling
|
|
1747
|
-
? []
|
|
1748
|
-
: extractPromptedToolCalls({
|
|
1749
|
-
content: response.content,
|
|
1750
|
-
tools,
|
|
1751
|
-
createId: () => `prompted-${loop}-${crypto.randomUUID()}`,
|
|
1752
|
-
}).map((call) => ({
|
|
1753
|
-
id: call.id,
|
|
1754
|
-
type: "function",
|
|
1755
|
-
function: {
|
|
1756
|
-
name: call.name,
|
|
1757
|
-
arguments: JSON.stringify(call.input ?? {}),
|
|
1758
|
-
},
|
|
1759
|
-
}));
|
|
1760
|
-
if (!supportsNativeToolCalling && toolCalls.length > 0) {
|
|
1761
|
-
assistantBuffer.text = "";
|
|
1762
|
-
}
|
|
1763
|
-
// No tool calls — return the text content
|
|
1764
|
-
if (toolCalls.length === 0) {
|
|
1765
|
-
return {
|
|
1766
|
-
output: assistantBuffer.text || response.content || "(no response)",
|
|
1767
|
-
usage,
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
// Append assistant message, then process tool calls
|
|
1771
|
-
messages.push({ role: "assistant", content: response.content || "" });
|
|
1772
|
-
for (const tc of toolCalls) {
|
|
1773
|
-
let args = {};
|
|
1774
|
-
try {
|
|
1775
|
-
args = JSON.parse(tc.function.arguments || "{}");
|
|
1776
|
-
}
|
|
1777
|
-
catch {
|
|
1778
|
-
// ignore parse errors, use empty args
|
|
1779
|
-
}
|
|
1780
|
-
const toolResult = await this.dispatchToolCall(tc.id, tc.function.name, args, toolCallContext, eventContext);
|
|
1781
|
-
// When ToolSearch returns results, activate deferred tools for subsequent turns
|
|
1782
|
-
if (tc.function.name === "tool_search") {
|
|
1783
|
-
this.activateToolSearchResults(toolResult);
|
|
1784
|
-
}
|
|
1785
|
-
messages.push({ role: "user", content: `Tool result for ${tc.function.name}:\n${toolResult}` });
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
// Max loops reached — return last assistant content or fallback
|
|
1789
|
-
const lastAssistant = [...messages].reverse().find(m => m.role === "assistant");
|
|
1790
|
-
return {
|
|
1791
|
-
output: lastAssistant?.content || "I was unable to complete the request within the allowed tool call limit.",
|
|
1792
|
-
usage,
|
|
1793
|
-
};
|
|
1794
|
-
}
|
|
1795
|
-
/**
|
|
1796
|
-
* Parse ToolSearch result JSON and activate any deferred tools found.
|
|
1797
|
-
* Called after each tool_search execution so the LLM can call found tools on the next turn.
|
|
1798
|
-
*/
|
|
1799
|
-
activateToolSearchResults(toolResult) {
|
|
1800
|
-
try {
|
|
1801
|
-
const parsed = JSON.parse(toolResult);
|
|
1802
|
-
const results = Array.isArray(parsed) ? parsed : null;
|
|
1803
|
-
if (results) {
|
|
1804
|
-
for (const item of results) {
|
|
1805
|
-
if (item && typeof item === "object" && typeof item["name"] === "string") {
|
|
1806
|
-
this.activatedTools.add(item["name"]);
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
catch {
|
|
1812
|
-
// Non-JSON result or unexpected shape — ignore
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
createAgentLoopEventSink(eventContext) {
|
|
1816
|
-
return {
|
|
1817
|
-
emit: async (event) => {
|
|
1818
|
-
if (event.type === "tool_call_started") {
|
|
1819
|
-
const detail = event.inputPreview ? previewActivityText(event.inputPreview) : undefined;
|
|
1820
|
-
this.emitActivity("tool", formatToolActivity("Running", event.toolName, detail), eventContext, event.callId);
|
|
1821
|
-
this.emitEvent({
|
|
1822
|
-
type: "tool_start",
|
|
1823
|
-
toolCallId: event.callId,
|
|
1824
|
-
toolName: event.toolName,
|
|
1825
|
-
args: this.parseAgentLoopPreview(event.inputPreview),
|
|
1826
|
-
...this.eventBase(eventContext),
|
|
1827
|
-
});
|
|
1828
|
-
this.emitEvent({
|
|
1829
|
-
type: "tool_update",
|
|
1830
|
-
toolCallId: event.callId,
|
|
1831
|
-
toolName: event.toolName,
|
|
1832
|
-
status: "running",
|
|
1833
|
-
message: "started",
|
|
1834
|
-
...this.eventBase(eventContext),
|
|
1835
|
-
});
|
|
1836
|
-
return;
|
|
1837
|
-
}
|
|
1838
|
-
if (event.type === "tool_call_finished") {
|
|
1839
|
-
this.emitActivity("tool", formatToolActivity(event.success ? "Finished" : "Failed", event.toolName, event.outputPreview), eventContext, event.callId);
|
|
1840
|
-
this.emitEvent({
|
|
1841
|
-
type: "tool_end",
|
|
1842
|
-
toolCallId: event.callId,
|
|
1843
|
-
toolName: event.toolName,
|
|
1844
|
-
success: event.success,
|
|
1845
|
-
summary: event.outputPreview,
|
|
1846
|
-
durationMs: event.durationMs,
|
|
1847
|
-
...this.eventBase(eventContext),
|
|
1848
|
-
});
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
if (event.type === "assistant_message" && event.phase === "commentary" && event.contentPreview) {
|
|
1852
|
-
this.emitActivity("commentary", previewActivityText(event.contentPreview, 120), eventContext, `commentary:${event.eventId}`);
|
|
1853
|
-
return;
|
|
1854
|
-
}
|
|
1855
|
-
if (event.type === "plan_update") {
|
|
1856
|
-
this.emitActivity("tool", `Updated plan: ${previewActivityText(event.summary)}`, eventContext, `plan:${event.turnId}`);
|
|
1857
|
-
this.emitEvent({
|
|
1858
|
-
type: "tool_update",
|
|
1859
|
-
toolCallId: `plan:${event.turnId}:${event.createdAt}`,
|
|
1860
|
-
toolName: "update_plan",
|
|
1861
|
-
status: "result",
|
|
1862
|
-
message: event.summary,
|
|
1863
|
-
...this.eventBase(eventContext),
|
|
1864
|
-
});
|
|
1865
|
-
return;
|
|
1866
|
-
}
|
|
1867
|
-
if (event.type === "approval_request") {
|
|
1868
|
-
this.emitActivity("tool", formatToolActivity("Running", event.toolName, `awaiting approval: ${event.reason}`), eventContext, event.callId);
|
|
1869
|
-
this.emitEvent({
|
|
1870
|
-
type: "tool_update",
|
|
1871
|
-
toolCallId: event.callId,
|
|
1872
|
-
toolName: event.toolName,
|
|
1873
|
-
status: "awaiting_approval",
|
|
1874
|
-
message: event.reason,
|
|
1875
|
-
...this.eventBase(eventContext),
|
|
1876
|
-
});
|
|
1877
|
-
return;
|
|
1878
|
-
}
|
|
1879
|
-
if (event.type === "approval") {
|
|
1880
|
-
this.emitActivity("tool", formatToolActivity("Finished", event.toolName, `approval ${event.status}: ${event.reason}`), eventContext);
|
|
1881
|
-
this.emitEvent({
|
|
1882
|
-
type: "tool_update",
|
|
1883
|
-
toolCallId: `approval:${event.turnId}:${event.createdAt}`,
|
|
1884
|
-
toolName: event.toolName,
|
|
1885
|
-
status: "result",
|
|
1886
|
-
message: `approval ${event.status}: ${event.reason}`,
|
|
1887
|
-
...this.eventBase(eventContext),
|
|
1888
|
-
});
|
|
1889
|
-
return;
|
|
1890
|
-
}
|
|
1891
|
-
if (event.type === "resumed") {
|
|
1892
|
-
this.emitEvent({
|
|
1893
|
-
type: "tool_update",
|
|
1894
|
-
toolCallId: `resume:${event.turnId}:${event.createdAt}`,
|
|
1895
|
-
toolName: "agentloop_resume",
|
|
1896
|
-
status: "result",
|
|
1897
|
-
message: `resumed ${event.restoredMessages} message(s) from ${event.fromUpdatedAt}`,
|
|
1898
|
-
...this.eventBase(eventContext),
|
|
1899
|
-
});
|
|
1900
|
-
return;
|
|
1901
|
-
}
|
|
1902
|
-
if (event.type === "context_compaction") {
|
|
1903
|
-
this.emitEvent({
|
|
1904
|
-
type: "tool_update",
|
|
1905
|
-
toolCallId: `compaction:${event.turnId}:${event.createdAt}`,
|
|
1906
|
-
toolName: "context_compaction",
|
|
1907
|
-
status: "result",
|
|
1908
|
-
message: `${event.phase} ${event.reason}: ${event.inputMessages} -> ${event.outputMessages}`,
|
|
1909
|
-
...this.eventBase(eventContext),
|
|
1910
|
-
});
|
|
1911
|
-
}
|
|
1912
|
-
},
|
|
1913
|
-
};
|
|
424
|
+
getSessionCwd() {
|
|
425
|
+
return this.sessionCwd;
|
|
1914
426
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
const parsed = JSON.parse(preview);
|
|
1918
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1919
|
-
return parsed;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
catch {
|
|
1923
|
-
// fall through
|
|
1924
|
-
}
|
|
1925
|
-
return preview ? { preview } : {};
|
|
427
|
+
getNativeAgentLoopStatePath() {
|
|
428
|
+
return this.nativeAgentLoopStatePath;
|
|
1926
429
|
}
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
const match = /^\/resume(?:\s+(.+))?$/i.exec(trimmed);
|
|
1930
|
-
if (!match)
|
|
1931
|
-
return null;
|
|
1932
|
-
const selector = match[1]?.trim();
|
|
1933
|
-
return selector ? { selector } : {};
|
|
430
|
+
setSessionExecutionPolicy(policy) {
|
|
431
|
+
this.sessionExecutionPolicy = policy;
|
|
1934
432
|
}
|
|
1935
|
-
async
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
if (!this.isAgentLoopSessionState(raw))
|
|
1940
|
-
return null;
|
|
1941
|
-
if (raw.status === "completed")
|
|
1942
|
-
return null;
|
|
1943
|
-
return {
|
|
1944
|
-
...raw,
|
|
1945
|
-
messages: [...raw.messages],
|
|
1946
|
-
calledTools: [...raw.calledTools],
|
|
1947
|
-
};
|
|
433
|
+
async getSessionExecutionPolicy() {
|
|
434
|
+
const policy = await resolveSessionExecutionPolicy(this.sessionExecutionPolicy, this.sessionCwd);
|
|
435
|
+
this.sessionExecutionPolicy = policy;
|
|
436
|
+
return policy;
|
|
1948
437
|
}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
return false;
|
|
1952
|
-
const candidate = value;
|
|
1953
|
-
return typeof candidate["sessionId"] === "string"
|
|
1954
|
-
&& typeof candidate["traceId"] === "string"
|
|
1955
|
-
&& typeof candidate["turnId"] === "string"
|
|
1956
|
-
&& typeof candidate["goalId"] === "string"
|
|
1957
|
-
&& typeof candidate["cwd"] === "string"
|
|
1958
|
-
&& typeof candidate["modelRef"] === "string"
|
|
1959
|
-
&& Array.isArray(candidate["messages"])
|
|
1960
|
-
&& Array.isArray(candidate["calledTools"])
|
|
1961
|
-
&& typeof candidate["status"] === "string";
|
|
438
|
+
resolveRouteFromIngress(ingress) {
|
|
439
|
+
return standaloneIngressRouter.selectRoute(ingress, getRouteCapabilities(this.deps));
|
|
1962
440
|
}
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
if (!this.deps.registry) {
|
|
1966
|
-
this.emitActivity("tool", formatToolActivity("Failed", name, "No tool registry configured"), eventContext, toolCallId);
|
|
1967
|
-
return JSON.stringify({ error: `No tool registry configured` });
|
|
1968
|
-
}
|
|
1969
|
-
const tool = this.deps.registry.get(name);
|
|
1970
|
-
if (!tool) {
|
|
1971
|
-
this.emitActivity("tool", formatToolActivity("Failed", name, `Unknown tool: ${name}`), eventContext, toolCallId);
|
|
1972
|
-
return JSON.stringify({ error: `Unknown tool: ${name}` });
|
|
1973
|
-
}
|
|
1974
|
-
const startTime = Date.now();
|
|
1975
|
-
try {
|
|
1976
|
-
const parsed = tool.inputSchema.safeParse(args);
|
|
1977
|
-
if (!parsed.success) {
|
|
1978
|
-
this.emitActivity("tool", formatToolActivity("Failed", name, `Invalid input: ${parsed.error.message}`), eventContext, toolCallId);
|
|
1979
|
-
this.emitEvent({
|
|
1980
|
-
type: "tool_end",
|
|
1981
|
-
toolCallId,
|
|
1982
|
-
toolName: name,
|
|
1983
|
-
success: false,
|
|
1984
|
-
summary: `Invalid input: ${parsed.error.message}`,
|
|
1985
|
-
durationMs: Date.now() - startTime,
|
|
1986
|
-
...this.eventBase(eventContext),
|
|
1987
|
-
});
|
|
1988
|
-
return JSON.stringify({ error: `Invalid input: ${parsed.error.message}` });
|
|
1989
|
-
}
|
|
1990
|
-
this.emitEvent({
|
|
1991
|
-
type: "tool_start",
|
|
1992
|
-
toolCallId,
|
|
1993
|
-
toolName: name,
|
|
1994
|
-
args,
|
|
1995
|
-
...this.eventBase(eventContext),
|
|
1996
|
-
});
|
|
1997
|
-
this.emitActivity("tool", formatToolActivity("Running", name, JSON.stringify(args)), eventContext, toolCallId);
|
|
1998
|
-
let result;
|
|
1999
|
-
if (this.deps.toolExecutor) {
|
|
2000
|
-
this.emitEvent({
|
|
2001
|
-
type: "tool_update",
|
|
2002
|
-
toolCallId,
|
|
2003
|
-
toolName: name,
|
|
2004
|
-
status: "running",
|
|
2005
|
-
message: "running",
|
|
2006
|
-
...this.eventBase(eventContext),
|
|
2007
|
-
});
|
|
2008
|
-
this.deps.onToolStart?.(name, args);
|
|
2009
|
-
result = await this.deps.toolExecutor.execute(name, parsed.data, context);
|
|
2010
|
-
}
|
|
2011
|
-
else {
|
|
2012
|
-
// Gate: check permissions before execution
|
|
2013
|
-
const permResult = await tool.checkPermissions(parsed.data, context);
|
|
2014
|
-
if (permResult.status === "denied") {
|
|
2015
|
-
this.emitEvent({
|
|
2016
|
-
type: "tool_end",
|
|
2017
|
-
toolCallId,
|
|
2018
|
-
toolName: name,
|
|
2019
|
-
success: false,
|
|
2020
|
-
summary: permResult.reason,
|
|
2021
|
-
durationMs: Date.now() - startTime,
|
|
2022
|
-
...this.eventBase(eventContext),
|
|
2023
|
-
});
|
|
2024
|
-
return `Tool ${name} denied: ${permResult.reason}`;
|
|
2025
|
-
}
|
|
2026
|
-
if (permResult.status === "needs_approval") {
|
|
2027
|
-
this.emitActivity("tool", formatToolActivity("Running", name, `awaiting approval: ${permResult.reason}`), eventContext, toolCallId);
|
|
2028
|
-
this.emitEvent({
|
|
2029
|
-
type: "tool_update",
|
|
2030
|
-
toolCallId,
|
|
2031
|
-
toolName: name,
|
|
2032
|
-
status: "awaiting_approval",
|
|
2033
|
-
message: permResult.reason,
|
|
2034
|
-
...this.eventBase(eventContext),
|
|
2035
|
-
});
|
|
2036
|
-
const approved = await context.approvalFn({
|
|
2037
|
-
toolName: name,
|
|
2038
|
-
input: parsed.data,
|
|
2039
|
-
reason: permResult.reason,
|
|
2040
|
-
permissionLevel: tool.metadata.permissionLevel,
|
|
2041
|
-
isDestructive: tool.metadata.isDestructive,
|
|
2042
|
-
reversibility: "unknown",
|
|
2043
|
-
});
|
|
2044
|
-
if (!approved) {
|
|
2045
|
-
this.emitEvent({
|
|
2046
|
-
type: "tool_end",
|
|
2047
|
-
toolCallId,
|
|
2048
|
-
toolName: name,
|
|
2049
|
-
success: false,
|
|
2050
|
-
summary: `Not approved: ${permResult.reason}`,
|
|
2051
|
-
durationMs: Date.now() - startTime,
|
|
2052
|
-
...this.eventBase(eventContext),
|
|
2053
|
-
});
|
|
2054
|
-
return `Tool ${name} not approved: ${permResult.reason}`;
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
this.emitEvent({
|
|
2058
|
-
type: "tool_update",
|
|
2059
|
-
toolCallId,
|
|
2060
|
-
toolName: name,
|
|
2061
|
-
status: "running",
|
|
2062
|
-
message: "running",
|
|
2063
|
-
...this.eventBase(eventContext),
|
|
2064
|
-
});
|
|
2065
|
-
this.deps.onToolStart?.(name, args);
|
|
2066
|
-
result = await tool.call(parsed.data, context);
|
|
2067
|
-
}
|
|
2068
|
-
const durationMs = Date.now() - startTime;
|
|
2069
|
-
this.deps.onToolEnd?.(name, { success: result.success, summary: result.summary || '...', durationMs });
|
|
2070
|
-
this.emitActivity("tool", formatToolActivity(result.success ? "Finished" : "Failed", name, result.summary || "..."), eventContext, toolCallId);
|
|
2071
|
-
this.emitEvent({
|
|
2072
|
-
type: "tool_update",
|
|
2073
|
-
toolCallId,
|
|
2074
|
-
toolName: name,
|
|
2075
|
-
status: "result",
|
|
2076
|
-
message: result.summary || "...",
|
|
2077
|
-
...this.eventBase(eventContext),
|
|
2078
|
-
});
|
|
2079
|
-
this.emitEvent({
|
|
2080
|
-
type: "tool_end",
|
|
2081
|
-
toolCallId,
|
|
2082
|
-
toolName: name,
|
|
2083
|
-
success: result.success,
|
|
2084
|
-
summary: result.summary || "...",
|
|
2085
|
-
durationMs,
|
|
2086
|
-
...this.eventBase(eventContext),
|
|
2087
|
-
});
|
|
2088
|
-
// Prefer structured data (JSON) over plain summary so the LLM gets actionable content
|
|
2089
|
-
return result.data != null ? JSON.stringify(result.data) : (result.summary ?? "(no result)");
|
|
2090
|
-
}
|
|
2091
|
-
catch (err) {
|
|
2092
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2093
|
-
const durationMs = Date.now() - startTime;
|
|
2094
|
-
this.deps.onToolEnd?.(name, { success: false, summary: message, durationMs });
|
|
2095
|
-
this.emitActivity("tool", formatToolActivity("Failed", name, message), eventContext, toolCallId);
|
|
2096
|
-
this.emitEvent({
|
|
2097
|
-
type: "tool_end",
|
|
2098
|
-
toolCallId,
|
|
2099
|
-
toolName: name,
|
|
2100
|
-
success: false,
|
|
2101
|
-
summary: message,
|
|
2102
|
-
durationMs,
|
|
2103
|
-
...this.eventBase(eventContext),
|
|
2104
|
-
});
|
|
2105
|
-
return JSON.stringify({ error: `Tool ${name} failed: ${message}` });
|
|
2106
|
-
}
|
|
441
|
+
resolveRouteFromInput(input, runtimeControlContext) {
|
|
442
|
+
return this.resolveRouteFromIngress(buildStandaloneIngressMessageFromContext(input, runtimeControlContext, this.deps));
|
|
2107
443
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
if (llmClient.sendMessageStream) {
|
|
2111
|
-
const response = await llmClient.sendMessageStream(messages, options, {
|
|
2112
|
-
onTextDelta: (delta) => {
|
|
2113
|
-
streamed = true;
|
|
2114
|
-
this.pushAssistantDelta(delta, assistantBuffer, eventContext);
|
|
2115
|
-
},
|
|
2116
|
-
});
|
|
2117
|
-
if (!streamed && response.content) {
|
|
2118
|
-
this.pushAssistantDelta(response.content, assistantBuffer, eventContext);
|
|
2119
|
-
}
|
|
2120
|
-
return response;
|
|
2121
|
-
}
|
|
2122
|
-
const response = await llmClient.sendMessage(messages, options);
|
|
2123
|
-
if (response.content) {
|
|
2124
|
-
this.pushAssistantDelta(response.content, assistantBuffer, eventContext);
|
|
2125
|
-
}
|
|
2126
|
-
return response;
|
|
444
|
+
loadedSessionToChatSession(session) {
|
|
445
|
+
return loadedSessionToChatSession(session);
|
|
2127
446
|
}
|
|
2128
|
-
|
|
447
|
+
routeHost() {
|
|
2129
448
|
return {
|
|
2130
|
-
|
|
2131
|
-
|
|
449
|
+
deps: this.deps,
|
|
450
|
+
eventBridge: this.eventBridge,
|
|
451
|
+
activatedTools: this.activatedTools,
|
|
452
|
+
getConversationSessionId: () => this.history?.getSessionId() ?? null,
|
|
453
|
+
getSessionCwd: () => this.sessionCwd,
|
|
454
|
+
getNativeAgentLoopStatePath: () => this.nativeAgentLoopStatePath,
|
|
455
|
+
getSessionExecutionPolicy: () => this.getSessionExecutionPolicy(),
|
|
456
|
+
setSessionExecutionPolicy: (policy) => { this.sessionExecutionPolicy = policy; },
|
|
2132
457
|
};
|
|
2133
458
|
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
emitEvent(event) {
|
|
2138
|
-
const handler = this.onEvent ?? this.deps.onEvent;
|
|
2139
|
-
handler?.(event);
|
|
2140
|
-
}
|
|
2141
|
-
emitActivity(kind, message, eventContext, sourceId) {
|
|
2142
|
-
if (!message.trim())
|
|
2143
|
-
return;
|
|
2144
|
-
this.emitEvent({
|
|
2145
|
-
type: "activity",
|
|
2146
|
-
kind,
|
|
2147
|
-
message,
|
|
2148
|
-
...(sourceId ? { sourceId } : {}),
|
|
2149
|
-
transient: true,
|
|
2150
|
-
...this.eventBase(eventContext),
|
|
2151
|
-
});
|
|
2152
|
-
}
|
|
2153
|
-
pushAssistantDelta(delta, assistantBuffer, eventContext) {
|
|
2154
|
-
if (!delta)
|
|
2155
|
-
return;
|
|
2156
|
-
assistantBuffer.text += delta;
|
|
2157
|
-
this.emitEvent({
|
|
2158
|
-
type: "assistant_delta",
|
|
2159
|
-
delta,
|
|
2160
|
-
text: assistantBuffer.text,
|
|
2161
|
-
...this.eventBase(eventContext),
|
|
2162
|
-
});
|
|
2163
|
-
}
|
|
2164
|
-
emitLifecycleEndEvent(status, elapsedMs, eventContext, persisted) {
|
|
2165
|
-
this.emitEvent({
|
|
2166
|
-
type: "lifecycle_end",
|
|
2167
|
-
status,
|
|
2168
|
-
elapsedMs,
|
|
2169
|
-
persisted,
|
|
2170
|
-
...this.eventBase(eventContext),
|
|
2171
|
-
});
|
|
2172
|
-
}
|
|
2173
|
-
emitLifecycleErrorEvent(error, partialText, eventContext) {
|
|
2174
|
-
this.emitEvent({
|
|
2175
|
-
type: "lifecycle_error",
|
|
2176
|
-
error,
|
|
2177
|
-
partialText,
|
|
2178
|
-
persisted: false,
|
|
2179
|
-
...this.eventBase(eventContext),
|
|
2180
|
-
});
|
|
2181
|
-
}
|
|
2182
|
-
/** Build a ToolCallContext from ChatRunnerDeps for tool dispatch. */
|
|
2183
|
-
async getSessionExecutionPolicy() {
|
|
2184
|
-
if (this.sessionExecutionPolicy)
|
|
2185
|
-
return this.sessionExecutionPolicy;
|
|
2186
|
-
const config = await loadProviderConfig({ saveMigration: false });
|
|
2187
|
-
this.sessionExecutionPolicy = resolveExecutionPolicy({
|
|
2188
|
-
workspaceRoot: this.sessionCwd ?? process.cwd(),
|
|
2189
|
-
security: config.agent_loop?.security,
|
|
2190
|
-
});
|
|
2191
|
-
return this.sessionExecutionPolicy;
|
|
459
|
+
providerConfigBaseDir() {
|
|
460
|
+
const stateManager = this.deps.stateManager;
|
|
461
|
+
return typeof stateManager.getBaseDir === "function" ? stateManager.getBaseDir() : getPulseedDirPath();
|
|
2192
462
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
return false;
|
|
2205
|
-
},
|
|
2206
|
-
executionPolicy,
|
|
2207
|
-
};
|
|
463
|
+
finalizeNonPersistentResult(result, eventContext) {
|
|
464
|
+
if (result.output) {
|
|
465
|
+
this.eventBridge.emitEvent({
|
|
466
|
+
type: "assistant_final",
|
|
467
|
+
text: result.output,
|
|
468
|
+
persisted: false,
|
|
469
|
+
...this.eventBridge.eventBase(eventContext),
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
this.eventBridge.emitLifecycleEndEvent(result.success ? "completed" : "error", result.elapsed_ms, eventContext, false);
|
|
473
|
+
return result;
|
|
2208
474
|
}
|
|
2209
475
|
}
|
|
476
|
+
void COMMAND_HELP;
|
|
477
|
+
void formatRoute;
|
|
2210
478
|
//# sourceMappingURL=chat-runner.js.map
|