@getpaseo/server 0.1.61 → 0.1.63
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/README.md +4 -0
- package/dist/server/client/daemon-client-runtime-metrics.d.ts +6 -6
- package/dist/server/client/daemon-client-runtime-metrics.d.ts.map +1 -1
- package/dist/server/client/daemon-client-transport-types.d.ts +13 -13
- package/dist/server/client/daemon-client-transport-types.d.ts.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.d.ts +1 -1
- package/dist/server/client/daemon-client-websocket-transport.d.ts.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.js +5 -4
- package/dist/server/client/daemon-client-websocket-transport.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +59 -37
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +62 -17
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-loading.d.ts.map +1 -1
- package/dist/server/server/agent/agent-loading.js +5 -3
- package/dist/server/server/agent/agent-loading.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +45 -19
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +393 -290
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.d.ts +6 -6
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +46 -38
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts +4 -6
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +59 -65
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-response-loop.d.ts +4 -4
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -1
- package/dist/server/server/agent/agent-response-loop.js +58 -45
- package/dist/server/server/agent/agent-response-loop.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +43 -40
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +2 -2
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
- package/dist/server/server/agent/agent-storage.js +29 -36
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/agent-stream-coalescer.d.ts +6 -6
- package/dist/server/server/agent/agent-stream-coalescer.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store-types.d.ts +10 -10
- package/dist/server/server/agent/agent-timeline-store-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.d.ts +2 -2
- package/dist/server/server/agent/agent-timeline-store.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.js +85 -64
- package/dist/server/server/agent/agent-timeline-store.js.map +1 -1
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +185 -148
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/mcp-shared.d.ts +9 -2
- package/dist/server/server/agent/mcp-shared.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-shared.js +2 -0
- package/dist/server/server/agent/mcp-shared.js.map +1 -1
- package/dist/server/server/agent/model-resolver.d.ts +2 -2
- package/dist/server/server/agent/model-resolver.d.ts.map +1 -1
- package/dist/server/server/agent/model-resolver.js +9 -5
- package/dist/server/server/agent/model-resolver.js.map +1 -1
- package/dist/server/server/agent/provider-launch-config.d.ts +28 -17
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js +20 -9
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/provider-registry.d.ts +4 -2
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.js +24 -21
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +6 -5
- package/dist/server/server/agent/provider-snapshot-manager.d.ts.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +40 -31
- package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts +11 -12
- package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.js +148 -122
- package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +2 -0
- package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js +47 -45
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js.map +1 -1
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +2 -2
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +10 -5
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +11 -2
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +2 -2
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +20 -13
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts +20 -8
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +610 -460
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +2 -2
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +2 -2
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +49 -44
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +27 -8
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +564 -492
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +2 -2
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +58 -47
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +2 -2
- package/dist/server/server/agent/providers/copilot-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/diagnostic-utils.d.ts +3 -3
- package/dist/server/server/agent/providers/diagnostic-utils.d.ts.map +1 -1
- package/dist/server/server/agent/providers/diagnostic-utils.js +82 -9
- package/dist/server/server/agent/providers/diagnostic-utils.js.map +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +2 -2
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +2 -2
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts +2 -2
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +385 -360
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/pi-direct-agent.d.ts +1 -0
- package/dist/server/server/agent/providers/pi-direct-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi-direct-agent.js +109 -140
- package/dist/server/server/agent/providers/pi-direct-agent.js.map +1 -1
- package/dist/server/server/agent/providers/test-utils/session-stream-adapter.d.ts.map +1 -1
- package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js +3 -1
- package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +3 -3
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +102 -73
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +2 -2
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -1
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -1
- package/dist/server/server/agent/stt-manager.js +63 -53
- package/dist/server/server/agent/stt-manager.js.map +1 -1
- package/dist/server/server/agent/timeline-projection.d.ts +6 -6
- package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
- package/dist/server/server/agent/timeline-projection.js +11 -6
- package/dist/server/server/agent/timeline-projection.js.map +1 -1
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -1
- package/dist/server/server/agent/tts-manager.js +1 -0
- package/dist/server/server/agent/tts-manager.js.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts +2 -2
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
- package/dist/server/server/bootstrap.d.ts +4 -4
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +493 -485
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/chat/chat-service.d.ts +1 -1
- package/dist/server/server/chat/chat-service.d.ts.map +1 -1
- package/dist/server/server/chat/chat-service.js +3 -3
- package/dist/server/server/chat/chat-service.js.map +1 -1
- package/dist/server/server/checkout-diff-manager.d.ts +2 -2
- package/dist/server/server/checkout-diff-manager.d.ts.map +1 -1
- package/dist/server/server/checkout-git-utils.d.ts +5 -3
- package/dist/server/server/checkout-git-utils.d.ts.map +1 -1
- package/dist/server/server/checkout-git-utils.js +1 -2
- package/dist/server/server/checkout-git-utils.js.map +1 -1
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +68 -39
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/connection-offer.d.ts +2 -2
- package/dist/server/server/connection-offer.d.ts.map +1 -1
- package/dist/server/server/daemon-config-store.d.ts +5 -3
- package/dist/server/server/daemon-config-store.d.ts.map +1 -1
- package/dist/server/server/daemon-config-store.js +26 -0
- package/dist/server/server/daemon-config-store.js.map +1 -1
- package/dist/server/server/daemon-keypair.d.ts +2 -2
- package/dist/server/server/daemon-keypair.d.ts.map +1 -1
- package/dist/server/server/editor-targets.d.ts +4 -4
- package/dist/server/server/editor-targets.d.ts.map +1 -1
- package/dist/server/server/editor-targets.js +11 -15
- package/dist/server/server/editor-targets.js.map +1 -1
- package/dist/server/server/exports.d.ts +3 -3
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +1 -3
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/file-download/token-store.d.ts +4 -4
- package/dist/server/server/file-download/token-store.d.ts.map +1 -1
- package/dist/server/server/index.js +16 -12
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/logger.d.ts +4 -4
- package/dist/server/server/logger.d.ts.map +1 -1
- package/dist/server/server/logger.js +26 -20
- package/dist/server/server/logger.js.map +1 -1
- package/dist/server/server/loop/rpc-schemas.d.ts +52 -52
- package/dist/server/server/loop-service.d.ts +13 -12
- package/dist/server/server/loop-service.d.ts.map +1 -1
- package/dist/server/server/loop-service.js +22 -18
- package/dist/server/server/loop-service.js.map +1 -1
- package/dist/server/server/package-version.d.ts +2 -2
- package/dist/server/server/package-version.d.ts.map +1 -1
- package/dist/server/server/package-version.js +19 -17
- package/dist/server/server/package-version.js.map +1 -1
- package/dist/server/server/pairing-offer.d.ts +2 -2
- package/dist/server/server/pairing-offer.d.ts.map +1 -1
- package/dist/server/server/paseo-env.d.ts +9 -0
- package/dist/server/server/paseo-env.d.ts.map +1 -0
- package/dist/server/server/paseo-env.js +70 -0
- package/dist/server/server/paseo-env.js.map +1 -0
- package/dist/server/server/paseo-worktree-archive-service.d.ts +4 -4
- package/dist/server/server/paseo-worktree-archive-service.d.ts.map +1 -1
- package/dist/server/server/paseo-worktree-archive-service.js +11 -11
- package/dist/server/server/paseo-worktree-archive-service.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +62 -62
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +4 -4
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/persistence-hooks.d.ts +8 -9
- package/dist/server/server/persistence-hooks.d.ts.map +1 -1
- package/dist/server/server/persistence-hooks.js +4 -12
- package/dist/server/server/persistence-hooks.js.map +1 -1
- package/dist/server/server/pid-lock.js.map +1 -1
- package/dist/server/server/push/push-service.d.ts.map +1 -1
- package/dist/server/server/push/push-service.js +1 -3
- package/dist/server/server/push/push-service.js.map +1 -1
- package/dist/server/server/relay-transport.d.ts +8 -8
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +27 -16
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/schedule/service.d.ts.map +1 -1
- package/dist/server/server/schedule/service.js +2 -2
- package/dist/server/server/schedule/service.js.map +1 -1
- package/dist/server/server/script-health-monitor.d.ts.map +1 -1
- package/dist/server/server/script-health-monitor.js +7 -6
- package/dist/server/server/script-health-monitor.js.map +1 -1
- package/dist/server/server/script-proxy.js +1 -1
- package/dist/server/server/script-proxy.js.map +1 -1
- package/dist/server/server/script-status-projection.d.ts +4 -4
- package/dist/server/server/script-status-projection.d.ts.map +1 -1
- package/dist/server/server/script-status-projection.js +54 -44
- package/dist/server/server/script-status-projection.js.map +1 -1
- package/dist/server/server/server-id.d.ts +4 -4
- package/dist/server/server/server-id.d.ts.map +1 -1
- package/dist/server/server/session.d.ts +50 -19
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +1116 -783
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/audio.js +1 -1
- package/dist/server/server/speech/audio.js.map +1 -1
- package/dist/server/server/speech/providers/local/config.d.ts +6 -6
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/config.js +41 -16
- package/dist/server/server/speech/providers/local/config.js.map +1 -1
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts +2 -2
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +42 -19
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.d.ts +4 -4
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.js +108 -77
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +1 -4
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +19 -19
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +28 -7
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts +23 -4
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +35 -28
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts +5 -5
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +7 -7
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +5 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +3 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +3 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +10 -4
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +4 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +2 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +18 -11
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -1
- package/dist/server/server/speech/providers/openai/config.d.ts +2 -2
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/config.js +58 -31
- package/dist/server/server/speech/providers/openai/config.js.map +1 -1
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +2 -2
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.d.ts +4 -4
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.js +37 -32
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -1
- package/dist/server/server/speech/providers/openai/stt.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/stt.js +4 -3
- package/dist/server/server/speech/providers/openai/stt.js.map +1 -1
- package/dist/server/server/speech/providers/openai/tts.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/tts.js +3 -2
- package/dist/server/server/speech/providers/openai/tts.js.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.js +46 -17
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -1
- package/dist/server/server/speech/speech-provider.d.ts +2 -2
- package/dist/server/server/speech/speech-provider.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.d.ts +6 -6
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.js +17 -17
- package/dist/server/server/speech/speech-runtime.js.map +1 -1
- package/dist/server/server/speech/speech-types.d.ts +2 -2
- package/dist/server/server/speech/speech-types.d.ts.map +1 -1
- package/dist/server/server/speech/turn-detection-provider.d.ts +2 -2
- package/dist/server/server/speech/turn-detection-provider.d.ts.map +1 -1
- package/dist/server/server/utils/diff-highlighter.d.ts +0 -3
- package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -1
- package/dist/server/server/utils/diff-highlighter.js +67 -66
- package/dist/server/server/utils/diff-highlighter.js.map +1 -1
- package/dist/server/server/voice/voice-turn-controller.d.ts.map +1 -1
- package/dist/server/server/voice/voice-turn-controller.js +1 -0
- package/dist/server/server/voice/voice-turn-controller.js.map +1 -1
- package/dist/server/server/voice-types.d.ts +2 -2
- package/dist/server/server/voice-types.d.ts.map +1 -1
- package/dist/server/server/websocket-server.d.ts +33 -23
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +349 -241
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-git-metadata.d.ts +2 -2
- package/dist/server/server/workspace-git-metadata.d.ts.map +1 -1
- package/dist/server/server/workspace-git-metadata.js +2 -32
- package/dist/server/server/workspace-git-metadata.js.map +1 -1
- package/dist/server/server/workspace-git-service.d.ts +17 -13
- package/dist/server/server/workspace-git-service.d.ts.map +1 -1
- package/dist/server/server/workspace-git-service.js +232 -140
- package/dist/server/server/workspace-git-service.js.map +1 -1
- package/dist/server/server/workspace-reconciliation-service.d.ts +5 -4
- package/dist/server/server/workspace-reconciliation-service.d.ts.map +1 -1
- package/dist/server/server/workspace-reconciliation-service.js +82 -82
- package/dist/server/server/workspace-reconciliation-service.js.map +1 -1
- package/dist/server/server/workspace-registry-bootstrap.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-bootstrap.js +40 -33
- package/dist/server/server/workspace-registry-bootstrap.js.map +1 -1
- package/dist/server/server/workspace-registry-model.d.ts +19 -6
- package/dist/server/server/workspace-registry-model.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-model.js +35 -21
- package/dist/server/server/workspace-registry-model.js.map +1 -1
- package/dist/server/server/workspace-registry.d.ts +2 -2
- package/dist/server/server/workspace-script-runtime-store.d.ts +2 -2
- package/dist/server/server/workspace-script-runtime-store.d.ts.map +1 -1
- package/dist/server/server/workspace-service-env.js +3 -3
- package/dist/server/server/workspace-service-env.js.map +1 -1
- package/dist/server/server/worktree-bootstrap.d.ts +4 -4
- package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
- package/dist/server/server/worktree-bootstrap.js +95 -67
- package/dist/server/server/worktree-bootstrap.js.map +1 -1
- package/dist/server/server/worktree-session.d.ts +8 -8
- package/dist/server/server/worktree-session.d.ts.map +1 -1
- package/dist/server/server/worktree-session.js +27 -19
- package/dist/server/server/worktree-session.js.map +1 -1
- package/dist/server/services/github-service.d.ts +2 -7
- package/dist/server/services/github-service.d.ts.map +1 -1
- package/dist/server/services/github-service.js +156 -157
- package/dist/server/services/github-service.js.map +1 -1
- package/dist/server/shared/agent-attention-notification.d.ts +9 -8
- package/dist/server/shared/agent-attention-notification.d.ts.map +1 -1
- package/dist/server/shared/agent-attention-notification.js +27 -17
- package/dist/server/shared/agent-attention-notification.js.map +1 -1
- package/dist/server/shared/daemon-endpoints.d.ts +2 -2
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
- package/dist/server/shared/daemon-endpoints.js +17 -2
- package/dist/server/shared/daemon-endpoints.js.map +1 -1
- package/dist/server/shared/messages.d.ts +21962 -3049
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +79 -2
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/terminal-stream-protocol.d.ts +2 -2
- package/dist/server/shared/terminal-stream-protocol.d.ts.map +1 -1
- package/dist/server/shared/tool-call-display.d.ts +2 -2
- package/dist/server/shared/tool-call-display.d.ts.map +1 -1
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
- package/dist/server/terminal/terminal-manager.js +1 -3
- package/dist/server/terminal/terminal-manager.js.map +1 -1
- package/dist/server/terminal/terminal-output-coalescer.d.ts +6 -6
- package/dist/server/terminal/terminal-output-coalescer.d.ts.map +1 -1
- package/dist/server/terminal/terminal.d.ts +3 -2
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +57 -19
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +13 -12
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +416 -282
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/directory-suggestions.js +12 -33
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/server/utils/executable.d.ts +1 -14
- package/dist/server/utils/executable.d.ts.map +1 -1
- package/dist/server/utils/executable.js +13 -49
- package/dist/server/utils/executable.js.map +1 -1
- package/dist/server/utils/github-remote.d.ts +13 -0
- package/dist/server/utils/github-remote.d.ts.map +1 -0
- package/dist/server/utils/github-remote.js +128 -0
- package/dist/server/utils/github-remote.js.map +1 -0
- package/dist/server/utils/paseo-config-file.d.ts +30 -0
- package/dist/server/utils/paseo-config-file.d.ts.map +1 -0
- package/dist/server/utils/paseo-config-file.js +90 -0
- package/dist/server/utils/paseo-config-file.js.map +1 -0
- package/dist/server/utils/paseo-config-schema.d.ts +290 -0
- package/dist/server/utils/paseo-config-schema.d.ts.map +1 -0
- package/dist/server/utils/paseo-config-schema.js +60 -0
- package/dist/server/utils/paseo-config-schema.js.map +1 -0
- package/dist/server/utils/project-icon.d.ts.map +1 -1
- package/dist/server/utils/project-icon.js +84 -109
- package/dist/server/utils/project-icon.js.map +1 -1
- package/dist/server/utils/promise-timeout.d.ts +2 -2
- package/dist/server/utils/promise-timeout.d.ts.map +1 -1
- package/dist/server/utils/run-git-command.d.ts +3 -1
- package/dist/server/utils/run-git-command.d.ts.map +1 -1
- package/dist/server/utils/run-git-command.js +10 -1
- package/dist/server/utils/run-git-command.js.map +1 -1
- package/dist/server/utils/script-hostname.d.ts +2 -2
- package/dist/server/utils/script-hostname.d.ts.map +1 -1
- package/dist/server/utils/spawn.d.ts +10 -3
- package/dist/server/utils/spawn.d.ts.map +1 -1
- package/dist/server/utils/spawn.js +30 -5
- package/dist/server/utils/spawn.js.map +1 -1
- package/dist/server/utils/windows-command.d.ts +15 -0
- package/dist/server/utils/windows-command.d.ts.map +1 -0
- package/dist/server/utils/windows-command.js +37 -0
- package/dist/server/utils/windows-command.js.map +1 -0
- package/dist/server/utils/worktree.d.ts +10 -7
- package/dist/server/utils/worktree.d.ts.map +1 -1
- package/dist/server/utils/worktree.js +64 -55
- package/dist/server/utils/worktree.js.map +1 -1
- package/dist/src/server/pid-lock.js.map +1 -1
- package/package.json +15 -20
- package/dist/server/server/agent/llm-openai.d.ts +0 -7
- package/dist/server/server/agent/llm-openai.d.ts.map +0 -1
- package/dist/server/server/agent/llm-openai.js +0 -8
- package/dist/server/server/agent/llm-openai.js.map +0 -1
- package/dist/server/server/agent/orchestrator.d.ts +0 -12
- package/dist/server/server/agent/orchestrator.d.ts.map +0 -1
- package/dist/server/server/agent/orchestrator.js +0 -12
- package/dist/server/server/agent/orchestrator.js.map +0 -1
- package/dist/server/server/types.d.ts +0 -5
- package/dist/server/server/types.d.ts.map +0 -1
- package/dist/server/server/types.js +0 -3
- package/dist/server/server/types.js.map +0 -1
- package/dist/server/server/workspace-registry.test-helpers.d.ts +0 -37
- package/dist/server/server/workspace-registry.test-helpers.d.ts.map +0 -1
- package/dist/server/server/workspace-registry.test-helpers.js +0 -121
- package/dist/server/server/workspace-registry.test-helpers.js.map +0 -1
|
@@ -2,7 +2,8 @@ import equal from "fast-deep-equal";
|
|
|
2
2
|
import { v4 as uuidv4 } from "uuid";
|
|
3
3
|
import { TTLCache } from "@isaacs/ttlcache";
|
|
4
4
|
import pMemoize from "p-memoize";
|
|
5
|
-
import {
|
|
5
|
+
import { realpathSync } from "node:fs";
|
|
6
|
+
import { basename, resolve, sep } from "path";
|
|
6
7
|
import { homedir } from "node:os";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
import { isLegacyEditorTargetId, serializeAgentStreamEvent, } from "./messages.js";
|
|
@@ -16,7 +17,7 @@ import { isPaseoDictationDebugEnabled } from "./agent/recordings-debug.js";
|
|
|
16
17
|
import { listAvailableEditorTargets, openInEditorTarget } from "./editor-targets.js";
|
|
17
18
|
import { DictationStreamManager, } from "./dictation/dictation-stream-manager.js";
|
|
18
19
|
import { createVoiceTurnController, } from "./voice/voice-turn-controller.js";
|
|
19
|
-
import { buildConfigOverrides, extractTimestamps, toAgentPersistenceHandle, } from "./persistence-hooks.js";
|
|
20
|
+
import { buildConfigOverrides, extractTimestamps, isStoredAgentProviderAvailable, toAgentPersistenceHandle, } from "./persistence-hooks.js";
|
|
20
21
|
import { ensureAgentLoaded } from "./agent/agent-loading.js";
|
|
21
22
|
import { sendPromptToAgent, unarchiveAgentState } from "./agent/mcp-shared.js";
|
|
22
23
|
import { experimental_createMCPClient } from "ai";
|
|
@@ -24,6 +25,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
24
25
|
import { buildWorkspaceScriptPayloads } from "./script-status-projection.js";
|
|
25
26
|
import { deriveProjectSlug } from "./workspace-git-metadata.js";
|
|
26
27
|
import { spawnWorkspaceScript } from "./worktree-bootstrap.js";
|
|
28
|
+
import { applyMutableProviderConfigToOverrides } from "./daemon-config-store.js";
|
|
27
29
|
import { buildProviderRegistry } from "./agent/provider-registry.js";
|
|
28
30
|
import { resolveSnapshotCwd } from "./agent/provider-snapshot-manager.js";
|
|
29
31
|
import { scheduleAgentMetadataGeneration } from "./agent/agent-metadata-generator.js";
|
|
@@ -32,11 +34,12 @@ import { MAX_EXPLICIT_AGENT_TITLE_CHARS } from "./agent/agent-title-limits.js";
|
|
|
32
34
|
import { appendTimelineItemIfAgentKnown, emitLiveTimelineItemIfAgentKnown, } from "./agent/timeline-append.js";
|
|
33
35
|
import { projectTimelineRows, selectTimelineWindowByProjectedLimit, } from "./agent/timeline-projection.js";
|
|
34
36
|
import { DEFAULT_STRUCTURED_GENERATION_PROVIDERS, StructuredAgentFallbackError, StructuredAgentResponseError, generateStructuredAgentResponseWithFallback, } from "./agent/agent-response-loop.js";
|
|
35
|
-
import { checkoutLiteFromGitSnapshot, normalizeWorkspaceId as normalizePersistedWorkspaceId, deriveProjectGroupingName,
|
|
37
|
+
import { checkoutLiteFromGitSnapshot, normalizeWorkspaceId as normalizePersistedWorkspaceId, deriveProjectGroupingName, classifyDirectoryForProjectMembership, deriveWorkspaceDisplayName, } from "./workspace-registry-model.js";
|
|
36
38
|
import { createPersistedProjectRecord, createPersistedWorkspaceRecord, } from "./workspace-registry.js";
|
|
37
39
|
import { buildVoiceModeSystemPrompt, stripVoiceModeSystemPrompt, wrapSpokenInput, } from "./voice-config.js";
|
|
38
40
|
import { isVoicePermissionAllowed } from "./voice-permission-policy.js";
|
|
39
41
|
import { listDirectoryEntries, readExplorerFile, getDownloadableFileInfo, } from "./file-explorer/service.js";
|
|
42
|
+
import { readPaseoConfigForEdit, writePaseoConfigForEdit, } from "../utils/paseo-config-file.js";
|
|
40
43
|
import { runAsyncWorktreeBootstrap } from "./worktree-bootstrap.js";
|
|
41
44
|
import { archivePersistedWorkspaceRecord } from "./workspace-archive-service.js";
|
|
42
45
|
import { WorkspaceReconciliationService } from "./workspace-reconciliation-service.js";
|
|
@@ -57,13 +60,98 @@ import { assertSafeGitRef as assertWorktreeSafeGitRef, buildAgentSessionConfig a
|
|
|
57
60
|
import { killTerminalsUnderPath as killWorktreeTerminalsUnderPath } from "./paseo-worktree-archive-service.js";
|
|
58
61
|
import { toWorktreeWireError } from "./worktree-errors.js";
|
|
59
62
|
const MAX_INITIAL_AGENT_TITLE_CHARS = Math.min(60, MAX_EXPLICIT_AGENT_TITLE_CHARS);
|
|
60
|
-
const
|
|
63
|
+
const WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY = "__removed__";
|
|
64
|
+
async function resolveKnownProjectRootForConfig(input) {
|
|
65
|
+
const requestedRoot = canonicalizeConfigRoot(input.repoRoot);
|
|
66
|
+
const projects = await input.projectRegistry.list();
|
|
67
|
+
for (const project of projects) {
|
|
68
|
+
if (project.archivedAt !== null) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const projectRoot = canonicalizeConfigRoot(project.rootPath);
|
|
72
|
+
if (requestedRoot === projectRoot) {
|
|
73
|
+
return projectRoot;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
function canonicalizeConfigRoot(repoRoot) {
|
|
79
|
+
const resolved = resolve(repoRoot);
|
|
80
|
+
try {
|
|
81
|
+
return stripTrailingPathSeparators(realpathSync(resolved));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return stripTrailingPathSeparators(resolved);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function stripTrailingPathSeparators(path) {
|
|
88
|
+
let normalized = path;
|
|
89
|
+
while (normalized.length > 1 && normalized.endsWith(sep)) {
|
|
90
|
+
normalized = normalized.slice(0, -1);
|
|
91
|
+
}
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
61
94
|
// TODO: Remove once all app store clients are on >=0.1.45 and understand arbitrary provider strings.
|
|
62
95
|
// Clients before 0.1.45 validate providers with z.enum(["claude", "codex", "opencode"]) and reject
|
|
63
96
|
// the entire session message if they encounter an unknown provider.
|
|
64
97
|
const LEGACY_PROVIDER_IDS = new Set(["claude", "codex", "opencode"]);
|
|
65
98
|
const MIN_VERSION_ALL_PROVIDERS = "0.1.45";
|
|
66
99
|
const MIN_VERSION_FLEXIBLE_EDITOR_IDS = "0.1.50";
|
|
100
|
+
function errorToFriendlyMessage(error) {
|
|
101
|
+
if (error instanceof Error)
|
|
102
|
+
return error.message;
|
|
103
|
+
if (typeof error === "string")
|
|
104
|
+
return error;
|
|
105
|
+
return "Unknown error";
|
|
106
|
+
}
|
|
107
|
+
function resolveSubscriptionId(subscribe, requestedSubscriptionId) {
|
|
108
|
+
if (!subscribe)
|
|
109
|
+
return null;
|
|
110
|
+
if (requestedSubscriptionId && requestedSubscriptionId.length > 0) {
|
|
111
|
+
return requestedSubscriptionId;
|
|
112
|
+
}
|
|
113
|
+
return uuidv4();
|
|
114
|
+
}
|
|
115
|
+
function diffChangeTypeFor(file) {
|
|
116
|
+
if (file.isNew)
|
|
117
|
+
return "A";
|
|
118
|
+
if (file.isDeleted)
|
|
119
|
+
return "D";
|
|
120
|
+
return "M";
|
|
121
|
+
}
|
|
122
|
+
function buildWorkspaceCheckout(workspace, project) {
|
|
123
|
+
if (project.kind !== "git") {
|
|
124
|
+
return {
|
|
125
|
+
cwd: workspace.cwd,
|
|
126
|
+
isGit: false,
|
|
127
|
+
currentBranch: null,
|
|
128
|
+
remoteUrl: null,
|
|
129
|
+
worktreeRoot: null,
|
|
130
|
+
isPaseoOwnedWorktree: false,
|
|
131
|
+
mainRepoRoot: null,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (workspace.kind === "worktree") {
|
|
135
|
+
return {
|
|
136
|
+
cwd: workspace.cwd,
|
|
137
|
+
isGit: true,
|
|
138
|
+
currentBranch: workspace.displayName,
|
|
139
|
+
remoteUrl: null,
|
|
140
|
+
worktreeRoot: workspace.cwd,
|
|
141
|
+
isPaseoOwnedWorktree: true,
|
|
142
|
+
mainRepoRoot: project.rootPath,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
cwd: workspace.cwd,
|
|
147
|
+
isGit: true,
|
|
148
|
+
currentBranch: workspace.displayName,
|
|
149
|
+
remoteUrl: null,
|
|
150
|
+
worktreeRoot: workspace.cwd,
|
|
151
|
+
isPaseoOwnedWorktree: false,
|
|
152
|
+
mainRepoRoot: null,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
67
155
|
function isAppVersionAtLeast(appVersion, minVersion) {
|
|
68
156
|
if (!appVersion)
|
|
69
157
|
return false;
|
|
@@ -119,6 +207,50 @@ export function resolveCreateAgentTitles(options) {
|
|
|
119
207
|
provisionalTitle,
|
|
120
208
|
};
|
|
121
209
|
}
|
|
210
|
+
function parseFetchWorkspacesCursorSort(raw) {
|
|
211
|
+
const cursorSort = [];
|
|
212
|
+
for (const item of raw) {
|
|
213
|
+
if (!item ||
|
|
214
|
+
typeof item !== "object" ||
|
|
215
|
+
typeof item.key !== "string" ||
|
|
216
|
+
typeof item.direction !== "string") {
|
|
217
|
+
throw new SessionRequestError("invalid_cursor", "Invalid fetch_workspaces cursor");
|
|
218
|
+
}
|
|
219
|
+
const key = item.key;
|
|
220
|
+
const direction = item.direction;
|
|
221
|
+
if ((key !== "status_priority" &&
|
|
222
|
+
key !== "activity_at" &&
|
|
223
|
+
key !== "name" &&
|
|
224
|
+
key !== "project_id") ||
|
|
225
|
+
(direction !== "asc" && direction !== "desc")) {
|
|
226
|
+
throw new SessionRequestError("invalid_cursor", "Invalid fetch_workspaces cursor");
|
|
227
|
+
}
|
|
228
|
+
cursorSort.push({ key, direction });
|
|
229
|
+
}
|
|
230
|
+
return cursorSort;
|
|
231
|
+
}
|
|
232
|
+
function parseFetchAgentsCursorSort(raw) {
|
|
233
|
+
const cursorSort = [];
|
|
234
|
+
for (const item of raw) {
|
|
235
|
+
if (!item ||
|
|
236
|
+
typeof item !== "object" ||
|
|
237
|
+
typeof item.key !== "string" ||
|
|
238
|
+
typeof item.direction !== "string") {
|
|
239
|
+
throw new SessionRequestError("invalid_cursor", "Invalid fetch_agents cursor");
|
|
240
|
+
}
|
|
241
|
+
const key = item.key;
|
|
242
|
+
const direction = item.direction;
|
|
243
|
+
if ((key !== "status_priority" &&
|
|
244
|
+
key !== "created_at" &&
|
|
245
|
+
key !== "updated_at" &&
|
|
246
|
+
key !== "title") ||
|
|
247
|
+
(direction !== "asc" && direction !== "desc")) {
|
|
248
|
+
throw new SessionRequestError("invalid_cursor", "Invalid fetch_agents cursor");
|
|
249
|
+
}
|
|
250
|
+
cursorSort.push({ key, direction });
|
|
251
|
+
}
|
|
252
|
+
return cursorSort;
|
|
253
|
+
}
|
|
122
254
|
export function resolveWaitForFinishError(options) {
|
|
123
255
|
if (options.status !== "error") {
|
|
124
256
|
return null;
|
|
@@ -292,53 +424,13 @@ export class Session {
|
|
|
292
424
|
this.getDaemonTcpPort = getDaemonTcpPort ?? null;
|
|
293
425
|
this.getDaemonTcpHost = getDaemonTcpHost ?? null;
|
|
294
426
|
this.resolveScriptHealth = resolveScriptHealth ?? null;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
if (this.providerSnapshotManager) {
|
|
299
|
-
const handleProviderSnapshotChange = (entries, cwd) => {
|
|
300
|
-
// COMPAT(providersSnapshot): keep provider visibility gating for older clients.
|
|
301
|
-
const visibleEntries = entries.filter((entry) => this.isProviderVisibleToClient(entry.provider));
|
|
302
|
-
this.emit({
|
|
303
|
-
type: "providers_snapshot_update",
|
|
304
|
-
payload: {
|
|
305
|
-
cwd,
|
|
306
|
-
entries: visibleEntries,
|
|
307
|
-
generatedAt: new Date().toISOString(),
|
|
308
|
-
},
|
|
309
|
-
});
|
|
310
|
-
};
|
|
311
|
-
this.providerSnapshotManager.on("change", handleProviderSnapshotChange);
|
|
312
|
-
this.unsubscribeProviderSnapshotEvents = () => {
|
|
313
|
-
this.providerSnapshotManager?.off("change", handleProviderSnapshotChange);
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
this.resolveVoiceTurnDetection = toResolver(voice?.turnDetection ?? null);
|
|
317
|
-
this.registerVoiceSpeakHandler = voiceBridge?.registerVoiceSpeakHandler;
|
|
318
|
-
this.unregisterVoiceSpeakHandler = voiceBridge?.unregisterVoiceSpeakHandler;
|
|
319
|
-
this.registerVoiceCallerContext = voiceBridge?.registerVoiceCallerContext;
|
|
320
|
-
this.unregisterVoiceCallerContext = voiceBridge?.unregisterVoiceCallerContext;
|
|
321
|
-
this.getSpeechReadiness = dictation?.getSpeechReadiness;
|
|
427
|
+
this.subscribeToOptionalManagers();
|
|
428
|
+
this.bindVoiceBridges({ voice, voiceBridge, dictation });
|
|
322
429
|
this.agentProviderRuntimeSettings = agentProviderRuntimeSettings;
|
|
323
430
|
this.providerOverrides = providerOverrides;
|
|
324
431
|
this.isDev = isDev === true;
|
|
325
432
|
this.abortController = new AbortController();
|
|
326
|
-
this.
|
|
327
|
-
runtimeSettings: this.agentProviderRuntimeSettings,
|
|
328
|
-
providerOverrides: this.providerOverrides,
|
|
329
|
-
workspaceGitService: this.workspaceGitService,
|
|
330
|
-
isDev: this.isDev,
|
|
331
|
-
});
|
|
332
|
-
// Initialize per-session managers
|
|
333
|
-
this.ttsManager = new TTSManager(this.sessionId, this.sessionLogger, tts);
|
|
334
|
-
this.sttManager = new STTManager(this.sessionId, this.sessionLogger, stt);
|
|
335
|
-
this.dictationStreamManager = new DictationStreamManager({
|
|
336
|
-
logger: this.sessionLogger,
|
|
337
|
-
sessionId: this.sessionId,
|
|
338
|
-
emit: (msg) => this.handleDictationManagerMessage(msg),
|
|
339
|
-
stt: dictation?.stt ?? null,
|
|
340
|
-
finalTimeoutMs: dictation?.finalTimeoutMs,
|
|
341
|
-
});
|
|
433
|
+
this.initializePerSessionManagers({ tts, stt, dictation });
|
|
342
434
|
// Initialize agent MCP client asynchronously
|
|
343
435
|
void this.initializeAgentMcp();
|
|
344
436
|
this.subscribeToAgentEvents();
|
|
@@ -349,9 +441,9 @@ export class Session {
|
|
|
349
441
|
this.appVersion = appVersion;
|
|
350
442
|
}
|
|
351
443
|
}
|
|
352
|
-
async
|
|
444
|
+
async syncWorkspaceGitObserverForWorkspace(workspace) {
|
|
353
445
|
const descriptor = await this.describeWorkspaceRecordWithGitData(workspace);
|
|
354
|
-
|
|
446
|
+
this.syncWorkspaceGitObservers([descriptor]);
|
|
355
447
|
}
|
|
356
448
|
async emitWorkspaceUpdateForWorkspaceId(workspaceId) {
|
|
357
449
|
await this.emitWorkspaceUpdatesForWorkspaceIds([workspaceId], { skipReconcile: true });
|
|
@@ -363,7 +455,7 @@ export class Session {
|
|
|
363
455
|
await this.emitWorkspaceUpdatesForCwds(cwds);
|
|
364
456
|
}
|
|
365
457
|
async warmWorkspaceGitDataForWorkspace(workspace) {
|
|
366
|
-
await this.
|
|
458
|
+
await this.syncWorkspaceGitObserverForWorkspace(workspace);
|
|
367
459
|
await this.emitWorkspaceUpdateForWorkspaceId(workspace.workspaceId);
|
|
368
460
|
}
|
|
369
461
|
/**
|
|
@@ -427,16 +519,11 @@ export class Session {
|
|
|
427
519
|
return;
|
|
428
520
|
}
|
|
429
521
|
this.sessionLogger.debug({ agentId, lifecycle: snapshot.lifecycle, hasInFlightRun }, "interruptAgentIfRunning: interrupting");
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
this.sessionLogger.warn({ agentId }, "interruptAgentIfRunning: reported running but no active run was cancelled");
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
catch (error) {
|
|
439
|
-
throw error;
|
|
522
|
+
const t0 = Date.now();
|
|
523
|
+
const cancelled = await this.agentManager.cancelAgentRun(agentId);
|
|
524
|
+
this.sessionLogger.debug({ agentId, cancelled, durationMs: Date.now() - t0 }, "interruptAgentIfRunning: cancelAgentRun completed");
|
|
525
|
+
if (!cancelled) {
|
|
526
|
+
this.sessionLogger.warn({ agentId }, "interruptAgentIfRunning: reported running but no active run was cancelled");
|
|
440
527
|
}
|
|
441
528
|
}
|
|
442
529
|
hasActiveAgentRun(agentId) {
|
|
@@ -464,12 +551,7 @@ export class Session {
|
|
|
464
551
|
}
|
|
465
552
|
catch (error) {
|
|
466
553
|
this.handleAgentRunError(agentId, error, "Failed to start agent run");
|
|
467
|
-
|
|
468
|
-
? error.message
|
|
469
|
-
: typeof error === "string"
|
|
470
|
-
? error
|
|
471
|
-
: "Unknown error";
|
|
472
|
-
return { ok: false, error: message };
|
|
554
|
+
return { ok: false, error: errorToFriendlyMessage(error) };
|
|
473
555
|
}
|
|
474
556
|
void (async () => {
|
|
475
557
|
try {
|
|
@@ -486,7 +568,7 @@ export class Session {
|
|
|
486
568
|
return { ok: true };
|
|
487
569
|
}
|
|
488
570
|
handleAgentRunError(agentId, error, context) {
|
|
489
|
-
const message = error
|
|
571
|
+
const message = errorToFriendlyMessage(error);
|
|
490
572
|
this.sessionLogger.error({ err: error, agentId, context }, `${context} for agent ${agentId}`);
|
|
491
573
|
this.emit({
|
|
492
574
|
type: "activity_log",
|
|
@@ -522,6 +604,50 @@ export class Session {
|
|
|
522
604
|
/**
|
|
523
605
|
* Subscribe to AgentManager events and forward them to the client
|
|
524
606
|
*/
|
|
607
|
+
subscribeToOptionalManagers() {
|
|
608
|
+
if (this.terminalManager) {
|
|
609
|
+
this.unsubscribeTerminalsChanged = this.terminalManager.subscribeTerminalsChanged((event) => this.handleTerminalsChanged(event));
|
|
610
|
+
}
|
|
611
|
+
if (this.providerSnapshotManager) {
|
|
612
|
+
const handleProviderSnapshotChange = (entries, cwd) => {
|
|
613
|
+
// COMPAT(providersSnapshot): keep provider visibility gating for older clients.
|
|
614
|
+
const visibleEntries = entries.filter((entry) => this.isProviderVisibleToClient(entry.provider));
|
|
615
|
+
this.emit({
|
|
616
|
+
type: "providers_snapshot_update",
|
|
617
|
+
payload: {
|
|
618
|
+
cwd,
|
|
619
|
+
entries: visibleEntries,
|
|
620
|
+
generatedAt: new Date().toISOString(),
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
};
|
|
624
|
+
this.providerSnapshotManager.on("change", handleProviderSnapshotChange);
|
|
625
|
+
this.unsubscribeProviderSnapshotEvents = () => {
|
|
626
|
+
this.providerSnapshotManager?.off("change", handleProviderSnapshotChange);
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
bindVoiceBridges(params) {
|
|
631
|
+
const { voice, voiceBridge, dictation } = params;
|
|
632
|
+
this.resolveVoiceTurnDetection = toResolver(voice?.turnDetection ?? null);
|
|
633
|
+
this.registerVoiceSpeakHandler = voiceBridge?.registerVoiceSpeakHandler;
|
|
634
|
+
this.unregisterVoiceSpeakHandler = voiceBridge?.unregisterVoiceSpeakHandler;
|
|
635
|
+
this.registerVoiceCallerContext = voiceBridge?.registerVoiceCallerContext;
|
|
636
|
+
this.unregisterVoiceCallerContext = voiceBridge?.unregisterVoiceCallerContext;
|
|
637
|
+
this.getSpeechReadiness = dictation?.getSpeechReadiness;
|
|
638
|
+
}
|
|
639
|
+
initializePerSessionManagers(params) {
|
|
640
|
+
const { tts, stt, dictation } = params;
|
|
641
|
+
this.ttsManager = new TTSManager(this.sessionId, this.sessionLogger, tts);
|
|
642
|
+
this.sttManager = new STTManager(this.sessionId, this.sessionLogger, stt);
|
|
643
|
+
this.dictationStreamManager = new DictationStreamManager({
|
|
644
|
+
logger: this.sessionLogger,
|
|
645
|
+
sessionId: this.sessionId,
|
|
646
|
+
emit: (msg) => this.handleDictationManagerMessage(msg),
|
|
647
|
+
stt: dictation?.stt ?? null,
|
|
648
|
+
finalTimeoutMs: dictation?.finalTimeoutMs,
|
|
649
|
+
});
|
|
650
|
+
}
|
|
525
651
|
subscribeToAgentEvents() {
|
|
526
652
|
if (this.unsubscribeAgentEvents) {
|
|
527
653
|
this.unsubscribeAgentEvents();
|
|
@@ -618,8 +744,19 @@ export class Session {
|
|
|
618
744
|
payload.archivedAt = storedRecord?.archivedAt ?? null;
|
|
619
745
|
return payload;
|
|
620
746
|
}
|
|
621
|
-
|
|
622
|
-
return
|
|
747
|
+
getProviderRegistry() {
|
|
748
|
+
return buildProviderRegistry(this.sessionLogger, {
|
|
749
|
+
runtimeSettings: this.agentProviderRuntimeSettings,
|
|
750
|
+
providerOverrides: applyMutableProviderConfigToOverrides(this.providerOverrides, this.daemonConfigStore.get().providers),
|
|
751
|
+
workspaceGitService: this.workspaceGitService,
|
|
752
|
+
isDev: this.isDev,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
getRegisteredProviderIds() {
|
|
756
|
+
return Object.keys(this.getProviderRegistry());
|
|
757
|
+
}
|
|
758
|
+
buildStoredAgentPayload(record, registeredProviderIds = this.getRegisteredProviderIds()) {
|
|
759
|
+
return buildStoredAgentPayload(record, registeredProviderIds);
|
|
623
760
|
}
|
|
624
761
|
isProviderVisibleToClient(provider) {
|
|
625
762
|
if (clientSupportsAllProviders(this.appVersion)) {
|
|
@@ -633,44 +770,34 @@ export class Session {
|
|
|
633
770
|
}
|
|
634
771
|
return editors.filter((editor) => isLegacyEditorTargetId(editor.id));
|
|
635
772
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
const matchesLabels = Object.entries(filter.labels).every(([key, value]) => agent.labels[key] === value);
|
|
640
|
-
if (!matchesLabels) {
|
|
641
|
-
return false;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
const includeArchived = filter?.includeArchived ?? false;
|
|
645
|
-
if (!includeArchived && agent.archivedAt) {
|
|
646
|
-
return false;
|
|
773
|
+
agentThinkingOptionMatchesFilter(agent, filter) {
|
|
774
|
+
if (filter.thinkingOptionId === undefined) {
|
|
775
|
+
return true;
|
|
647
776
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
777
|
+
const expectedThinkingOptionId = resolveEffectiveThinkingOptionId({
|
|
778
|
+
configuredThinkingOptionId: filter.thinkingOptionId ?? null,
|
|
779
|
+
});
|
|
780
|
+
const resolvedThinkingOptionId = agent.effectiveThinkingOptionId ??
|
|
781
|
+
resolveEffectiveThinkingOptionId({
|
|
782
|
+
runtimeInfo: agent.runtimeInfo,
|
|
783
|
+
configuredThinkingOptionId: agent.thinkingOptionId ?? null,
|
|
651
784
|
});
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
});
|
|
657
|
-
if (resolvedThinkingOptionId !== expectedThinkingOptionId) {
|
|
658
|
-
return false;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
if (filter?.statuses && filter.statuses.length > 0) {
|
|
785
|
+
return resolvedThinkingOptionId === expectedThinkingOptionId;
|
|
786
|
+
}
|
|
787
|
+
matchesAgentStructuralFilter(agent, project, filter) {
|
|
788
|
+
if (filter.statuses && filter.statuses.length > 0) {
|
|
662
789
|
const statuses = new Set(filter.statuses);
|
|
663
790
|
if (!statuses.has(agent.status)) {
|
|
664
791
|
return false;
|
|
665
792
|
}
|
|
666
793
|
}
|
|
667
|
-
if (typeof filter
|
|
794
|
+
if (typeof filter.requiresAttention === "boolean") {
|
|
668
795
|
const requiresAttention = agent.requiresAttention ?? false;
|
|
669
796
|
if (requiresAttention !== filter.requiresAttention) {
|
|
670
797
|
return false;
|
|
671
798
|
}
|
|
672
799
|
}
|
|
673
|
-
if (filter
|
|
800
|
+
if (filter.projectKeys && filter.projectKeys.length > 0) {
|
|
674
801
|
const projectKeys = new Set(filter.projectKeys.filter((item) => item.trim().length > 0));
|
|
675
802
|
if (projectKeys.size > 0 && !projectKeys.has(project.projectKey)) {
|
|
676
803
|
return false;
|
|
@@ -678,6 +805,26 @@ export class Session {
|
|
|
678
805
|
}
|
|
679
806
|
return true;
|
|
680
807
|
}
|
|
808
|
+
matchesAgentFilter(options) {
|
|
809
|
+
const { agent, project, filter } = options;
|
|
810
|
+
if (filter?.labels) {
|
|
811
|
+
const matchesLabels = Object.entries(filter.labels).every(([key, value]) => agent.labels[key] === value);
|
|
812
|
+
if (!matchesLabels) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
const includeArchived = filter?.includeArchived ?? false;
|
|
817
|
+
if (!includeArchived && agent.archivedAt) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
if (filter && !this.agentThinkingOptionMatchesFilter(agent, filter)) {
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
if (filter && !this.matchesAgentStructuralFilter(agent, project, filter)) {
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
681
828
|
getAgentUpdateTargetId(update) {
|
|
682
829
|
return update.kind === "remove" ? update.agentId : update.agent.id;
|
|
683
830
|
}
|
|
@@ -724,54 +871,26 @@ export class Session {
|
|
|
724
871
|
const workspaceId = this.resolveRegisteredWorkspaceIdForCwd(normalizedCwd, workspaces);
|
|
725
872
|
return workspaces.find((workspace) => workspace.workspaceId === workspaceId) ?? null;
|
|
726
873
|
}
|
|
874
|
+
async findExactWorkspaceByDirectory(cwd, options) {
|
|
875
|
+
const normalizedCwd = await this.resolveWorkspaceDirectory(cwd, options);
|
|
876
|
+
const workspaces = await this.workspaceRegistry.list();
|
|
877
|
+
return workspaces.find((workspace) => workspace.cwd === normalizedCwd) ?? null;
|
|
878
|
+
}
|
|
727
879
|
async resolveWorkspaceDirectory(cwd, options) {
|
|
728
880
|
const normalizedCwd = normalizePersistedWorkspaceId(cwd);
|
|
729
881
|
if (options?.refreshGit === false) {
|
|
730
882
|
const snapshot = this.workspaceGitService.peekSnapshot(normalizedCwd);
|
|
731
883
|
return normalizePersistedWorkspaceId(snapshot?.git.repoRoot ?? normalizedCwd);
|
|
732
884
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
return normalizePersistedWorkspaceId(snapshot.git.repoRoot ?? normalizedCwd);
|
|
736
|
-
}
|
|
737
|
-
catch {
|
|
738
|
-
return normalizedCwd;
|
|
739
|
-
}
|
|
885
|
+
const checkout = await this.workspaceGitService.getCheckout(normalizedCwd);
|
|
886
|
+
return normalizePersistedWorkspaceId(checkout.worktreeRoot ?? normalizedCwd);
|
|
740
887
|
}
|
|
741
888
|
async buildProjectPlacementForWorkspace(workspace, projectRecord) {
|
|
742
889
|
const project = projectRecord ?? (await this.projectRegistry.get(workspace.projectId));
|
|
743
890
|
if (!project) {
|
|
744
891
|
throw new Error(`Project not found for workspace ${workspace.workspaceId}`);
|
|
745
892
|
}
|
|
746
|
-
const checkout = project
|
|
747
|
-
? {
|
|
748
|
-
cwd: workspace.cwd,
|
|
749
|
-
isGit: false,
|
|
750
|
-
currentBranch: null,
|
|
751
|
-
remoteUrl: null,
|
|
752
|
-
worktreeRoot: null,
|
|
753
|
-
isPaseoOwnedWorktree: false,
|
|
754
|
-
mainRepoRoot: null,
|
|
755
|
-
}
|
|
756
|
-
: workspace.kind === "worktree"
|
|
757
|
-
? {
|
|
758
|
-
cwd: workspace.cwd,
|
|
759
|
-
isGit: true,
|
|
760
|
-
currentBranch: workspace.displayName,
|
|
761
|
-
remoteUrl: null,
|
|
762
|
-
worktreeRoot: workspace.cwd,
|
|
763
|
-
isPaseoOwnedWorktree: true,
|
|
764
|
-
mainRepoRoot: project.rootPath,
|
|
765
|
-
}
|
|
766
|
-
: {
|
|
767
|
-
cwd: workspace.cwd,
|
|
768
|
-
isGit: true,
|
|
769
|
-
currentBranch: workspace.displayName,
|
|
770
|
-
remoteUrl: null,
|
|
771
|
-
worktreeRoot: workspace.cwd,
|
|
772
|
-
isPaseoOwnedWorktree: false,
|
|
773
|
-
mainRepoRoot: null,
|
|
774
|
-
};
|
|
893
|
+
const checkout = buildWorkspaceCheckout(workspace, project);
|
|
775
894
|
return {
|
|
776
895
|
projectKey: project.projectId,
|
|
777
896
|
projectName: project.displayName,
|
|
@@ -851,360 +970,7 @@ export class Session {
|
|
|
851
970
|
try {
|
|
852
971
|
this.sessionLogger.trace({ messageType: msg.type, payloadBytes: JSON.stringify(msg).length }, "inbound message");
|
|
853
972
|
try {
|
|
854
|
-
|
|
855
|
-
case "voice_audio_chunk":
|
|
856
|
-
await this.handleAudioChunk(msg);
|
|
857
|
-
break;
|
|
858
|
-
case "abort_request":
|
|
859
|
-
await this.handleAbort();
|
|
860
|
-
break;
|
|
861
|
-
case "audio_played":
|
|
862
|
-
this.handleAudioPlayed(msg.id);
|
|
863
|
-
break;
|
|
864
|
-
case "fetch_agents_request":
|
|
865
|
-
await this.handleFetchAgents(msg);
|
|
866
|
-
break;
|
|
867
|
-
case "fetch_agent_history_request":
|
|
868
|
-
await this.handleFetchAgentHistory(msg);
|
|
869
|
-
break;
|
|
870
|
-
case "fetch_workspaces_request":
|
|
871
|
-
await this.handleFetchWorkspacesRequest(msg);
|
|
872
|
-
break;
|
|
873
|
-
case "fetch_agent_request":
|
|
874
|
-
await this.handleFetchAgent(msg.agentId, msg.requestId);
|
|
875
|
-
break;
|
|
876
|
-
case "delete_agent_request":
|
|
877
|
-
await this.handleDeleteAgentRequest(msg.agentId, msg.requestId);
|
|
878
|
-
break;
|
|
879
|
-
case "archive_agent_request":
|
|
880
|
-
await this.handleArchiveAgentRequest(msg.agentId, msg.requestId);
|
|
881
|
-
break;
|
|
882
|
-
case "close_items_request":
|
|
883
|
-
await this.handleCloseItemsRequest(msg);
|
|
884
|
-
break;
|
|
885
|
-
case "update_agent_request":
|
|
886
|
-
await this.handleUpdateAgentRequest(msg.agentId, msg.name, msg.labels, msg.requestId);
|
|
887
|
-
break;
|
|
888
|
-
case "set_voice_mode":
|
|
889
|
-
await this.handleSetVoiceMode(msg.enabled, msg.agentId, msg.requestId);
|
|
890
|
-
break;
|
|
891
|
-
case "send_agent_message_request":
|
|
892
|
-
await this.handleSendAgentMessageRequest(msg);
|
|
893
|
-
break;
|
|
894
|
-
case "wait_for_finish_request":
|
|
895
|
-
await this.handleWaitForFinish(msg.agentId, msg.requestId, msg.timeoutMs);
|
|
896
|
-
break;
|
|
897
|
-
case "get_daemon_config_request":
|
|
898
|
-
this.emit({
|
|
899
|
-
type: "get_daemon_config_response",
|
|
900
|
-
payload: {
|
|
901
|
-
requestId: msg.requestId,
|
|
902
|
-
config: this.daemonConfigStore.get(),
|
|
903
|
-
},
|
|
904
|
-
});
|
|
905
|
-
break;
|
|
906
|
-
case "set_daemon_config_request":
|
|
907
|
-
this.emit({
|
|
908
|
-
type: "set_daemon_config_response",
|
|
909
|
-
payload: {
|
|
910
|
-
requestId: msg.requestId,
|
|
911
|
-
config: this.daemonConfigStore.patch(msg.config),
|
|
912
|
-
},
|
|
913
|
-
});
|
|
914
|
-
break;
|
|
915
|
-
case "dictation_stream_start":
|
|
916
|
-
{
|
|
917
|
-
const unavailable = this.resolveVoiceFeatureUnavailableContext("dictation");
|
|
918
|
-
if (unavailable) {
|
|
919
|
-
this.emit({
|
|
920
|
-
type: "dictation_stream_error",
|
|
921
|
-
payload: {
|
|
922
|
-
dictationId: msg.dictationId,
|
|
923
|
-
error: unavailable.message,
|
|
924
|
-
retryable: unavailable.retryable,
|
|
925
|
-
reasonCode: unavailable.reasonCode,
|
|
926
|
-
missingModelIds: unavailable.missingModelIds,
|
|
927
|
-
},
|
|
928
|
-
});
|
|
929
|
-
break;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
await this.dictationStreamManager.handleStart(msg.dictationId, msg.format);
|
|
933
|
-
break;
|
|
934
|
-
case "dictation_stream_chunk":
|
|
935
|
-
await this.dictationStreamManager.handleChunk({
|
|
936
|
-
dictationId: msg.dictationId,
|
|
937
|
-
seq: msg.seq,
|
|
938
|
-
audioBase64: msg.audio,
|
|
939
|
-
format: msg.format,
|
|
940
|
-
});
|
|
941
|
-
break;
|
|
942
|
-
case "dictation_stream_finish":
|
|
943
|
-
await this.dictationStreamManager.handleFinish(msg.dictationId, msg.finalSeq);
|
|
944
|
-
break;
|
|
945
|
-
case "dictation_stream_cancel":
|
|
946
|
-
this.dictationStreamManager.handleCancel(msg.dictationId);
|
|
947
|
-
break;
|
|
948
|
-
case "create_agent_request":
|
|
949
|
-
await this.handleCreateAgentRequest(msg);
|
|
950
|
-
break;
|
|
951
|
-
case "resume_agent_request":
|
|
952
|
-
await this.handleResumeAgentRequest(msg);
|
|
953
|
-
break;
|
|
954
|
-
case "refresh_agent_request":
|
|
955
|
-
await this.handleRefreshAgentRequest(msg);
|
|
956
|
-
break;
|
|
957
|
-
case "cancel_agent_request":
|
|
958
|
-
await this.handleCancelAgentRequest(msg.agentId, msg.requestId);
|
|
959
|
-
break;
|
|
960
|
-
case "restart_server_request":
|
|
961
|
-
await this.handleRestartServerRequest(msg.requestId, msg.reason);
|
|
962
|
-
break;
|
|
963
|
-
case "shutdown_server_request":
|
|
964
|
-
await this.handleShutdownServerRequest(msg.requestId);
|
|
965
|
-
break;
|
|
966
|
-
case "fetch_agent_timeline_request":
|
|
967
|
-
await this.handleFetchAgentTimelineRequest(msg);
|
|
968
|
-
break;
|
|
969
|
-
case "set_agent_mode_request":
|
|
970
|
-
await this.handleSetAgentModeRequest(msg.agentId, msg.modeId, msg.requestId);
|
|
971
|
-
break;
|
|
972
|
-
case "set_agent_model_request":
|
|
973
|
-
await this.handleSetAgentModelRequest(msg.agentId, msg.modelId, msg.requestId);
|
|
974
|
-
break;
|
|
975
|
-
case "set_agent_feature_request":
|
|
976
|
-
await this.handleSetAgentFeatureRequest(msg.agentId, msg.featureId, msg.value, msg.requestId);
|
|
977
|
-
break;
|
|
978
|
-
case "set_agent_thinking_request":
|
|
979
|
-
await this.handleSetAgentThinkingRequest(msg.agentId, msg.thinkingOptionId, msg.requestId);
|
|
980
|
-
break;
|
|
981
|
-
case "agent_permission_response":
|
|
982
|
-
await this.handleAgentPermissionResponse(msg.agentId, msg.requestId, msg.response);
|
|
983
|
-
break;
|
|
984
|
-
case "checkout_status_request":
|
|
985
|
-
await this.handleCheckoutStatusRequest(msg);
|
|
986
|
-
break;
|
|
987
|
-
case "validate_branch_request":
|
|
988
|
-
await this.handleValidateBranchRequest(msg);
|
|
989
|
-
break;
|
|
990
|
-
case "branch_suggestions_request":
|
|
991
|
-
await this.handleBranchSuggestionsRequest(msg);
|
|
992
|
-
break;
|
|
993
|
-
case "directory_suggestions_request":
|
|
994
|
-
await this.handleDirectorySuggestionsRequest(msg);
|
|
995
|
-
break;
|
|
996
|
-
case "subscribe_checkout_diff_request":
|
|
997
|
-
await this.handleSubscribeCheckoutDiffRequest(msg);
|
|
998
|
-
break;
|
|
999
|
-
case "unsubscribe_checkout_diff_request":
|
|
1000
|
-
this.handleUnsubscribeCheckoutDiffRequest(msg);
|
|
1001
|
-
break;
|
|
1002
|
-
case "checkout_switch_branch_request":
|
|
1003
|
-
await this.handleCheckoutSwitchBranchRequest(msg);
|
|
1004
|
-
break;
|
|
1005
|
-
case "stash_save_request":
|
|
1006
|
-
await this.handleStashSaveRequest(msg);
|
|
1007
|
-
break;
|
|
1008
|
-
case "stash_pop_request":
|
|
1009
|
-
await this.handleStashPopRequest(msg);
|
|
1010
|
-
break;
|
|
1011
|
-
case "stash_list_request":
|
|
1012
|
-
await this.handleStashListRequest(msg);
|
|
1013
|
-
break;
|
|
1014
|
-
case "checkout_commit_request":
|
|
1015
|
-
await this.handleCheckoutCommitRequest(msg);
|
|
1016
|
-
break;
|
|
1017
|
-
case "checkout_merge_request":
|
|
1018
|
-
await this.handleCheckoutMergeRequest(msg);
|
|
1019
|
-
break;
|
|
1020
|
-
case "checkout_merge_from_base_request":
|
|
1021
|
-
await this.handleCheckoutMergeFromBaseRequest(msg);
|
|
1022
|
-
break;
|
|
1023
|
-
case "checkout_pull_request":
|
|
1024
|
-
await this.handleCheckoutPullRequest(msg);
|
|
1025
|
-
break;
|
|
1026
|
-
case "checkout_push_request":
|
|
1027
|
-
await this.handleCheckoutPushRequest(msg);
|
|
1028
|
-
break;
|
|
1029
|
-
case "checkout_pr_create_request":
|
|
1030
|
-
await this.handleCheckoutPrCreateRequest(msg);
|
|
1031
|
-
break;
|
|
1032
|
-
case "checkout_pr_status_request":
|
|
1033
|
-
await this.handleCheckoutPrStatusRequest(msg);
|
|
1034
|
-
break;
|
|
1035
|
-
case "pull_request_timeline_request":
|
|
1036
|
-
await this.handlePullRequestTimelineRequest(msg);
|
|
1037
|
-
break;
|
|
1038
|
-
case "github_search_request":
|
|
1039
|
-
await this.handleGitHubSearchRequest(msg);
|
|
1040
|
-
break;
|
|
1041
|
-
case "paseo_worktree_list_request":
|
|
1042
|
-
await this.handlePaseoWorktreeListRequest(msg);
|
|
1043
|
-
break;
|
|
1044
|
-
case "paseo_worktree_archive_request":
|
|
1045
|
-
await this.handlePaseoWorktreeArchiveRequest(msg);
|
|
1046
|
-
break;
|
|
1047
|
-
case "create_paseo_worktree_request":
|
|
1048
|
-
await this.handleCreatePaseoWorktreeRequest(msg);
|
|
1049
|
-
break;
|
|
1050
|
-
case "workspace_setup_status_request":
|
|
1051
|
-
await this.handleWorkspaceSetupStatusRequest(msg);
|
|
1052
|
-
break;
|
|
1053
|
-
case "list_available_editors_request":
|
|
1054
|
-
await this.handleListAvailableEditorsRequest(msg);
|
|
1055
|
-
break;
|
|
1056
|
-
case "open_in_editor_request":
|
|
1057
|
-
await this.handleOpenInEditorRequest(msg);
|
|
1058
|
-
break;
|
|
1059
|
-
case "open_project_request":
|
|
1060
|
-
await this.handleOpenProjectRequest(msg);
|
|
1061
|
-
break;
|
|
1062
|
-
case "archive_workspace_request":
|
|
1063
|
-
await this.handleArchiveWorkspaceRequest(msg);
|
|
1064
|
-
break;
|
|
1065
|
-
case "file_explorer_request":
|
|
1066
|
-
await this.handleFileExplorerRequest(msg);
|
|
1067
|
-
break;
|
|
1068
|
-
case "project_icon_request":
|
|
1069
|
-
await this.handleProjectIconRequest(msg);
|
|
1070
|
-
break;
|
|
1071
|
-
case "file_download_token_request":
|
|
1072
|
-
await this.handleFileDownloadTokenRequest(msg);
|
|
1073
|
-
break;
|
|
1074
|
-
case "list_provider_models_request":
|
|
1075
|
-
await this.handleListProviderModelsRequest(msg);
|
|
1076
|
-
break;
|
|
1077
|
-
case "list_provider_modes_request":
|
|
1078
|
-
await this.handleListProviderModesRequest(msg);
|
|
1079
|
-
break;
|
|
1080
|
-
case "list_provider_features_request":
|
|
1081
|
-
await this.handleListProviderFeaturesRequest(msg);
|
|
1082
|
-
break;
|
|
1083
|
-
case "list_available_providers_request":
|
|
1084
|
-
await this.handleListAvailableProvidersRequest(msg);
|
|
1085
|
-
break;
|
|
1086
|
-
case "get_providers_snapshot_request":
|
|
1087
|
-
await this.handleGetProvidersSnapshotRequest(msg);
|
|
1088
|
-
break;
|
|
1089
|
-
case "refresh_providers_snapshot_request":
|
|
1090
|
-
await this.handleRefreshProvidersSnapshotRequest(msg);
|
|
1091
|
-
break;
|
|
1092
|
-
case "provider_diagnostic_request":
|
|
1093
|
-
await this.handleProviderDiagnosticRequest(msg);
|
|
1094
|
-
break;
|
|
1095
|
-
case "clear_agent_attention":
|
|
1096
|
-
await this.handleClearAgentAttention(msg.agentId, msg.requestId);
|
|
1097
|
-
break;
|
|
1098
|
-
case "client_heartbeat":
|
|
1099
|
-
this.handleClientHeartbeat(msg);
|
|
1100
|
-
break;
|
|
1101
|
-
case "ping": {
|
|
1102
|
-
const now = Date.now();
|
|
1103
|
-
this.emit({
|
|
1104
|
-
type: "pong",
|
|
1105
|
-
payload: {
|
|
1106
|
-
requestId: msg.requestId,
|
|
1107
|
-
clientSentAt: msg.clientSentAt,
|
|
1108
|
-
serverReceivedAt: now,
|
|
1109
|
-
serverSentAt: now,
|
|
1110
|
-
},
|
|
1111
|
-
});
|
|
1112
|
-
break;
|
|
1113
|
-
}
|
|
1114
|
-
case "list_commands_request":
|
|
1115
|
-
await this.handleListCommandsRequest(msg);
|
|
1116
|
-
break;
|
|
1117
|
-
case "register_push_token":
|
|
1118
|
-
this.handleRegisterPushToken(msg.token);
|
|
1119
|
-
break;
|
|
1120
|
-
case "subscribe_terminals_request":
|
|
1121
|
-
this.handleSubscribeTerminalsRequest(msg);
|
|
1122
|
-
break;
|
|
1123
|
-
case "unsubscribe_terminals_request":
|
|
1124
|
-
this.handleUnsubscribeTerminalsRequest(msg);
|
|
1125
|
-
break;
|
|
1126
|
-
case "list_terminals_request":
|
|
1127
|
-
await this.handleListTerminalsRequest(msg);
|
|
1128
|
-
break;
|
|
1129
|
-
case "create_terminal_request":
|
|
1130
|
-
await this.handleCreateTerminalRequest(msg);
|
|
1131
|
-
break;
|
|
1132
|
-
case "start_workspace_script_request":
|
|
1133
|
-
await this.handleStartWorkspaceScriptRequest(msg);
|
|
1134
|
-
break;
|
|
1135
|
-
case "subscribe_terminal_request":
|
|
1136
|
-
await this.handleSubscribeTerminalRequest(msg);
|
|
1137
|
-
break;
|
|
1138
|
-
case "unsubscribe_terminal_request":
|
|
1139
|
-
this.handleUnsubscribeTerminalRequest(msg);
|
|
1140
|
-
break;
|
|
1141
|
-
case "terminal_input":
|
|
1142
|
-
this.handleTerminalInput(msg);
|
|
1143
|
-
break;
|
|
1144
|
-
case "kill_terminal_request":
|
|
1145
|
-
await this.handleKillTerminalRequest(msg);
|
|
1146
|
-
break;
|
|
1147
|
-
case "capture_terminal_request":
|
|
1148
|
-
await this.handleCaptureTerminalRequest(msg);
|
|
1149
|
-
break;
|
|
1150
|
-
case "chat/create":
|
|
1151
|
-
await this.handleChatCreateRequest(msg);
|
|
1152
|
-
break;
|
|
1153
|
-
case "chat/list":
|
|
1154
|
-
await this.handleChatListRequest(msg);
|
|
1155
|
-
break;
|
|
1156
|
-
case "chat/inspect":
|
|
1157
|
-
await this.handleChatInspectRequest(msg);
|
|
1158
|
-
break;
|
|
1159
|
-
case "chat/delete":
|
|
1160
|
-
await this.handleChatDeleteRequest(msg);
|
|
1161
|
-
break;
|
|
1162
|
-
case "chat/post":
|
|
1163
|
-
await this.handleChatPostRequest(msg);
|
|
1164
|
-
break;
|
|
1165
|
-
case "chat/read":
|
|
1166
|
-
await this.handleChatReadRequest(msg);
|
|
1167
|
-
break;
|
|
1168
|
-
case "chat/wait":
|
|
1169
|
-
await this.handleChatWaitRequest(msg);
|
|
1170
|
-
break;
|
|
1171
|
-
case "schedule/create":
|
|
1172
|
-
await this.handleScheduleCreateRequest(msg);
|
|
1173
|
-
break;
|
|
1174
|
-
case "schedule/list":
|
|
1175
|
-
await this.handleScheduleListRequest(msg);
|
|
1176
|
-
break;
|
|
1177
|
-
case "schedule/inspect":
|
|
1178
|
-
await this.handleScheduleInspectRequest(msg);
|
|
1179
|
-
break;
|
|
1180
|
-
case "schedule/logs":
|
|
1181
|
-
await this.handleScheduleLogsRequest(msg);
|
|
1182
|
-
break;
|
|
1183
|
-
case "schedule/pause":
|
|
1184
|
-
await this.handleSchedulePauseRequest(msg);
|
|
1185
|
-
break;
|
|
1186
|
-
case "schedule/resume":
|
|
1187
|
-
await this.handleScheduleResumeRequest(msg);
|
|
1188
|
-
break;
|
|
1189
|
-
case "schedule/delete":
|
|
1190
|
-
await this.handleScheduleDeleteRequest(msg);
|
|
1191
|
-
break;
|
|
1192
|
-
case "loop/run":
|
|
1193
|
-
await this.handleLoopRunRequest(msg);
|
|
1194
|
-
break;
|
|
1195
|
-
case "loop/list":
|
|
1196
|
-
await this.handleLoopListRequest(msg);
|
|
1197
|
-
break;
|
|
1198
|
-
case "loop/inspect":
|
|
1199
|
-
await this.handleLoopInspectRequest(msg);
|
|
1200
|
-
break;
|
|
1201
|
-
case "loop/logs":
|
|
1202
|
-
await this.handleLoopLogsRequest(msg);
|
|
1203
|
-
break;
|
|
1204
|
-
case "loop/stop":
|
|
1205
|
-
await this.handleLoopStopRequest(msg);
|
|
1206
|
-
break;
|
|
1207
|
-
}
|
|
973
|
+
await this.dispatchInboundMessage(msg);
|
|
1208
974
|
}
|
|
1209
975
|
catch (error) {
|
|
1210
976
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -1241,6 +1007,418 @@ export class Session {
|
|
|
1241
1007
|
this.inflightRequests--;
|
|
1242
1008
|
}
|
|
1243
1009
|
}
|
|
1010
|
+
async dispatchInboundMessage(msg) {
|
|
1011
|
+
const promise = this.dispatchVoiceAndControlMessage(msg) ??
|
|
1012
|
+
this.dispatchAgentLifecycleMessage(msg) ??
|
|
1013
|
+
this.dispatchAgentConfigMessage(msg) ??
|
|
1014
|
+
this.dispatchCheckoutMessage(msg) ??
|
|
1015
|
+
this.dispatchWorkspaceAndProjectMessage(msg) ??
|
|
1016
|
+
this.dispatchProviderMessage(msg) ??
|
|
1017
|
+
this.dispatchTerminalMessage(msg) ??
|
|
1018
|
+
this.dispatchChatScheduleLoopMessage(msg) ??
|
|
1019
|
+
this.dispatchMiscMessage(msg);
|
|
1020
|
+
if (promise)
|
|
1021
|
+
await promise;
|
|
1022
|
+
}
|
|
1023
|
+
dispatchVoiceAndControlMessage(msg) {
|
|
1024
|
+
switch (msg.type) {
|
|
1025
|
+
case "voice_audio_chunk":
|
|
1026
|
+
return this.handleAudioChunk(msg);
|
|
1027
|
+
case "abort_request":
|
|
1028
|
+
return this.handleAbort();
|
|
1029
|
+
case "audio_played":
|
|
1030
|
+
this.handleAudioPlayed(msg.id);
|
|
1031
|
+
return undefined;
|
|
1032
|
+
case "set_voice_mode":
|
|
1033
|
+
return this.handleSetVoiceMode(msg.enabled, msg.agentId, msg.requestId);
|
|
1034
|
+
case "dictation_stream_start":
|
|
1035
|
+
return this.handleDictationStreamStart(msg);
|
|
1036
|
+
case "dictation_stream_chunk":
|
|
1037
|
+
return this.dictationStreamManager.handleChunk({
|
|
1038
|
+
dictationId: msg.dictationId,
|
|
1039
|
+
seq: msg.seq,
|
|
1040
|
+
audioBase64: msg.audio,
|
|
1041
|
+
format: msg.format,
|
|
1042
|
+
});
|
|
1043
|
+
case "dictation_stream_finish":
|
|
1044
|
+
return this.dictationStreamManager.handleFinish(msg.dictationId, msg.finalSeq);
|
|
1045
|
+
case "dictation_stream_cancel":
|
|
1046
|
+
this.dictationStreamManager.handleCancel(msg.dictationId);
|
|
1047
|
+
return undefined;
|
|
1048
|
+
case "restart_server_request":
|
|
1049
|
+
return this.handleRestartServerRequest(msg.requestId, msg.reason);
|
|
1050
|
+
case "shutdown_server_request":
|
|
1051
|
+
return this.handleShutdownServerRequest(msg.requestId);
|
|
1052
|
+
case "client_heartbeat":
|
|
1053
|
+
this.handleClientHeartbeat(msg);
|
|
1054
|
+
return undefined;
|
|
1055
|
+
case "ping": {
|
|
1056
|
+
const now = Date.now();
|
|
1057
|
+
this.emit({
|
|
1058
|
+
type: "pong",
|
|
1059
|
+
payload: {
|
|
1060
|
+
requestId: msg.requestId,
|
|
1061
|
+
clientSentAt: msg.clientSentAt,
|
|
1062
|
+
serverReceivedAt: now,
|
|
1063
|
+
serverSentAt: now,
|
|
1064
|
+
},
|
|
1065
|
+
});
|
|
1066
|
+
return undefined;
|
|
1067
|
+
}
|
|
1068
|
+
default:
|
|
1069
|
+
return undefined;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
async handleDictationStreamStart(msg) {
|
|
1073
|
+
const unavailable = this.resolveVoiceFeatureUnavailableContext("dictation");
|
|
1074
|
+
if (unavailable) {
|
|
1075
|
+
this.emit({
|
|
1076
|
+
type: "dictation_stream_error",
|
|
1077
|
+
payload: {
|
|
1078
|
+
dictationId: msg.dictationId,
|
|
1079
|
+
error: unavailable.message,
|
|
1080
|
+
retryable: unavailable.retryable,
|
|
1081
|
+
reasonCode: unavailable.reasonCode,
|
|
1082
|
+
missingModelIds: unavailable.missingModelIds,
|
|
1083
|
+
},
|
|
1084
|
+
});
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
await this.dictationStreamManager.handleStart(msg.dictationId, msg.format);
|
|
1088
|
+
}
|
|
1089
|
+
dispatchAgentLifecycleMessage(msg) {
|
|
1090
|
+
switch (msg.type) {
|
|
1091
|
+
case "fetch_agents_request":
|
|
1092
|
+
return this.handleFetchAgents(msg);
|
|
1093
|
+
case "fetch_agent_history_request":
|
|
1094
|
+
return this.handleFetchAgentHistory(msg);
|
|
1095
|
+
case "fetch_agent_request":
|
|
1096
|
+
return this.handleFetchAgent(msg.agentId, msg.requestId);
|
|
1097
|
+
case "delete_agent_request":
|
|
1098
|
+
return this.handleDeleteAgentRequest(msg.agentId, msg.requestId);
|
|
1099
|
+
case "archive_agent_request":
|
|
1100
|
+
return this.handleArchiveAgentRequest(msg.agentId, msg.requestId);
|
|
1101
|
+
case "close_items_request":
|
|
1102
|
+
return this.handleCloseItemsRequest(msg);
|
|
1103
|
+
case "update_agent_request":
|
|
1104
|
+
return this.handleUpdateAgentRequest(msg.agentId, msg.name, msg.labels, msg.requestId);
|
|
1105
|
+
case "send_agent_message_request":
|
|
1106
|
+
return this.handleSendAgentMessageRequest(msg);
|
|
1107
|
+
case "wait_for_finish_request":
|
|
1108
|
+
return this.handleWaitForFinish(msg.agentId, msg.requestId, msg.timeoutMs);
|
|
1109
|
+
case "create_agent_request":
|
|
1110
|
+
return this.handleCreateAgentRequest(msg);
|
|
1111
|
+
case "resume_agent_request":
|
|
1112
|
+
return this.handleResumeAgentRequest(msg);
|
|
1113
|
+
case "refresh_agent_request":
|
|
1114
|
+
return this.handleRefreshAgentRequest(msg);
|
|
1115
|
+
case "cancel_agent_request":
|
|
1116
|
+
return this.handleCancelAgentRequest(msg.agentId, msg.requestId);
|
|
1117
|
+
case "fetch_agent_timeline_request":
|
|
1118
|
+
return this.handleFetchAgentTimelineRequest(msg);
|
|
1119
|
+
case "agent_permission_response":
|
|
1120
|
+
return this.handleAgentPermissionResponse(msg.agentId, msg.requestId, msg.response);
|
|
1121
|
+
case "clear_agent_attention":
|
|
1122
|
+
return this.handleClearAgentAttention(msg.agentId, msg.requestId);
|
|
1123
|
+
default:
|
|
1124
|
+
return undefined;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
dispatchAgentConfigMessage(msg) {
|
|
1128
|
+
switch (msg.type) {
|
|
1129
|
+
case "set_agent_mode_request":
|
|
1130
|
+
return this.handleSetAgentModeRequest(msg.agentId, msg.modeId, msg.requestId);
|
|
1131
|
+
case "set_agent_model_request":
|
|
1132
|
+
return this.handleSetAgentModelRequest(msg.agentId, msg.modelId, msg.requestId);
|
|
1133
|
+
case "set_agent_feature_request":
|
|
1134
|
+
return this.handleSetAgentFeatureRequest(msg.agentId, msg.featureId, msg.value, msg.requestId);
|
|
1135
|
+
case "set_agent_thinking_request":
|
|
1136
|
+
return this.handleSetAgentThinkingRequest(msg.agentId, msg.thinkingOptionId, msg.requestId);
|
|
1137
|
+
case "get_daemon_config_request":
|
|
1138
|
+
this.emit({
|
|
1139
|
+
type: "get_daemon_config_response",
|
|
1140
|
+
payload: { requestId: msg.requestId, config: this.daemonConfigStore.get() },
|
|
1141
|
+
});
|
|
1142
|
+
return undefined;
|
|
1143
|
+
case "set_daemon_config_request":
|
|
1144
|
+
this.emit({
|
|
1145
|
+
type: "set_daemon_config_response",
|
|
1146
|
+
payload: {
|
|
1147
|
+
requestId: msg.requestId,
|
|
1148
|
+
config: this.daemonConfigStore.patch(msg.config),
|
|
1149
|
+
},
|
|
1150
|
+
});
|
|
1151
|
+
return undefined;
|
|
1152
|
+
case "read_project_config_request":
|
|
1153
|
+
return this.handleReadProjectConfigRequest(msg);
|
|
1154
|
+
case "write_project_config_request":
|
|
1155
|
+
return this.handleWriteProjectConfigRequest(msg);
|
|
1156
|
+
default:
|
|
1157
|
+
return undefined;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
async handleReadProjectConfigRequest(msg) {
|
|
1161
|
+
const repoRoot = await resolveKnownProjectRootForConfig({
|
|
1162
|
+
repoRoot: msg.repoRoot,
|
|
1163
|
+
projectRegistry: this.projectRegistry,
|
|
1164
|
+
});
|
|
1165
|
+
if (!repoRoot) {
|
|
1166
|
+
this.emitProjectConfigReadFailure(msg, { code: "project_not_found" });
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
const result = readPaseoConfigForEdit(repoRoot);
|
|
1170
|
+
if (!result.ok) {
|
|
1171
|
+
this.sessionLogger.warn({ repoRoot, requestId: msg.requestId, outcome: result.error.code }, "Failed to read project config");
|
|
1172
|
+
this.emitProjectConfigReadFailure(msg, result.error, repoRoot);
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
if (result.config === null) {
|
|
1176
|
+
this.sessionLogger.debug({ repoRoot, requestId: msg.requestId, outcome: "missing_project_config" }, "Project config missing");
|
|
1177
|
+
}
|
|
1178
|
+
this.emit({
|
|
1179
|
+
type: "read_project_config_response",
|
|
1180
|
+
payload: {
|
|
1181
|
+
requestId: msg.requestId,
|
|
1182
|
+
repoRoot,
|
|
1183
|
+
ok: true,
|
|
1184
|
+
config: result.config,
|
|
1185
|
+
revision: result.revision,
|
|
1186
|
+
},
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
async handleWriteProjectConfigRequest(msg) {
|
|
1190
|
+
const repoRoot = await resolveKnownProjectRootForConfig({
|
|
1191
|
+
repoRoot: msg.repoRoot,
|
|
1192
|
+
projectRegistry: this.projectRegistry,
|
|
1193
|
+
});
|
|
1194
|
+
if (!repoRoot) {
|
|
1195
|
+
this.emitProjectConfigWriteFailure(msg, { code: "project_not_found" });
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
this.sessionLogger.debug({ repoRoot, requestId: msg.requestId, outcome: "write_attempt" }, "Writing project config");
|
|
1199
|
+
const result = writePaseoConfigForEdit({
|
|
1200
|
+
repoRoot,
|
|
1201
|
+
config: msg.config,
|
|
1202
|
+
expectedRevision: msg.expectedRevision,
|
|
1203
|
+
});
|
|
1204
|
+
if (!result.ok) {
|
|
1205
|
+
this.sessionLogger.debug({ repoRoot, requestId: msg.requestId, outcome: result.error.code }, "Project config write did not complete");
|
|
1206
|
+
this.emitProjectConfigWriteFailure(msg, result.error, repoRoot);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
this.sessionLogger.debug({ repoRoot, requestId: msg.requestId, outcome: "written" }, "Project config written");
|
|
1210
|
+
this.emit({
|
|
1211
|
+
type: "write_project_config_response",
|
|
1212
|
+
payload: {
|
|
1213
|
+
requestId: msg.requestId,
|
|
1214
|
+
repoRoot,
|
|
1215
|
+
ok: true,
|
|
1216
|
+
config: result.config,
|
|
1217
|
+
revision: result.revision,
|
|
1218
|
+
},
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
emitProjectConfigReadFailure(msg, error, repoRoot = msg.repoRoot) {
|
|
1222
|
+
this.emit({
|
|
1223
|
+
type: "read_project_config_response",
|
|
1224
|
+
payload: {
|
|
1225
|
+
requestId: msg.requestId,
|
|
1226
|
+
repoRoot,
|
|
1227
|
+
ok: false,
|
|
1228
|
+
error,
|
|
1229
|
+
},
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
emitProjectConfigWriteFailure(msg, error, repoRoot = msg.repoRoot) {
|
|
1233
|
+
this.emit({
|
|
1234
|
+
type: "write_project_config_response",
|
|
1235
|
+
payload: {
|
|
1236
|
+
requestId: msg.requestId,
|
|
1237
|
+
repoRoot,
|
|
1238
|
+
ok: false,
|
|
1239
|
+
error,
|
|
1240
|
+
},
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
dispatchCheckoutMessage(msg) {
|
|
1244
|
+
switch (msg.type) {
|
|
1245
|
+
case "checkout_status_request":
|
|
1246
|
+
return this.handleCheckoutStatusRequest(msg);
|
|
1247
|
+
case "validate_branch_request":
|
|
1248
|
+
return this.handleValidateBranchRequest(msg);
|
|
1249
|
+
case "branch_suggestions_request":
|
|
1250
|
+
return this.handleBranchSuggestionsRequest(msg);
|
|
1251
|
+
case "directory_suggestions_request":
|
|
1252
|
+
return this.handleDirectorySuggestionsRequest(msg);
|
|
1253
|
+
case "subscribe_checkout_diff_request":
|
|
1254
|
+
return this.handleSubscribeCheckoutDiffRequest(msg);
|
|
1255
|
+
case "unsubscribe_checkout_diff_request":
|
|
1256
|
+
this.handleUnsubscribeCheckoutDiffRequest(msg);
|
|
1257
|
+
return undefined;
|
|
1258
|
+
case "checkout_switch_branch_request":
|
|
1259
|
+
return this.handleCheckoutSwitchBranchRequest(msg);
|
|
1260
|
+
case "stash_save_request":
|
|
1261
|
+
return this.handleStashSaveRequest(msg);
|
|
1262
|
+
case "stash_pop_request":
|
|
1263
|
+
return this.handleStashPopRequest(msg);
|
|
1264
|
+
case "stash_list_request":
|
|
1265
|
+
return this.handleStashListRequest(msg);
|
|
1266
|
+
case "checkout_commit_request":
|
|
1267
|
+
return this.handleCheckoutCommitRequest(msg);
|
|
1268
|
+
case "checkout_merge_request":
|
|
1269
|
+
return this.handleCheckoutMergeRequest(msg);
|
|
1270
|
+
case "checkout_merge_from_base_request":
|
|
1271
|
+
return this.handleCheckoutMergeFromBaseRequest(msg);
|
|
1272
|
+
case "checkout_pull_request":
|
|
1273
|
+
return this.handleCheckoutPullRequest(msg);
|
|
1274
|
+
case "checkout_push_request":
|
|
1275
|
+
return this.handleCheckoutPushRequest(msg);
|
|
1276
|
+
case "checkout_pr_create_request":
|
|
1277
|
+
return this.handleCheckoutPrCreateRequest(msg);
|
|
1278
|
+
case "checkout_pr_status_request":
|
|
1279
|
+
return this.handleCheckoutPrStatusRequest(msg);
|
|
1280
|
+
case "pull_request_timeline_request":
|
|
1281
|
+
return this.handlePullRequestTimelineRequest(msg);
|
|
1282
|
+
case "github_search_request":
|
|
1283
|
+
return this.handleGitHubSearchRequest(msg);
|
|
1284
|
+
default:
|
|
1285
|
+
return undefined;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
dispatchWorkspaceAndProjectMessage(msg) {
|
|
1289
|
+
switch (msg.type) {
|
|
1290
|
+
case "fetch_workspaces_request":
|
|
1291
|
+
return this.handleFetchWorkspacesRequest(msg);
|
|
1292
|
+
case "paseo_worktree_list_request":
|
|
1293
|
+
return this.handlePaseoWorktreeListRequest(msg);
|
|
1294
|
+
case "paseo_worktree_archive_request":
|
|
1295
|
+
return this.handlePaseoWorktreeArchiveRequest(msg);
|
|
1296
|
+
case "create_paseo_worktree_request":
|
|
1297
|
+
return this.handleCreatePaseoWorktreeRequest(msg);
|
|
1298
|
+
case "workspace_setup_status_request":
|
|
1299
|
+
return this.handleWorkspaceSetupStatusRequest(msg);
|
|
1300
|
+
case "list_available_editors_request":
|
|
1301
|
+
return this.handleListAvailableEditorsRequest(msg);
|
|
1302
|
+
case "open_in_editor_request":
|
|
1303
|
+
return this.handleOpenInEditorRequest(msg);
|
|
1304
|
+
case "open_project_request":
|
|
1305
|
+
return this.handleOpenProjectRequest(msg);
|
|
1306
|
+
case "archive_workspace_request":
|
|
1307
|
+
return this.handleArchiveWorkspaceRequest(msg);
|
|
1308
|
+
case "file_explorer_request":
|
|
1309
|
+
return this.handleFileExplorerRequest(msg);
|
|
1310
|
+
case "project_icon_request":
|
|
1311
|
+
return this.handleProjectIconRequest(msg);
|
|
1312
|
+
case "file_download_token_request":
|
|
1313
|
+
return this.handleFileDownloadTokenRequest(msg);
|
|
1314
|
+
default:
|
|
1315
|
+
return undefined;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
dispatchProviderMessage(msg) {
|
|
1319
|
+
switch (msg.type) {
|
|
1320
|
+
case "list_provider_models_request":
|
|
1321
|
+
return this.handleListProviderModelsRequest(msg);
|
|
1322
|
+
case "list_provider_modes_request":
|
|
1323
|
+
return this.handleListProviderModesRequest(msg);
|
|
1324
|
+
case "list_provider_features_request":
|
|
1325
|
+
return this.handleListProviderFeaturesRequest(msg);
|
|
1326
|
+
case "list_available_providers_request":
|
|
1327
|
+
return this.handleListAvailableProvidersRequest(msg);
|
|
1328
|
+
case "get_providers_snapshot_request":
|
|
1329
|
+
return this.handleGetProvidersSnapshotRequest(msg);
|
|
1330
|
+
case "refresh_providers_snapshot_request":
|
|
1331
|
+
return this.handleRefreshProvidersSnapshotRequest(msg);
|
|
1332
|
+
case "provider_diagnostic_request":
|
|
1333
|
+
return this.handleProviderDiagnosticRequest(msg);
|
|
1334
|
+
default:
|
|
1335
|
+
return undefined;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
dispatchTerminalMessage(msg) {
|
|
1339
|
+
switch (msg.type) {
|
|
1340
|
+
case "subscribe_terminals_request":
|
|
1341
|
+
this.handleSubscribeTerminalsRequest(msg);
|
|
1342
|
+
return undefined;
|
|
1343
|
+
case "unsubscribe_terminals_request":
|
|
1344
|
+
this.handleUnsubscribeTerminalsRequest(msg);
|
|
1345
|
+
return undefined;
|
|
1346
|
+
case "list_terminals_request":
|
|
1347
|
+
return this.handleListTerminalsRequest(msg);
|
|
1348
|
+
case "create_terminal_request":
|
|
1349
|
+
return this.handleCreateTerminalRequest(msg);
|
|
1350
|
+
case "start_workspace_script_request":
|
|
1351
|
+
return this.handleStartWorkspaceScriptRequest(msg);
|
|
1352
|
+
case "subscribe_terminal_request":
|
|
1353
|
+
return this.handleSubscribeTerminalRequest(msg);
|
|
1354
|
+
case "unsubscribe_terminal_request":
|
|
1355
|
+
this.handleUnsubscribeTerminalRequest(msg);
|
|
1356
|
+
return undefined;
|
|
1357
|
+
case "terminal_input":
|
|
1358
|
+
this.handleTerminalInput(msg);
|
|
1359
|
+
return undefined;
|
|
1360
|
+
case "kill_terminal_request":
|
|
1361
|
+
return this.handleKillTerminalRequest(msg);
|
|
1362
|
+
case "capture_terminal_request":
|
|
1363
|
+
return this.handleCaptureTerminalRequest(msg);
|
|
1364
|
+
default:
|
|
1365
|
+
return undefined;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
dispatchChatScheduleLoopMessage(msg) {
|
|
1369
|
+
switch (msg.type) {
|
|
1370
|
+
case "chat/create":
|
|
1371
|
+
return this.handleChatCreateRequest(msg);
|
|
1372
|
+
case "chat/list":
|
|
1373
|
+
return this.handleChatListRequest(msg);
|
|
1374
|
+
case "chat/inspect":
|
|
1375
|
+
return this.handleChatInspectRequest(msg);
|
|
1376
|
+
case "chat/delete":
|
|
1377
|
+
return this.handleChatDeleteRequest(msg);
|
|
1378
|
+
case "chat/post":
|
|
1379
|
+
return this.handleChatPostRequest(msg);
|
|
1380
|
+
case "chat/read":
|
|
1381
|
+
return this.handleChatReadRequest(msg);
|
|
1382
|
+
case "chat/wait":
|
|
1383
|
+
return this.handleChatWaitRequest(msg);
|
|
1384
|
+
case "schedule/create":
|
|
1385
|
+
return this.handleScheduleCreateRequest(msg);
|
|
1386
|
+
case "schedule/list":
|
|
1387
|
+
return this.handleScheduleListRequest(msg);
|
|
1388
|
+
case "schedule/inspect":
|
|
1389
|
+
return this.handleScheduleInspectRequest(msg);
|
|
1390
|
+
case "schedule/logs":
|
|
1391
|
+
return this.handleScheduleLogsRequest(msg);
|
|
1392
|
+
case "schedule/pause":
|
|
1393
|
+
return this.handleSchedulePauseRequest(msg);
|
|
1394
|
+
case "schedule/resume":
|
|
1395
|
+
return this.handleScheduleResumeRequest(msg);
|
|
1396
|
+
case "schedule/delete":
|
|
1397
|
+
return this.handleScheduleDeleteRequest(msg);
|
|
1398
|
+
case "loop/run":
|
|
1399
|
+
return this.handleLoopRunRequest(msg);
|
|
1400
|
+
case "loop/list":
|
|
1401
|
+
return this.handleLoopListRequest(msg);
|
|
1402
|
+
case "loop/inspect":
|
|
1403
|
+
return this.handleLoopInspectRequest(msg);
|
|
1404
|
+
case "loop/logs":
|
|
1405
|
+
return this.handleLoopLogsRequest(msg);
|
|
1406
|
+
case "loop/stop":
|
|
1407
|
+
return this.handleLoopStopRequest(msg);
|
|
1408
|
+
default:
|
|
1409
|
+
return undefined;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
async dispatchMiscMessage(msg) {
|
|
1413
|
+
switch (msg.type) {
|
|
1414
|
+
case "list_commands_request":
|
|
1415
|
+
await this.handleListCommandsRequest(msg);
|
|
1416
|
+
return;
|
|
1417
|
+
case "register_push_token":
|
|
1418
|
+
this.handleRegisterPushToken(msg.token);
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1244
1422
|
resetPeakInflight() {
|
|
1245
1423
|
this.peakInflightRequests = this.inflightRequests;
|
|
1246
1424
|
}
|
|
@@ -1441,13 +1619,15 @@ export class Session {
|
|
|
1441
1619
|
return { agentId, archivedAt: archivedRecord.archivedAt };
|
|
1442
1620
|
}
|
|
1443
1621
|
async handleCloseItemsRequest(msg) {
|
|
1622
|
+
const archiveResults = await Promise.allSettled(msg.agentIds.map((agentId) => this.archiveAgentForClose(agentId)));
|
|
1444
1623
|
const agents = [];
|
|
1445
|
-
for (
|
|
1446
|
-
|
|
1447
|
-
|
|
1624
|
+
for (let i = 0; i < archiveResults.length; i += 1) {
|
|
1625
|
+
const result = archiveResults[i];
|
|
1626
|
+
if (result.status === "fulfilled") {
|
|
1627
|
+
agents.push(result.value);
|
|
1448
1628
|
}
|
|
1449
|
-
|
|
1450
|
-
this.sessionLogger.warn({ err:
|
|
1629
|
+
else {
|
|
1630
|
+
this.sessionLogger.warn({ err: result.reason, agentId: msg.agentIds[i], requestId: msg.requestId }, "Failed to archive agent during close_items batch");
|
|
1451
1631
|
}
|
|
1452
1632
|
}
|
|
1453
1633
|
const terminals = [];
|
|
@@ -1529,7 +1709,9 @@ export class Session {
|
|
|
1529
1709
|
requestId,
|
|
1530
1710
|
agentId,
|
|
1531
1711
|
accepted: false,
|
|
1532
|
-
error: error?.message
|
|
1712
|
+
error: error?.message
|
|
1713
|
+
? String(error.message)
|
|
1714
|
+
: "Failed to update agent",
|
|
1533
1715
|
},
|
|
1534
1716
|
});
|
|
1535
1717
|
}
|
|
@@ -1899,24 +2081,15 @@ export class Session {
|
|
|
1899
2081
|
initialPrompt: trimmedPrompt,
|
|
1900
2082
|
});
|
|
1901
2083
|
await this.forwardAgentUpdate(snapshot);
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
deps: {
|
|
1912
|
-
workspaceGitService: this.workspaceGitService,
|
|
1913
|
-
},
|
|
1914
|
-
});
|
|
1915
|
-
const started = await this.handleSendAgentMessage(snapshot.id, trimmedPrompt || "", resolveClientMessageId(clientMessageId), images, attachments, outputSchema ? { outputSchema } : undefined);
|
|
1916
|
-
if (!started.ok) {
|
|
1917
|
-
throw new Error(started.error);
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
2084
|
+
await this.sendInitialCreateAgentPrompt({
|
|
2085
|
+
snapshot,
|
|
2086
|
+
trimmedPrompt,
|
|
2087
|
+
images,
|
|
2088
|
+
attachments,
|
|
2089
|
+
clientMessageId,
|
|
2090
|
+
outputSchema,
|
|
2091
|
+
explicitTitle,
|
|
2092
|
+
});
|
|
1920
2093
|
if (requestId) {
|
|
1921
2094
|
const agentPayload = await this.buildAgentPayload(snapshot);
|
|
1922
2095
|
this.emit({
|
|
@@ -1975,6 +2148,31 @@ export class Session {
|
|
|
1975
2148
|
});
|
|
1976
2149
|
}
|
|
1977
2150
|
}
|
|
2151
|
+
async sendInitialCreateAgentPrompt(params) {
|
|
2152
|
+
const { snapshot, trimmedPrompt, images, attachments, clientMessageId, outputSchema } = params;
|
|
2153
|
+
const hasPrompt = Boolean(trimmedPrompt);
|
|
2154
|
+
const hasImages = (images?.length ?? 0) > 0;
|
|
2155
|
+
const hasAttachments = (attachments?.length ?? 0) > 0;
|
|
2156
|
+
if (!hasPrompt && !hasImages && !hasAttachments) {
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
scheduleAgentMetadataGeneration({
|
|
2160
|
+
agentManager: this.agentManager,
|
|
2161
|
+
agentId: snapshot.id,
|
|
2162
|
+
cwd: snapshot.cwd,
|
|
2163
|
+
initialPrompt: trimmedPrompt,
|
|
2164
|
+
explicitTitle: params.explicitTitle,
|
|
2165
|
+
paseoHome: this.paseoHome,
|
|
2166
|
+
logger: this.sessionLogger,
|
|
2167
|
+
deps: {
|
|
2168
|
+
workspaceGitService: this.workspaceGitService,
|
|
2169
|
+
},
|
|
2170
|
+
});
|
|
2171
|
+
const started = await this.handleSendAgentMessage(snapshot.id, trimmedPrompt || "", resolveClientMessageId(clientMessageId), images, attachments, outputSchema ? { outputSchema } : undefined);
|
|
2172
|
+
if (!started.ok) {
|
|
2173
|
+
throw new Error(started.error);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
1978
2176
|
async handleResumeAgentRequest(msg) {
|
|
1979
2177
|
const { handle, overrides, requestId } = msg;
|
|
1980
2178
|
if (!handle) {
|
|
@@ -2041,7 +2239,11 @@ export class Session {
|
|
|
2041
2239
|
if (!record) {
|
|
2042
2240
|
throw new Error(`Agent not found: ${agentId}`);
|
|
2043
2241
|
}
|
|
2044
|
-
const
|
|
2242
|
+
const providerRegistry = this.getProviderRegistry();
|
|
2243
|
+
if (!isStoredAgentProviderAvailable(record, Object.keys(providerRegistry))) {
|
|
2244
|
+
throw new Error(`Agent ${agentId} references unavailable provider '${record.provider}'`);
|
|
2245
|
+
}
|
|
2246
|
+
const handle = toAgentPersistenceHandle(providerRegistry, record.persistence);
|
|
2045
2247
|
if (!handle) {
|
|
2046
2248
|
throw new Error(`Agent ${agentId} cannot be refreshed because it lacks persistence`);
|
|
2047
2249
|
}
|
|
@@ -2107,13 +2309,32 @@ export class Session {
|
|
|
2107
2309
|
github: this.github,
|
|
2108
2310
|
}, config, gitOptions, legacyWorktreeName, attachments);
|
|
2109
2311
|
}
|
|
2312
|
+
emitProviderDisabledResponse(kind, provider, requestId, fetchedAt) {
|
|
2313
|
+
const payload = {
|
|
2314
|
+
provider,
|
|
2315
|
+
error: `Provider ${provider} is disabled`,
|
|
2316
|
+
fetchedAt,
|
|
2317
|
+
requestId,
|
|
2318
|
+
};
|
|
2319
|
+
if (kind === "models") {
|
|
2320
|
+
this.emit({ type: "list_provider_models_response", payload });
|
|
2321
|
+
}
|
|
2322
|
+
else {
|
|
2323
|
+
this.emit({ type: "list_provider_modes_response", payload });
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2110
2326
|
async handleListProviderModelsRequest(msg) {
|
|
2111
2327
|
const cwd = resolveSnapshotCwd(msg.cwd ? expandTilde(msg.cwd) : undefined);
|
|
2112
2328
|
const fetchedAt = new Date().toISOString();
|
|
2113
2329
|
const manager = this.providerSnapshotManager;
|
|
2114
2330
|
if (!manager) {
|
|
2115
2331
|
try {
|
|
2116
|
-
const
|
|
2332
|
+
const definition = this.getProviderRegistry()[msg.provider];
|
|
2333
|
+
if (!definition.enabled) {
|
|
2334
|
+
this.emitProviderDisabledResponse("models", msg.provider, msg.requestId, fetchedAt);
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
const models = await definition.fetchModels({
|
|
2117
2338
|
cwd,
|
|
2118
2339
|
force: false,
|
|
2119
2340
|
});
|
|
@@ -2155,6 +2376,10 @@ export class Session {
|
|
|
2155
2376
|
});
|
|
2156
2377
|
return;
|
|
2157
2378
|
}
|
|
2379
|
+
if (!entry.enabled) {
|
|
2380
|
+
this.emitProviderDisabledResponse("models", msg.provider, msg.requestId, fetchedAt);
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2158
2383
|
if (entry.status === "ready") {
|
|
2159
2384
|
this.emit({
|
|
2160
2385
|
type: "list_provider_models_response",
|
|
@@ -2199,6 +2424,10 @@ export class Session {
|
|
|
2199
2424
|
});
|
|
2200
2425
|
return;
|
|
2201
2426
|
}
|
|
2427
|
+
if (!entry.enabled) {
|
|
2428
|
+
this.emitProviderDisabledResponse("modes", msg.provider, msg.requestId, fetchedAt);
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2202
2431
|
if (entry.status === "ready") {
|
|
2203
2432
|
this.emit({
|
|
2204
2433
|
type: "list_provider_modes_response",
|
|
@@ -2227,7 +2456,12 @@ export class Session {
|
|
|
2227
2456
|
return;
|
|
2228
2457
|
}
|
|
2229
2458
|
try {
|
|
2230
|
-
const
|
|
2459
|
+
const definition = this.getProviderRegistry()[msg.provider];
|
|
2460
|
+
if (!definition.enabled) {
|
|
2461
|
+
this.emitProviderDisabledResponse("modes", msg.provider, msg.requestId, fetchedAt);
|
|
2462
|
+
return;
|
|
2463
|
+
}
|
|
2464
|
+
const modes = await definition.fetchModes({
|
|
2231
2465
|
cwd,
|
|
2232
2466
|
force: false,
|
|
2233
2467
|
});
|
|
@@ -2262,6 +2496,9 @@ export class Session {
|
|
|
2262
2496
|
}
|
|
2263
2497
|
const findEntry = () => manager.getSnapshot(cwd).find((candidate) => candidate.provider === provider);
|
|
2264
2498
|
let entry = findEntry();
|
|
2499
|
+
if (entry && !entry.enabled) {
|
|
2500
|
+
return entry;
|
|
2501
|
+
}
|
|
2265
2502
|
if (!entry || entry.status === "loading") {
|
|
2266
2503
|
// Awaits the in-flight warmup (deduped per-cwd) so old clients still get
|
|
2267
2504
|
// a resolved answer rather than a loading placeholder.
|
|
@@ -2374,7 +2611,7 @@ export class Session {
|
|
|
2374
2611
|
}
|
|
2375
2612
|
async handleProviderDiagnosticRequest(msg) {
|
|
2376
2613
|
try {
|
|
2377
|
-
const client = this.
|
|
2614
|
+
const client = this.getProviderRegistry()[msg.provider].createClient(this.sessionLogger);
|
|
2378
2615
|
const diagnostic = client.getDiagnostic
|
|
2379
2616
|
? (await client.getDiagnostic()).diagnostic
|
|
2380
2617
|
: "No diagnostic available for this provider.";
|
|
@@ -2431,7 +2668,7 @@ export class Session {
|
|
|
2431
2668
|
? [
|
|
2432
2669
|
"Files changed:",
|
|
2433
2670
|
...diff.structured.map((file) => {
|
|
2434
|
-
const changeType = file
|
|
2671
|
+
const changeType = diffChangeTypeFor(file);
|
|
2435
2672
|
const status = file.status && file.status !== "ok" ? ` [${file.status}]` : "";
|
|
2436
2673
|
return `${changeType}\t${file.path}\t(+${file.additions} -${file.deletions})${status}`;
|
|
2437
2674
|
}),
|
|
@@ -2487,7 +2724,7 @@ export class Session {
|
|
|
2487
2724
|
? [
|
|
2488
2725
|
"Files changed:",
|
|
2489
2726
|
...diff.structured.map((file) => {
|
|
2490
|
-
const changeType = file
|
|
2727
|
+
const changeType = diffChangeTypeFor(file);
|
|
2491
2728
|
const status = file.status && file.status !== "ok" ? ` [${file.status}]` : "";
|
|
2492
2729
|
return `${changeType}\t${file.path}\t(+${file.additions} -${file.deletions})${status}`;
|
|
2493
2730
|
}),
|
|
@@ -2543,7 +2780,9 @@ export class Session {
|
|
|
2543
2780
|
return snapshot.git.isDirty === true;
|
|
2544
2781
|
}
|
|
2545
2782
|
catch (error) {
|
|
2546
|
-
throw new Error(`Unable to inspect git status for ${cwd}: ${error.message}
|
|
2783
|
+
throw new Error(`Unable to inspect git status for ${cwd}: ${error.message}`, {
|
|
2784
|
+
cause: error,
|
|
2785
|
+
});
|
|
2547
2786
|
}
|
|
2548
2787
|
}
|
|
2549
2788
|
async checkoutExistingBranch(cwd, branch) {
|
|
@@ -2623,7 +2862,9 @@ export class Session {
|
|
|
2623
2862
|
requestId,
|
|
2624
2863
|
agentId,
|
|
2625
2864
|
accepted: false,
|
|
2626
|
-
error: error?.message
|
|
2865
|
+
error: error?.message
|
|
2866
|
+
? String(error.message)
|
|
2867
|
+
: "Failed to set agent mode",
|
|
2627
2868
|
},
|
|
2628
2869
|
});
|
|
2629
2870
|
}
|
|
@@ -2655,7 +2896,9 @@ export class Session {
|
|
|
2655
2896
|
requestId,
|
|
2656
2897
|
agentId,
|
|
2657
2898
|
accepted: false,
|
|
2658
|
-
error: error?.message
|
|
2899
|
+
error: error?.message
|
|
2900
|
+
? String(error.message)
|
|
2901
|
+
: "Failed to set agent model",
|
|
2659
2902
|
},
|
|
2660
2903
|
});
|
|
2661
2904
|
}
|
|
@@ -2687,7 +2930,9 @@ export class Session {
|
|
|
2687
2930
|
requestId,
|
|
2688
2931
|
agentId,
|
|
2689
2932
|
accepted: false,
|
|
2690
|
-
error: error?.message
|
|
2933
|
+
error: error?.message
|
|
2934
|
+
? String(error.message)
|
|
2935
|
+
: "Failed to set agent feature",
|
|
2691
2936
|
},
|
|
2692
2937
|
});
|
|
2693
2938
|
}
|
|
@@ -2719,7 +2964,9 @@ export class Session {
|
|
|
2719
2964
|
requestId,
|
|
2720
2965
|
agentId,
|
|
2721
2966
|
accepted: false,
|
|
2722
|
-
error: error?.message
|
|
2967
|
+
error: error?.message
|
|
2968
|
+
? String(error.message)
|
|
2969
|
+
: "Failed to set agent thinking option",
|
|
2723
2970
|
},
|
|
2724
2971
|
});
|
|
2725
2972
|
}
|
|
@@ -3105,9 +3352,9 @@ export class Session {
|
|
|
3105
3352
|
this.workspaceGitSubscriptions.get(normalizedCwd)?.();
|
|
3106
3353
|
this.workspaceGitSubscriptions.delete(normalizedCwd);
|
|
3107
3354
|
}
|
|
3108
|
-
|
|
3355
|
+
workspaceGitDescriptorStateKey(workspace) {
|
|
3109
3356
|
if (!workspace) {
|
|
3110
|
-
return
|
|
3357
|
+
return WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY;
|
|
3111
3358
|
}
|
|
3112
3359
|
return JSON.stringify([
|
|
3113
3360
|
workspace.name,
|
|
@@ -3119,34 +3366,30 @@ export class Session {
|
|
|
3119
3366
|
if (!target) {
|
|
3120
3367
|
return false;
|
|
3121
3368
|
}
|
|
3122
|
-
const
|
|
3123
|
-
if (target.
|
|
3369
|
+
const nextStateKey = this.workspaceGitDescriptorStateKey(workspace);
|
|
3370
|
+
if (target.latestDescriptorStateKey === nextStateKey) {
|
|
3124
3371
|
return true;
|
|
3125
3372
|
}
|
|
3126
|
-
target.
|
|
3373
|
+
target.latestDescriptorStateKey = nextStateKey;
|
|
3127
3374
|
return false;
|
|
3128
3375
|
}
|
|
3129
|
-
|
|
3376
|
+
rememberWorkspaceGitDescriptorState(workspaceId, workspace) {
|
|
3130
3377
|
const target = this.workspaceGitWatchTargets.get(workspaceId);
|
|
3131
3378
|
if (!target) {
|
|
3132
3379
|
return;
|
|
3133
3380
|
}
|
|
3134
|
-
target.
|
|
3381
|
+
target.latestDescriptorStateKey = this.workspaceGitDescriptorStateKey(workspace);
|
|
3135
3382
|
target.lastBranchName = workspace?.name ?? null;
|
|
3136
3383
|
}
|
|
3137
|
-
|
|
3384
|
+
syncWorkspaceGitObservers(workspaces) {
|
|
3138
3385
|
for (const workspace of workspaces) {
|
|
3139
|
-
|
|
3140
|
-
if (!persistedWorkspace) {
|
|
3141
|
-
continue;
|
|
3142
|
-
}
|
|
3143
|
-
await this.syncWorkspaceGitWatchTarget(persistedWorkspace.cwd, {
|
|
3386
|
+
this.syncWorkspaceGitObserver(workspace.workspaceDirectory, {
|
|
3144
3387
|
isGit: workspace.projectKind === "git",
|
|
3145
3388
|
});
|
|
3146
|
-
this.
|
|
3389
|
+
this.rememberWorkspaceGitDescriptorState(workspace.workspaceDirectory, workspace);
|
|
3147
3390
|
}
|
|
3148
3391
|
}
|
|
3149
|
-
|
|
3392
|
+
syncWorkspaceGitObserver(cwd, options) {
|
|
3150
3393
|
const normalizedCwd = normalizePersistedWorkspaceId(cwd);
|
|
3151
3394
|
if (!options.isGit) {
|
|
3152
3395
|
this.removeWorkspaceGitSubscription(normalizedCwd);
|
|
@@ -3155,7 +3398,7 @@ export class Session {
|
|
|
3155
3398
|
if (this.workspaceGitSubscriptions.has(normalizedCwd)) {
|
|
3156
3399
|
return;
|
|
3157
3400
|
}
|
|
3158
|
-
const subscription =
|
|
3401
|
+
const subscription = this.workspaceGitService.registerWorkspace({ cwd: normalizedCwd }, (snapshot) => {
|
|
3159
3402
|
void this.emitWorkspaceUpdateForCwd(normalizedCwd);
|
|
3160
3403
|
this.emitCheckoutStatusUpdate(normalizedCwd, snapshot);
|
|
3161
3404
|
});
|
|
@@ -3236,6 +3479,7 @@ export class Session {
|
|
|
3236
3479
|
cwd,
|
|
3237
3480
|
isGit: true,
|
|
3238
3481
|
repoRoot: snapshot.git.repoRoot,
|
|
3482
|
+
mainRepoRoot: snapshot.git.mainRepoRoot,
|
|
3239
3483
|
currentBranch: snapshot.git.currentBranch ?? null,
|
|
3240
3484
|
isDirty: snapshot.git.isDirty,
|
|
3241
3485
|
baseRef: snapshot.git.baseRef ?? null,
|
|
@@ -3326,7 +3570,9 @@ export class Session {
|
|
|
3326
3570
|
const message = branchLabel
|
|
3327
3571
|
? `${Session.PASEO_STASH_PREFIX} ${branchLabel}`
|
|
3328
3572
|
: `${Session.PASEO_STASH_PREFIX} unnamed`;
|
|
3329
|
-
await execCommand("git", ["stash", "push", "--include-untracked", "-m", message], {
|
|
3573
|
+
await execCommand("git", ["stash", "push", "--include-untracked", "-m", message], {
|
|
3574
|
+
cwd,
|
|
3575
|
+
});
|
|
3330
3576
|
await this.notifyGitMutation(cwd, "stash-push");
|
|
3331
3577
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
3332
3578
|
this.emit({
|
|
@@ -3344,7 +3590,9 @@ export class Session {
|
|
|
3344
3590
|
async handleStashPopRequest(msg) {
|
|
3345
3591
|
const { cwd, stashIndex, requestId } = msg;
|
|
3346
3592
|
try {
|
|
3347
|
-
await execCommand("git", ["stash", "pop", `stash@{${stashIndex}}`], {
|
|
3593
|
+
await execCommand("git", ["stash", "pop", `stash@{${stashIndex}}`], {
|
|
3594
|
+
cwd,
|
|
3595
|
+
});
|
|
3348
3596
|
await this.notifyGitMutation(cwd, "stash-pop");
|
|
3349
3597
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
3350
3598
|
this.emit({
|
|
@@ -3572,7 +3820,7 @@ export class Session {
|
|
|
3572
3820
|
title,
|
|
3573
3821
|
body,
|
|
3574
3822
|
base: msg.baseRef,
|
|
3575
|
-
}, this.github
|
|
3823
|
+
}, this.github);
|
|
3576
3824
|
await this.notifyGitMutation(cwd, "create-pr", { invalidateGithub: true });
|
|
3577
3825
|
this.emit({
|
|
3578
3826
|
type: "checkout_pr_create_response",
|
|
@@ -3916,9 +4164,12 @@ export class Session {
|
|
|
3916
4164
|
// (excluding internal agents which are for ephemeral system tasks)
|
|
3917
4165
|
const registryRecords = await this.agentStorage.list();
|
|
3918
4166
|
const liveIds = new Set(agentSnapshots.map((a) => a.id));
|
|
4167
|
+
const registeredProviderIds = this.getRegisteredProviderIds();
|
|
3919
4168
|
const persistedAgents = registryRecords
|
|
3920
4169
|
.filter((record) => !liveIds.has(record.id) && !record.internal)
|
|
3921
|
-
.
|
|
4170
|
+
.filter((record) => filter?.includeUnavailablePersisted === true ||
|
|
4171
|
+
isStoredAgentProviderAvailable(record, registeredProviderIds))
|
|
4172
|
+
.map((record) => this.buildStoredAgentPayload(record, registeredProviderIds));
|
|
3922
4173
|
let agents = [...liveAgents, ...persistedAgents];
|
|
3923
4174
|
agents = agents.filter((agent) => this.isProviderVisibleToClient(agent.provider));
|
|
3924
4175
|
// Filter by labels if filter provided
|
|
@@ -4099,25 +4350,7 @@ export class Session {
|
|
|
4099
4350
|
if (!payload.values || typeof payload.values !== "object") {
|
|
4100
4351
|
throw new SessionRequestError("invalid_cursor", "Invalid fetch_agents cursor");
|
|
4101
4352
|
}
|
|
4102
|
-
const cursorSort =
|
|
4103
|
-
for (const item of payload.sort) {
|
|
4104
|
-
if (!item ||
|
|
4105
|
-
typeof item !== "object" ||
|
|
4106
|
-
typeof item.key !== "string" ||
|
|
4107
|
-
typeof item.direction !== "string") {
|
|
4108
|
-
throw new SessionRequestError("invalid_cursor", "Invalid fetch_agents cursor");
|
|
4109
|
-
}
|
|
4110
|
-
const key = item.key;
|
|
4111
|
-
const direction = item.direction;
|
|
4112
|
-
if ((key !== "status_priority" &&
|
|
4113
|
-
key !== "created_at" &&
|
|
4114
|
-
key !== "updated_at" &&
|
|
4115
|
-
key !== "title") ||
|
|
4116
|
-
(direction !== "asc" && direction !== "desc")) {
|
|
4117
|
-
throw new SessionRequestError("invalid_cursor", "Invalid fetch_agents cursor");
|
|
4118
|
-
}
|
|
4119
|
-
cursorSort.push({ key, direction });
|
|
4120
|
-
}
|
|
4353
|
+
const cursorSort = parseFetchAgentsCursorSort(payload.sort);
|
|
4121
4354
|
if (cursorSort.length !== sort.length ||
|
|
4122
4355
|
cursorSort.some((entry, index) => entry.key !== sort[index]?.key || entry.direction !== sort[index]?.direction)) {
|
|
4123
4356
|
throw new SessionRequestError("invalid_cursor", "fetch_agents cursor does not match current sort");
|
|
@@ -4149,18 +4382,49 @@ export class Session {
|
|
|
4149
4382
|
.filter((project) => !project.archivedAt)
|
|
4150
4383
|
.map((project) => [project.projectId, project]));
|
|
4151
4384
|
const placementsByCwd = new Map();
|
|
4152
|
-
|
|
4153
|
-
if (workspace.archivedAt)
|
|
4154
|
-
|
|
4155
|
-
}
|
|
4385
|
+
const pairs = persistedWorkspaces.flatMap((workspace) => {
|
|
4386
|
+
if (workspace.archivedAt)
|
|
4387
|
+
return [];
|
|
4156
4388
|
const project = activeProjects.get(workspace.projectId);
|
|
4157
|
-
if (!project)
|
|
4158
|
-
|
|
4159
|
-
}
|
|
4160
|
-
|
|
4389
|
+
if (!project)
|
|
4390
|
+
return [];
|
|
4391
|
+
return [{ workspace, project }];
|
|
4392
|
+
});
|
|
4393
|
+
const placements = await Promise.all(pairs.map(({ workspace, project }) => this.buildProjectPlacementForWorkspace(workspace, project)));
|
|
4394
|
+
for (let i = 0; i < pairs.length; i += 1) {
|
|
4395
|
+
placementsByCwd.set(normalizePersistedWorkspaceId(pairs[i].workspace.cwd), placements[i]);
|
|
4161
4396
|
}
|
|
4162
4397
|
return placementsByCwd;
|
|
4163
4398
|
}
|
|
4399
|
+
async collectFetchAgentsEntries(params) {
|
|
4400
|
+
const { candidates, limit, getPlacement, filter } = params;
|
|
4401
|
+
const matchedEntries = [];
|
|
4402
|
+
const batchSize = 25;
|
|
4403
|
+
for (let start = 0; start < candidates.length && matchedEntries.length <= limit; start += batchSize) {
|
|
4404
|
+
const batch = candidates.slice(start, start + batchSize);
|
|
4405
|
+
const batchEntries = await Promise.all(batch.map(async (agent) => {
|
|
4406
|
+
const project = await getPlacement(agent.cwd);
|
|
4407
|
+
return project ? { agent, project } : null;
|
|
4408
|
+
}));
|
|
4409
|
+
for (const entry of batchEntries) {
|
|
4410
|
+
if (!entry) {
|
|
4411
|
+
continue;
|
|
4412
|
+
}
|
|
4413
|
+
if (!this.matchesAgentFilter({
|
|
4414
|
+
agent: entry.agent,
|
|
4415
|
+
project: entry.project,
|
|
4416
|
+
filter,
|
|
4417
|
+
})) {
|
|
4418
|
+
continue;
|
|
4419
|
+
}
|
|
4420
|
+
matchedEntries.push(entry);
|
|
4421
|
+
if (matchedEntries.length > limit) {
|
|
4422
|
+
break;
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
return matchedEntries;
|
|
4427
|
+
}
|
|
4164
4428
|
async listFetchAgentsEntries(request) {
|
|
4165
4429
|
const filter = request.type === "fetch_agent_history_request" &&
|
|
4166
4430
|
request.filter?.includeArchived === undefined
|
|
@@ -4170,6 +4434,7 @@ export class Session {
|
|
|
4170
4434
|
const sort = this.normalizeFetchAgentsSort(request.sort);
|
|
4171
4435
|
let agents = await this.listAgentPayloads({
|
|
4172
4436
|
labels: filter?.labels,
|
|
4437
|
+
includeUnavailablePersisted: request.type === "fetch_agent_history_request",
|
|
4173
4438
|
});
|
|
4174
4439
|
const activePlacementsByCwd = scope === "active" ? await this.buildActiveProjectPlacementsByWorkspaceCwd() : null;
|
|
4175
4440
|
if (activePlacementsByCwd) {
|
|
@@ -4196,31 +4461,12 @@ export class Session {
|
|
|
4196
4461
|
candidates = candidates.filter((agent) => this.compareAgentWithCursor(agent, cursor, sort) > 0);
|
|
4197
4462
|
}
|
|
4198
4463
|
const limit = request.page?.limit ?? 200;
|
|
4199
|
-
const matchedEntries =
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
return project ? { agent, project } : null;
|
|
4206
|
-
}));
|
|
4207
|
-
for (const entry of batchEntries) {
|
|
4208
|
-
if (!entry) {
|
|
4209
|
-
continue;
|
|
4210
|
-
}
|
|
4211
|
-
if (!this.matchesAgentFilter({
|
|
4212
|
-
agent: entry.agent,
|
|
4213
|
-
project: entry.project,
|
|
4214
|
-
filter,
|
|
4215
|
-
})) {
|
|
4216
|
-
continue;
|
|
4217
|
-
}
|
|
4218
|
-
matchedEntries.push(entry);
|
|
4219
|
-
if (matchedEntries.length > limit) {
|
|
4220
|
-
break;
|
|
4221
|
-
}
|
|
4222
|
-
}
|
|
4223
|
-
}
|
|
4464
|
+
const matchedEntries = await this.collectFetchAgentsEntries({
|
|
4465
|
+
candidates,
|
|
4466
|
+
limit,
|
|
4467
|
+
getPlacement,
|
|
4468
|
+
filter,
|
|
4469
|
+
});
|
|
4224
4470
|
const pagedEntries = matchedEntries.slice(0, limit);
|
|
4225
4471
|
const hasMore = matchedEntries.length > limit;
|
|
4226
4472
|
const nextCursor = hasMore && pagedEntries.length > 0
|
|
@@ -4281,6 +4527,11 @@ export class Session {
|
|
|
4281
4527
|
resolveHealth: this.resolveScriptHealth ?? undefined,
|
|
4282
4528
|
})
|
|
4283
4529
|
: [],
|
|
4530
|
+
...(resolvedProjectRecord
|
|
4531
|
+
? {
|
|
4532
|
+
project: await this.buildProjectPlacementForWorkspace(workspace, resolvedProjectRecord),
|
|
4533
|
+
}
|
|
4534
|
+
: {}),
|
|
4284
4535
|
};
|
|
4285
4536
|
}
|
|
4286
4537
|
buildWorkspaceGitRuntimePayload(snapshot) {
|
|
@@ -4367,16 +4618,14 @@ export class Session {
|
|
|
4367
4618
|
const descriptorsByWorkspaceId = new Map();
|
|
4368
4619
|
const workspaceIds = options.workspaceIds ? new Set(options.workspaceIds) : null;
|
|
4369
4620
|
const workspaceIdsByDirectory = new Map(activeRecords.map((workspace) => [normalizePersistedWorkspaceId(workspace.cwd), workspace.workspaceId]));
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
includeGitData: options.includeGitData,
|
|
4379
|
-
}));
|
|
4621
|
+
const includedWorkspaces = activeRecords.filter((workspace) => !workspaceIds || workspaceIds.has(workspace.workspaceId));
|
|
4622
|
+
const workspaceDescriptors = await Promise.all(includedWorkspaces.map((workspace) => this.buildWorkspaceDescriptor({
|
|
4623
|
+
workspace,
|
|
4624
|
+
projectRecord: activeProjects.get(workspace.projectId) ?? null,
|
|
4625
|
+
includeGitData: options.includeGitData,
|
|
4626
|
+
})));
|
|
4627
|
+
for (let i = 0; i < includedWorkspaces.length; i += 1) {
|
|
4628
|
+
descriptorsByWorkspaceId.set(includedWorkspaces[i].workspaceId, workspaceDescriptors[i]);
|
|
4380
4629
|
}
|
|
4381
4630
|
for (const agent of agents) {
|
|
4382
4631
|
if (agent.archivedAt) {
|
|
@@ -4406,8 +4655,13 @@ export class Session {
|
|
|
4406
4655
|
if (exact) {
|
|
4407
4656
|
return exact.workspaceId;
|
|
4408
4657
|
}
|
|
4658
|
+
const userHome = homedir();
|
|
4409
4659
|
let bestMatch = null;
|
|
4410
4660
|
for (const workspace of workspaces) {
|
|
4661
|
+
if (workspace.cwd === userHome)
|
|
4662
|
+
continue;
|
|
4663
|
+
if (workspace.archivedAt)
|
|
4664
|
+
continue;
|
|
4411
4665
|
const prefix = workspace.cwd.endsWith(sep) ? workspace.cwd : `${workspace.cwd}${sep}`;
|
|
4412
4666
|
if (!normalizedCwd.startsWith(prefix)) {
|
|
4413
4667
|
continue;
|
|
@@ -4492,25 +4746,7 @@ export class Session {
|
|
|
4492
4746
|
if (!payload.values || typeof payload.values !== "object") {
|
|
4493
4747
|
throw new SessionRequestError("invalid_cursor", "Invalid fetch_workspaces cursor");
|
|
4494
4748
|
}
|
|
4495
|
-
const cursorSort =
|
|
4496
|
-
for (const item of payload.sort) {
|
|
4497
|
-
if (!item ||
|
|
4498
|
-
typeof item !== "object" ||
|
|
4499
|
-
typeof item.key !== "string" ||
|
|
4500
|
-
typeof item.direction !== "string") {
|
|
4501
|
-
throw new SessionRequestError("invalid_cursor", "Invalid fetch_workspaces cursor");
|
|
4502
|
-
}
|
|
4503
|
-
const key = item.key;
|
|
4504
|
-
const direction = item.direction;
|
|
4505
|
-
if ((key !== "status_priority" &&
|
|
4506
|
-
key !== "activity_at" &&
|
|
4507
|
-
key !== "name" &&
|
|
4508
|
-
key !== "project_id") ||
|
|
4509
|
-
(direction !== "asc" && direction !== "desc")) {
|
|
4510
|
-
throw new SessionRequestError("invalid_cursor", "Invalid fetch_workspaces cursor");
|
|
4511
|
-
}
|
|
4512
|
-
cursorSort.push({ key, direction });
|
|
4513
|
-
}
|
|
4749
|
+
const cursorSort = parseFetchWorkspacesCursorSort(payload.sort);
|
|
4514
4750
|
if (cursorSort.length !== sort.length ||
|
|
4515
4751
|
cursorSort.some((entry, index) => entry.key !== sort[index]?.key || entry.direction !== sort[index]?.direction)) {
|
|
4516
4752
|
throw new SessionRequestError("invalid_cursor", "fetch_workspaces cursor does not match current sort");
|
|
@@ -4637,41 +4873,121 @@ export class Session {
|
|
|
4637
4873
|
}
|
|
4638
4874
|
}
|
|
4639
4875
|
async findOrCreateWorkspaceForDirectory(cwd) {
|
|
4876
|
+
const inputCwd = normalizePersistedWorkspaceId(cwd);
|
|
4640
4877
|
const normalizedCwd = await this.resolveWorkspaceDirectory(cwd);
|
|
4641
|
-
const existingWorkspace = await this.
|
|
4878
|
+
const existingWorkspace = await this.findExactWorkspaceByDirectory(normalizedCwd, {
|
|
4879
|
+
refreshGit: false,
|
|
4880
|
+
});
|
|
4642
4881
|
if (existingWorkspace) {
|
|
4643
|
-
|
|
4882
|
+
if (existingWorkspace.archivedAt && inputCwd !== normalizedCwd) {
|
|
4883
|
+
const timestamp = new Date().toISOString();
|
|
4884
|
+
const displayName = basename(inputCwd) || inputCwd;
|
|
4885
|
+
const projectRecord = createPersistedProjectRecord({
|
|
4886
|
+
projectId: inputCwd,
|
|
4887
|
+
rootPath: inputCwd,
|
|
4888
|
+
kind: "non_git",
|
|
4889
|
+
displayName,
|
|
4890
|
+
createdAt: timestamp,
|
|
4891
|
+
updatedAt: timestamp,
|
|
4892
|
+
});
|
|
4893
|
+
await this.projectRegistry.upsert(projectRecord);
|
|
4894
|
+
const workspaceRecord = createPersistedWorkspaceRecord({
|
|
4895
|
+
workspaceId: inputCwd,
|
|
4896
|
+
projectId: projectRecord.projectId,
|
|
4897
|
+
cwd: inputCwd,
|
|
4898
|
+
kind: "directory",
|
|
4899
|
+
displayName,
|
|
4900
|
+
createdAt: timestamp,
|
|
4901
|
+
updatedAt: timestamp,
|
|
4902
|
+
});
|
|
4903
|
+
await this.workspaceRegistry.upsert(workspaceRecord);
|
|
4904
|
+
return workspaceRecord;
|
|
4905
|
+
}
|
|
4906
|
+
return this.reclassifyOrUnarchiveWorkspaceForDirectory({
|
|
4907
|
+
workspace: existingWorkspace,
|
|
4908
|
+
project: await this.projectRegistry.get(existingWorkspace.projectId),
|
|
4909
|
+
cwd: normalizedCwd,
|
|
4910
|
+
});
|
|
4644
4911
|
}
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
const
|
|
4912
|
+
return this.createWorkspaceForDirectory(normalizedCwd);
|
|
4913
|
+
}
|
|
4914
|
+
async createWorkspaceForDirectory(cwd) {
|
|
4915
|
+
const checkout = await this.workspaceGitService.getCheckout(cwd);
|
|
4916
|
+
const membership = classifyDirectoryForProjectMembership({ cwd, checkout });
|
|
4650
4917
|
const timestamp = new Date().toISOString();
|
|
4651
|
-
const projectRecord =
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
kind: deriveProjectKind(placement.checkout),
|
|
4655
|
-
displayName: placement.projectName,
|
|
4656
|
-
createdAt: timestamp,
|
|
4657
|
-
updatedAt: timestamp,
|
|
4918
|
+
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
4919
|
+
membership,
|
|
4920
|
+
timestamp,
|
|
4658
4921
|
});
|
|
4659
4922
|
await this.projectRegistry.upsert(projectRecord);
|
|
4660
4923
|
const workspaceRecord = createPersistedWorkspaceRecord({
|
|
4661
|
-
workspaceId,
|
|
4662
|
-
projectId:
|
|
4663
|
-
cwd
|
|
4664
|
-
kind:
|
|
4665
|
-
displayName:
|
|
4666
|
-
cwd: normalizedCwd,
|
|
4667
|
-
checkout: placement.checkout,
|
|
4668
|
-
}),
|
|
4924
|
+
workspaceId: membership.workspaceId,
|
|
4925
|
+
projectId: projectRecord.projectId,
|
|
4926
|
+
cwd,
|
|
4927
|
+
kind: membership.workspaceKind,
|
|
4928
|
+
displayName: membership.workspaceDisplayName,
|
|
4669
4929
|
createdAt: timestamp,
|
|
4670
4930
|
updatedAt: timestamp,
|
|
4671
4931
|
});
|
|
4672
4932
|
await this.workspaceRegistry.upsert(workspaceRecord);
|
|
4673
4933
|
return workspaceRecord;
|
|
4674
4934
|
}
|
|
4935
|
+
async reclassifyOrUnarchiveWorkspaceForDirectory(input) {
|
|
4936
|
+
const checkout = await this.workspaceGitService.getCheckout(input.cwd);
|
|
4937
|
+
const membership = classifyDirectoryForProjectMembership({ cwd: input.cwd, checkout });
|
|
4938
|
+
const timestamp = new Date().toISOString();
|
|
4939
|
+
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
4940
|
+
membership,
|
|
4941
|
+
timestamp,
|
|
4942
|
+
});
|
|
4943
|
+
const projectId = projectRecord.projectId;
|
|
4944
|
+
const kind = membership.workspaceKind;
|
|
4945
|
+
const displayName = membership.workspaceDisplayName;
|
|
4946
|
+
if (input.workspace.workspaceId === membership.workspaceId &&
|
|
4947
|
+
input.workspace.projectId === projectId &&
|
|
4948
|
+
input.workspace.kind === kind &&
|
|
4949
|
+
input.workspace.displayName === displayName) {
|
|
4950
|
+
return this.ensureWorkspaceRecordUnarchived(input.workspace);
|
|
4951
|
+
}
|
|
4952
|
+
await this.projectRegistry.upsert(projectRecord);
|
|
4953
|
+
const nextWorkspace = {
|
|
4954
|
+
...input.workspace,
|
|
4955
|
+
workspaceId: membership.workspaceId,
|
|
4956
|
+
projectId,
|
|
4957
|
+
cwd: input.cwd,
|
|
4958
|
+
kind,
|
|
4959
|
+
displayName,
|
|
4960
|
+
archivedAt: null,
|
|
4961
|
+
updatedAt: timestamp,
|
|
4962
|
+
};
|
|
4963
|
+
await this.workspaceRegistry.upsert(nextWorkspace);
|
|
4964
|
+
return nextWorkspace;
|
|
4965
|
+
}
|
|
4966
|
+
async resolveProjectRecordForPlacement(input) {
|
|
4967
|
+
const rootPath = input.membership.projectRootPath;
|
|
4968
|
+
const kind = input.membership.projectKind;
|
|
4969
|
+
const projects = await this.projectRegistry.list();
|
|
4970
|
+
const existingProject = projects.find((project) => !project.archivedAt && project.rootPath === rootPath) ??
|
|
4971
|
+
projects.find((project) => project.rootPath === rootPath) ??
|
|
4972
|
+
null;
|
|
4973
|
+
if (!existingProject) {
|
|
4974
|
+
return createPersistedProjectRecord({
|
|
4975
|
+
projectId: input.membership.projectKey,
|
|
4976
|
+
rootPath,
|
|
4977
|
+
kind,
|
|
4978
|
+
displayName: input.membership.projectName,
|
|
4979
|
+
createdAt: input.timestamp,
|
|
4980
|
+
updatedAt: input.timestamp,
|
|
4981
|
+
});
|
|
4982
|
+
}
|
|
4983
|
+
return {
|
|
4984
|
+
...existingProject,
|
|
4985
|
+
rootPath,
|
|
4986
|
+
kind,
|
|
4987
|
+
archivedAt: null,
|
|
4988
|
+
updatedAt: input.timestamp,
|
|
4989
|
+
};
|
|
4990
|
+
}
|
|
4675
4991
|
async ensureWorkspaceRecordUnarchived(workspace) {
|
|
4676
4992
|
const project = await this.projectRegistry.get(workspace.projectId);
|
|
4677
4993
|
if (!workspace.archivedAt && (!project || !project.archivedAt)) {
|
|
@@ -4753,7 +5069,7 @@ export class Session {
|
|
|
4753
5069
|
const result = await service.runOnce();
|
|
4754
5070
|
const changedWorkspaceIds = new Set();
|
|
4755
5071
|
const changedProjectIds = new Set();
|
|
4756
|
-
|
|
5072
|
+
await Promise.all(result.changesApplied.map(async (change) => {
|
|
4757
5073
|
switch (change.kind) {
|
|
4758
5074
|
case "workspace_archived":
|
|
4759
5075
|
await this.removeWorkspaceGitWatchTarget(change.directory);
|
|
@@ -4769,7 +5085,7 @@ export class Session {
|
|
|
4769
5085
|
changedProjectIds.add(change.projectId);
|
|
4770
5086
|
break;
|
|
4771
5087
|
}
|
|
4772
|
-
}
|
|
5088
|
+
}));
|
|
4773
5089
|
if (changedProjectIds.size > 0) {
|
|
4774
5090
|
for (const workspace of await this.workspaceRegistry.list()) {
|
|
4775
5091
|
if (changedProjectIds.has(workspace.projectId)) {
|
|
@@ -4808,7 +5124,7 @@ export class Session {
|
|
|
4808
5124
|
this.onBranchChanged(workspaceId, watchTarget.lastBranchName, newBranchName);
|
|
4809
5125
|
}
|
|
4810
5126
|
}
|
|
4811
|
-
this.
|
|
5127
|
+
this.rememberWorkspaceGitDescriptorState(workspaceId, nextWorkspace);
|
|
4812
5128
|
if (!nextWorkspace) {
|
|
4813
5129
|
subscription.lastEmittedByWorkspaceId.delete(workspaceId);
|
|
4814
5130
|
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
|
@@ -4848,11 +5164,7 @@ export class Session {
|
|
|
4848
5164
|
}
|
|
4849
5165
|
async handleFetchAgents(request) {
|
|
4850
5166
|
const requestedSubscriptionId = request.subscribe?.subscriptionId?.trim();
|
|
4851
|
-
const subscriptionId = request.subscribe
|
|
4852
|
-
? requestedSubscriptionId && requestedSubscriptionId.length > 0
|
|
4853
|
-
? requestedSubscriptionId
|
|
4854
|
-
: uuidv4()
|
|
4855
|
-
: null;
|
|
5167
|
+
const subscriptionId = resolveSubscriptionId(request.subscribe, requestedSubscriptionId);
|
|
4856
5168
|
try {
|
|
4857
5169
|
if (subscriptionId) {
|
|
4858
5170
|
this.agentUpdatesSubscription = {
|
|
@@ -4928,11 +5240,7 @@ export class Session {
|
|
|
4928
5240
|
}
|
|
4929
5241
|
async handleFetchWorkspacesRequest(request) {
|
|
4930
5242
|
const requestedSubscriptionId = request.subscribe?.subscriptionId?.trim();
|
|
4931
|
-
const subscriptionId = request.subscribe
|
|
4932
|
-
? requestedSubscriptionId && requestedSubscriptionId.length > 0
|
|
4933
|
-
? requestedSubscriptionId
|
|
4934
|
-
: uuidv4()
|
|
4935
|
-
: null;
|
|
5243
|
+
const subscriptionId = resolveSubscriptionId(request.subscribe, requestedSubscriptionId);
|
|
4936
5244
|
try {
|
|
4937
5245
|
this.sessionLogger.debug({
|
|
4938
5246
|
requestId: request.requestId,
|
|
@@ -4951,7 +5259,7 @@ export class Session {
|
|
|
4951
5259
|
};
|
|
4952
5260
|
}
|
|
4953
5261
|
const payload = await this.listFetchWorkspacesEntries(request);
|
|
4954
|
-
|
|
5262
|
+
this.syncWorkspaceGitObservers(payload.entries);
|
|
4955
5263
|
this.sessionLogger.debug({
|
|
4956
5264
|
requestId: request.requestId,
|
|
4957
5265
|
subscriptionId,
|
|
@@ -5001,8 +5309,9 @@ export class Session {
|
|
|
5001
5309
|
async handleOpenProjectRequest(request) {
|
|
5002
5310
|
try {
|
|
5003
5311
|
const workspace = await this.findOrCreateWorkspaceForDirectory(request.cwd);
|
|
5312
|
+
await this.syncWorkspaceGitObserverForWorkspace(workspace);
|
|
5313
|
+
const descriptor = await this.describeWorkspaceRecord(workspace);
|
|
5004
5314
|
await this.emitWorkspaceUpdateForCwd(workspace.cwd);
|
|
5005
|
-
const descriptor = await this.describeWorkspaceRecordWithGitData(workspace);
|
|
5006
5315
|
this.emit({
|
|
5007
5316
|
type: "open_project_response",
|
|
5008
5317
|
payload: {
|
|
@@ -5011,6 +5320,15 @@ export class Session {
|
|
|
5011
5320
|
error: null,
|
|
5012
5321
|
},
|
|
5013
5322
|
});
|
|
5323
|
+
void this.workspaceGitService
|
|
5324
|
+
.getSnapshot(workspace.cwd, {
|
|
5325
|
+
force: true,
|
|
5326
|
+
includeGitHub: true,
|
|
5327
|
+
reason: "open_project",
|
|
5328
|
+
})
|
|
5329
|
+
.catch((error) => {
|
|
5330
|
+
this.sessionLogger.warn({ err: error, cwd: workspace.cwd }, "Background snapshot refresh failed after open_project");
|
|
5331
|
+
});
|
|
5014
5332
|
}
|
|
5015
5333
|
catch (error) {
|
|
5016
5334
|
const message = error instanceof Error ? error.message : "Failed to open project";
|
|
@@ -5278,6 +5596,55 @@ export class Session {
|
|
|
5278
5596
|
payload: { requestId, agent, project, error: null },
|
|
5279
5597
|
});
|
|
5280
5598
|
}
|
|
5599
|
+
loadProjectedTimelineWindow(params) {
|
|
5600
|
+
const { agentId, direction, cursor, requestedLimit, provider } = params;
|
|
5601
|
+
let timeline = params.timeline;
|
|
5602
|
+
const projectedLimit = Math.max(1, Math.floor(requestedLimit));
|
|
5603
|
+
let fetchLimit = projectedLimit;
|
|
5604
|
+
let projectedWindow = selectTimelineWindowByProjectedLimit({
|
|
5605
|
+
rows: timeline.rows,
|
|
5606
|
+
provider,
|
|
5607
|
+
direction,
|
|
5608
|
+
limit: projectedLimit,
|
|
5609
|
+
collapseToolLifecycle: false,
|
|
5610
|
+
});
|
|
5611
|
+
while (timeline.hasOlder) {
|
|
5612
|
+
const needsMoreProjectedEntries = projectedWindow.projectedEntries.length < projectedLimit;
|
|
5613
|
+
const firstLoadedRow = timeline.rows[0];
|
|
5614
|
+
const firstSelectedRow = projectedWindow.selectedRows[0];
|
|
5615
|
+
const startsAtLoadedBoundary = firstLoadedRow != null &&
|
|
5616
|
+
firstSelectedRow != null &&
|
|
5617
|
+
firstSelectedRow.seq === firstLoadedRow.seq;
|
|
5618
|
+
const boundaryIsAssistantChunk = startsAtLoadedBoundary && firstLoadedRow.item.type === "assistant_message";
|
|
5619
|
+
if (!needsMoreProjectedEntries && !boundaryIsAssistantChunk) {
|
|
5620
|
+
break;
|
|
5621
|
+
}
|
|
5622
|
+
const maxRows = Math.max(0, timeline.window.maxSeq - timeline.window.minSeq + 1);
|
|
5623
|
+
const nextFetchLimit = Math.min(maxRows, fetchLimit * 2);
|
|
5624
|
+
if (nextFetchLimit <= fetchLimit) {
|
|
5625
|
+
break;
|
|
5626
|
+
}
|
|
5627
|
+
fetchLimit = nextFetchLimit;
|
|
5628
|
+
timeline = this.agentManager.fetchTimeline(agentId, {
|
|
5629
|
+
direction,
|
|
5630
|
+
cursor,
|
|
5631
|
+
limit: fetchLimit,
|
|
5632
|
+
});
|
|
5633
|
+
projectedWindow = selectTimelineWindowByProjectedLimit({
|
|
5634
|
+
rows: timeline.rows,
|
|
5635
|
+
provider,
|
|
5636
|
+
direction,
|
|
5637
|
+
limit: projectedLimit,
|
|
5638
|
+
collapseToolLifecycle: false,
|
|
5639
|
+
});
|
|
5640
|
+
}
|
|
5641
|
+
return {
|
|
5642
|
+
timeline,
|
|
5643
|
+
selectedRows: projectedWindow.selectedRows,
|
|
5644
|
+
minSeq: projectedWindow.minSeq,
|
|
5645
|
+
maxSeq: projectedWindow.maxSeq,
|
|
5646
|
+
};
|
|
5647
|
+
}
|
|
5281
5648
|
async handleFetchAgentTimelineRequest(msg) {
|
|
5282
5649
|
const direction = msg.direction ?? (msg.cursor ? "after" : "tail");
|
|
5283
5650
|
const projection = msg.projection ?? "projected";
|
|
@@ -5313,51 +5680,20 @@ export class Session {
|
|
|
5313
5680
|
let endCursor = null;
|
|
5314
5681
|
let entries;
|
|
5315
5682
|
if (shouldLimitByProjectedWindow) {
|
|
5316
|
-
const
|
|
5317
|
-
|
|
5318
|
-
let projectedWindow = selectTimelineWindowByProjectedLimit({
|
|
5319
|
-
rows: timeline.rows,
|
|
5320
|
-
provider: snapshot.provider,
|
|
5683
|
+
const projectedResult = this.loadProjectedTimelineWindow({
|
|
5684
|
+
agentId: msg.agentId,
|
|
5321
5685
|
direction,
|
|
5322
|
-
|
|
5323
|
-
|
|
5686
|
+
cursor,
|
|
5687
|
+
requestedLimit,
|
|
5688
|
+
provider: snapshot.provider,
|
|
5689
|
+
timeline,
|
|
5324
5690
|
});
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
firstSelectedRow.seq === firstLoadedRow.seq;
|
|
5332
|
-
const boundaryIsAssistantChunk = startsAtLoadedBoundary && firstLoadedRow.item.type === "assistant_message";
|
|
5333
|
-
if (!needsMoreProjectedEntries && !boundaryIsAssistantChunk) {
|
|
5334
|
-
break;
|
|
5335
|
-
}
|
|
5336
|
-
const maxRows = Math.max(0, timeline.window.maxSeq - timeline.window.minSeq + 1);
|
|
5337
|
-
const nextFetchLimit = Math.min(maxRows, fetchLimit * 2);
|
|
5338
|
-
if (nextFetchLimit <= fetchLimit) {
|
|
5339
|
-
break;
|
|
5340
|
-
}
|
|
5341
|
-
fetchLimit = nextFetchLimit;
|
|
5342
|
-
timeline = this.agentManager.fetchTimeline(msg.agentId, {
|
|
5343
|
-
direction,
|
|
5344
|
-
cursor,
|
|
5345
|
-
limit: fetchLimit,
|
|
5346
|
-
});
|
|
5347
|
-
projectedWindow = selectTimelineWindowByProjectedLimit({
|
|
5348
|
-
rows: timeline.rows,
|
|
5349
|
-
provider: snapshot.provider,
|
|
5350
|
-
direction,
|
|
5351
|
-
limit: projectedLimit,
|
|
5352
|
-
collapseToolLifecycle: false,
|
|
5353
|
-
});
|
|
5354
|
-
}
|
|
5355
|
-
const selectedRows = projectedWindow.selectedRows;
|
|
5356
|
-
entries = projectTimelineRows(selectedRows, snapshot.provider, projection);
|
|
5357
|
-
if (projectedWindow.minSeq !== null && projectedWindow.maxSeq !== null) {
|
|
5358
|
-
startCursor = { epoch: timeline.epoch, seq: projectedWindow.minSeq };
|
|
5359
|
-
endCursor = { epoch: timeline.epoch, seq: projectedWindow.maxSeq };
|
|
5360
|
-
hasOlder = projectedWindow.minSeq > timeline.window.minSeq;
|
|
5691
|
+
timeline = projectedResult.timeline;
|
|
5692
|
+
entries = projectTimelineRows(projectedResult.selectedRows, snapshot.provider, projection);
|
|
5693
|
+
if (projectedResult.minSeq !== null && projectedResult.maxSeq !== null) {
|
|
5694
|
+
startCursor = { epoch: timeline.epoch, seq: projectedResult.minSeq };
|
|
5695
|
+
endCursor = { epoch: timeline.epoch, seq: projectedResult.maxSeq };
|
|
5696
|
+
hasOlder = projectedResult.minSeq > timeline.window.minSeq;
|
|
5361
5697
|
hasNewer = false;
|
|
5362
5698
|
}
|
|
5363
5699
|
}
|
|
@@ -5465,18 +5801,13 @@ export class Session {
|
|
|
5465
5801
|
await this.agentManager.waitForAgentRunStart(agentId, { signal: startAbort.signal });
|
|
5466
5802
|
}
|
|
5467
5803
|
catch (error) {
|
|
5468
|
-
const message = error instanceof Error
|
|
5469
|
-
? error.message
|
|
5470
|
-
: typeof error === "string"
|
|
5471
|
-
? error
|
|
5472
|
-
: "Unknown error";
|
|
5473
5804
|
this.emit({
|
|
5474
5805
|
type: "send_agent_message_response",
|
|
5475
5806
|
payload: {
|
|
5476
5807
|
requestId: msg.requestId,
|
|
5477
5808
|
agentId,
|
|
5478
5809
|
accepted: false,
|
|
5479
|
-
error:
|
|
5810
|
+
error: errorToFriendlyMessage(error),
|
|
5480
5811
|
},
|
|
5481
5812
|
});
|
|
5482
5813
|
return;
|
|
@@ -5495,18 +5826,13 @@ export class Session {
|
|
|
5495
5826
|
});
|
|
5496
5827
|
}
|
|
5497
5828
|
catch (error) {
|
|
5498
|
-
const message = error instanceof Error
|
|
5499
|
-
? error.message
|
|
5500
|
-
: typeof error === "string"
|
|
5501
|
-
? error
|
|
5502
|
-
: "Unknown error";
|
|
5503
5829
|
this.emit({
|
|
5504
5830
|
type: "send_agent_message_response",
|
|
5505
5831
|
payload: {
|
|
5506
5832
|
requestId: msg.requestId,
|
|
5507
5833
|
agentId: resolved.agentId,
|
|
5508
5834
|
accepted: false,
|
|
5509
|
-
error:
|
|
5835
|
+
error: errorToFriendlyMessage(error),
|
|
5510
5836
|
},
|
|
5511
5837
|
});
|
|
5512
5838
|
}
|
|
@@ -5544,11 +5870,16 @@ export class Session {
|
|
|
5544
5870
|
return;
|
|
5545
5871
|
}
|
|
5546
5872
|
const final = this.buildStoredAgentPayload(record);
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5873
|
+
let status;
|
|
5874
|
+
if (record.attentionReason === "permission") {
|
|
5875
|
+
status = "permission";
|
|
5876
|
+
}
|
|
5877
|
+
else if (record.lastStatus === "error") {
|
|
5878
|
+
status = "error";
|
|
5879
|
+
}
|
|
5880
|
+
else {
|
|
5881
|
+
status = "idle";
|
|
5882
|
+
}
|
|
5552
5883
|
const error = resolveWaitForFinishError({ status, final });
|
|
5553
5884
|
this.emit({
|
|
5554
5885
|
type: "wait_for_finish_response",
|
|
@@ -5572,11 +5903,16 @@ export class Session {
|
|
|
5572
5903
|
if (!final) {
|
|
5573
5904
|
throw new Error(`Agent ${agentId} disappeared while waiting`);
|
|
5574
5905
|
}
|
|
5575
|
-
let status
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5906
|
+
let status;
|
|
5907
|
+
if (result.permission) {
|
|
5908
|
+
status = "permission";
|
|
5909
|
+
}
|
|
5910
|
+
else if (result.status === "error") {
|
|
5911
|
+
status = "error";
|
|
5912
|
+
}
|
|
5913
|
+
else {
|
|
5914
|
+
status = "idle";
|
|
5915
|
+
}
|
|
5580
5916
|
const error = resolveWaitForFinishError({ status, final });
|
|
5581
5917
|
this.emit({
|
|
5582
5918
|
type: "wait_for_finish_response",
|
|
@@ -5587,11 +5923,7 @@ export class Session {
|
|
|
5587
5923
|
const isAbort = error instanceof Error &&
|
|
5588
5924
|
(error.name === "AbortError" || error.message.toLowerCase().includes("aborted"));
|
|
5589
5925
|
if (!isAbort) {
|
|
5590
|
-
const message = error
|
|
5591
|
-
? error.message
|
|
5592
|
-
: typeof error === "string"
|
|
5593
|
-
? error
|
|
5594
|
-
: "Unknown error";
|
|
5926
|
+
const message = errorToFriendlyMessage(error);
|
|
5595
5927
|
this.sessionLogger.error({ err: error, agentId }, "wait_for_finish_request failed");
|
|
5596
5928
|
const final = await this.getAgentPayloadById(agentId);
|
|
5597
5929
|
this.emit({
|
|
@@ -5608,7 +5940,7 @@ export class Session {
|
|
|
5608
5940
|
}
|
|
5609
5941
|
const final = await this.getAgentPayloadById(agentId);
|
|
5610
5942
|
if (!final) {
|
|
5611
|
-
throw new Error(`Agent ${agentId} disappeared while waiting
|
|
5943
|
+
throw new Error(`Agent ${agentId} disappeared while waiting`, { cause: error });
|
|
5612
5944
|
}
|
|
5613
5945
|
this.emit({
|
|
5614
5946
|
type: "wait_for_finish_response",
|
|
@@ -5624,44 +5956,7 @@ export class Session {
|
|
|
5624
5956
|
/**
|
|
5625
5957
|
* Handle audio chunk for buffering and transcription
|
|
5626
5958
|
*/
|
|
5627
|
-
async
|
|
5628
|
-
if (!this.isVoiceMode) {
|
|
5629
|
-
this.sessionLogger.warn("Received voice_audio_chunk while voice mode is disabled; transcript will be emitted but voice assistant turn is skipped");
|
|
5630
|
-
}
|
|
5631
|
-
const chunkFormat = msg.format || "audio/wav";
|
|
5632
|
-
if (this.isVoiceMode) {
|
|
5633
|
-
if (!this.voiceTurnController) {
|
|
5634
|
-
throw new Error("Voice mode is enabled but the voice turn controller is not running");
|
|
5635
|
-
}
|
|
5636
|
-
const chunkBytes = Buffer.byteLength(msg.audio, "base64");
|
|
5637
|
-
this.voiceInputChunkCount += 1;
|
|
5638
|
-
this.voiceInputBytes += chunkBytes;
|
|
5639
|
-
if (this.voiceInputChunkCount === 1) {
|
|
5640
|
-
this.sessionLogger.info({
|
|
5641
|
-
format: chunkFormat,
|
|
5642
|
-
audioBytes: chunkBytes,
|
|
5643
|
-
}, "Received first voice_audio_chunk for active voice mode");
|
|
5644
|
-
}
|
|
5645
|
-
const now = Date.now();
|
|
5646
|
-
if (this.voiceInputChunkCount % 50 === 0 || now - this.voiceInputWindowStartedAt >= 1000) {
|
|
5647
|
-
this.sessionLogger.info({
|
|
5648
|
-
chunkCount: this.voiceInputChunkCount,
|
|
5649
|
-
audioBytes: this.voiceInputBytes,
|
|
5650
|
-
windowMs: now - this.voiceInputWindowStartedAt,
|
|
5651
|
-
format: chunkFormat,
|
|
5652
|
-
}, "Voice input chunk summary");
|
|
5653
|
-
this.voiceInputWindowStartedAt = now;
|
|
5654
|
-
this.voiceInputChunkCount = 0;
|
|
5655
|
-
this.voiceInputBytes = 0;
|
|
5656
|
-
}
|
|
5657
|
-
await this.voiceTurnController.appendClientChunk({
|
|
5658
|
-
audioBase64: msg.audio,
|
|
5659
|
-
format: chunkFormat,
|
|
5660
|
-
});
|
|
5661
|
-
return;
|
|
5662
|
-
}
|
|
5663
|
-
const chunkBuffer = Buffer.from(msg.audio, "base64");
|
|
5664
|
-
const isPCMChunk = chunkFormat.toLowerCase().includes("pcm");
|
|
5959
|
+
async ensureAudioBufferForFormat(chunkFormat, isPCMChunk) {
|
|
5665
5960
|
if (!this.audioBuffer) {
|
|
5666
5961
|
this.audioBuffer = {
|
|
5667
5962
|
chunks: [],
|
|
@@ -5669,8 +5964,8 @@ export class Session {
|
|
|
5669
5964
|
isPCM: isPCMChunk,
|
|
5670
5965
|
totalPCMBytes: 0,
|
|
5671
5966
|
};
|
|
5967
|
+
return this.audioBuffer;
|
|
5672
5968
|
}
|
|
5673
|
-
// If the format changes mid-stream, flush what we have first
|
|
5674
5969
|
if (this.audioBuffer.isPCM !== isPCMChunk) {
|
|
5675
5970
|
this.sessionLogger.debug({
|
|
5676
5971
|
oldFormat: this.audioBuffer.isPCM ? "pcm" : this.audioBuffer.format,
|
|
@@ -5686,19 +5981,61 @@ export class Session {
|
|
|
5686
5981
|
isPCM: isPCMChunk,
|
|
5687
5982
|
totalPCMBytes: 0,
|
|
5688
5983
|
};
|
|
5984
|
+
return this.audioBuffer;
|
|
5689
5985
|
}
|
|
5690
|
-
|
|
5691
|
-
// Keep latest format info for non-PCM blobs
|
|
5986
|
+
if (!this.audioBuffer.isPCM) {
|
|
5692
5987
|
this.audioBuffer.format = chunkFormat;
|
|
5693
5988
|
}
|
|
5694
|
-
this.audioBuffer
|
|
5695
|
-
|
|
5696
|
-
|
|
5989
|
+
return this.audioBuffer;
|
|
5990
|
+
}
|
|
5991
|
+
async forwardAudioChunkToVoiceTurn(msg, chunkFormat) {
|
|
5992
|
+
if (!this.voiceTurnController) {
|
|
5993
|
+
throw new Error("Voice mode is enabled but the voice turn controller is not running");
|
|
5994
|
+
}
|
|
5995
|
+
const chunkBytes = Buffer.byteLength(msg.audio, "base64");
|
|
5996
|
+
this.voiceInputChunkCount += 1;
|
|
5997
|
+
this.voiceInputBytes += chunkBytes;
|
|
5998
|
+
if (this.voiceInputChunkCount === 1) {
|
|
5999
|
+
this.sessionLogger.info({
|
|
6000
|
+
format: chunkFormat,
|
|
6001
|
+
audioBytes: chunkBytes,
|
|
6002
|
+
}, "Received first voice_audio_chunk for active voice mode");
|
|
6003
|
+
}
|
|
6004
|
+
const now = Date.now();
|
|
6005
|
+
if (this.voiceInputChunkCount % 50 === 0 || now - this.voiceInputWindowStartedAt >= 1000) {
|
|
6006
|
+
this.sessionLogger.info({
|
|
6007
|
+
chunkCount: this.voiceInputChunkCount,
|
|
6008
|
+
audioBytes: this.voiceInputBytes,
|
|
6009
|
+
windowMs: now - this.voiceInputWindowStartedAt,
|
|
6010
|
+
format: chunkFormat,
|
|
6011
|
+
}, "Voice input chunk summary");
|
|
6012
|
+
this.voiceInputWindowStartedAt = now;
|
|
6013
|
+
this.voiceInputChunkCount = 0;
|
|
6014
|
+
this.voiceInputBytes = 0;
|
|
6015
|
+
}
|
|
6016
|
+
await this.voiceTurnController.appendClientChunk({
|
|
6017
|
+
audioBase64: msg.audio,
|
|
6018
|
+
format: chunkFormat,
|
|
6019
|
+
});
|
|
6020
|
+
}
|
|
6021
|
+
async handleAudioChunk(msg) {
|
|
6022
|
+
if (!this.isVoiceMode) {
|
|
6023
|
+
this.sessionLogger.warn("Received voice_audio_chunk while voice mode is disabled; transcript will be emitted but voice assistant turn is skipped");
|
|
6024
|
+
}
|
|
6025
|
+
const chunkFormat = msg.format || "audio/wav";
|
|
6026
|
+
if (this.isVoiceMode) {
|
|
6027
|
+
await this.forwardAudioChunkToVoiceTurn(msg, chunkFormat);
|
|
6028
|
+
return;
|
|
6029
|
+
}
|
|
6030
|
+
const chunkBuffer = Buffer.from(msg.audio, "base64");
|
|
6031
|
+
const isPCMChunk = chunkFormat.toLowerCase().includes("pcm");
|
|
6032
|
+
const buffer = await this.ensureAudioBufferForFormat(chunkFormat, isPCMChunk);
|
|
6033
|
+
buffer.chunks.push(chunkBuffer);
|
|
6034
|
+
if (buffer.isPCM) {
|
|
6035
|
+
buffer.totalPCMBytes += chunkBuffer.length;
|
|
5697
6036
|
}
|
|
5698
6037
|
// In non-voice mode, use streaming threshold to process chunks
|
|
5699
|
-
const reachedStreamingThreshold = !this.isVoiceMode &&
|
|
5700
|
-
this.audioBuffer.isPCM &&
|
|
5701
|
-
this.audioBuffer.totalPCMBytes >= MIN_STREAMING_SEGMENT_BYTES;
|
|
6038
|
+
const reachedStreamingThreshold = !this.isVoiceMode && buffer.isPCM && buffer.totalPCMBytes >= MIN_STREAMING_SEGMENT_BYTES;
|
|
5702
6039
|
if (!msg.isLast && reachedStreamingThreshold) {
|
|
5703
6040
|
return;
|
|
5704
6041
|
}
|
|
@@ -6265,7 +6602,7 @@ export class Session {
|
|
|
6265
6602
|
async handleChatPostRequest(request) {
|
|
6266
6603
|
try {
|
|
6267
6604
|
const authorAgentId = request.authorAgentId?.trim() || this.clientId;
|
|
6268
|
-
const message = await this.chatService.
|
|
6605
|
+
const message = await this.chatService.dispatchMessage({
|
|
6269
6606
|
room: request.room,
|
|
6270
6607
|
authorAgentId,
|
|
6271
6608
|
body: request.body,
|
|
@@ -6615,11 +6952,7 @@ export class Session {
|
|
|
6615
6952
|
}
|
|
6616
6953
|
this.emitTerminalsChangedSnapshot({
|
|
6617
6954
|
cwd: event.cwd,
|
|
6618
|
-
terminals: this.filterStandaloneTerminals(event.terminals).map((terminal) => ({
|
|
6619
|
-
id: terminal.id,
|
|
6620
|
-
name: terminal.name,
|
|
6621
|
-
...(terminal.title ? { title: terminal.title } : {}),
|
|
6622
|
-
})),
|
|
6955
|
+
terminals: this.filterStandaloneTerminals(event.terminals).map((terminal) => Object.assign({ id: terminal.id, name: terminal.name }, terminal.title ? { title: terminal.title } : {})),
|
|
6623
6956
|
});
|
|
6624
6957
|
}
|
|
6625
6958
|
handleSubscribeTerminalsRequest(msg) {
|
|
@@ -7041,7 +7374,7 @@ export class Session {
|
|
|
7041
7374
|
return true;
|
|
7042
7375
|
}
|
|
7043
7376
|
disposeTerminalSubscriptions() {
|
|
7044
|
-
for (const terminalId of
|
|
7377
|
+
for (const terminalId of Array.from(this.terminalIdToSlot.keys())) {
|
|
7045
7378
|
this.detachTerminalStream(terminalId, { emitExit: false });
|
|
7046
7379
|
}
|
|
7047
7380
|
}
|