@getpaseo/server 0.1.2
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/.env.example +20 -0
- package/README.md +107 -0
- package/agent-prompt.md +339 -0
- package/dist/scripts/daemon-runner.js +32 -0
- package/dist/scripts/daemon-runner.js.map +1 -0
- package/dist/scripts/dev-runner.js +19 -0
- package/dist/scripts/dev-runner.js.map +1 -0
- package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
- package/dist/scripts/supervisor.js +95 -0
- package/dist/scripts/supervisor.js.map +1 -0
- package/dist/server/client/daemon-client.d.ts +383 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -0
- package/dist/server/client/daemon-client.js +2443 -0
- package/dist/server/client/daemon-client.js.map +1 -0
- package/dist/server/server/agent/activity-curator.d.ts +8 -0
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -0
- package/dist/server/server/agent/activity-curator.js +228 -0
- package/dist/server/server/agent/activity-curator.js.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts +34 -0
- package/dist/server/server/agent/agent-management-mcp.d.ts.map +1 -0
- package/dist/server/server/agent/agent-management-mcp.js +619 -0
- package/dist/server/server/agent/agent-management-mcp.js.map +1 -0
- package/dist/server/server/agent/agent-manager.d.ts +182 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -0
- package/dist/server/server/agent/agent-manager.js +1066 -0
- package/dist/server/server/agent/agent-manager.js.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts +29 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -0
- package/dist/server/server/agent/agent-metadata-generator.js +157 -0
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -0
- package/dist/server/server/agent/agent-projections.d.ts +12 -0
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -0
- package/dist/server/server/agent/agent-projections.js +238 -0
- package/dist/server/server/agent/agent-projections.js.map +1 -0
- package/dist/server/server/agent/agent-response-loop.d.ts +32 -0
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -0
- package/dist/server/server/agent/agent-response-loop.js +224 -0
- package/dist/server/server/agent/agent-response-loop.js.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts +360 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -0
- package/dist/server/server/agent/agent-sdk-types.js +2 -0
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -0
- package/dist/server/server/agent/agent-storage.d.ts +187 -0
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -0
- package/dist/server/server/agent/agent-storage.js +328 -0
- package/dist/server/server/agent/agent-storage.js.map +1 -0
- package/dist/server/server/agent/audio-utils.d.ts +3 -0
- package/dist/server/server/agent/audio-utils.d.ts.map +1 -0
- package/dist/server/server/agent/audio-utils.js +19 -0
- package/dist/server/server/agent/audio-utils.js.map +1 -0
- package/dist/server/server/agent/dictation-debug.d.ts +13 -0
- package/dist/server/server/agent/dictation-debug.d.ts.map +1 -0
- package/dist/server/server/agent/dictation-debug.js +50 -0
- package/dist/server/server/agent/dictation-debug.js.map +1 -0
- package/dist/server/server/agent/llm-openai.d.ts +7 -0
- package/dist/server/server/agent/llm-openai.d.ts.map +1 -0
- package/dist/server/server/agent/llm-openai.js +8 -0
- package/dist/server/server/agent/llm-openai.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts +26 -0
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -0
- package/dist/server/server/agent/mcp-server.js +762 -0
- package/dist/server/server/agent/mcp-server.js.map +1 -0
- package/dist/server/server/agent/model-resolver.d.ts +11 -0
- package/dist/server/server/agent/model-resolver.d.ts.map +1 -0
- package/dist/server/server/agent/model-resolver.js +21 -0
- package/dist/server/server/agent/model-resolver.js.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts +7 -0
- package/dist/server/server/agent/orchestrator-instructions.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator-instructions.js +51 -0
- package/dist/server/server/agent/orchestrator-instructions.js.map +1 -0
- package/dist/server/server/agent/orchestrator.d.ts +12 -0
- package/dist/server/server/agent/orchestrator.d.ts.map +1 -0
- package/dist/server/server/agent/orchestrator.js +12 -0
- package/dist/server/server/agent/orchestrator.js.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
- package/dist/server/server/agent/pcm16-resampler.d.ts.map +1 -0
- package/dist/server/server/agent/pcm16-resampler.js +63 -0
- package/dist/server/server/agent/pcm16-resampler.js.map +1 -0
- package/dist/server/server/agent/provider-launch-config.d.ts +139 -0
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -0
- package/dist/server/server/agent/provider-launch-config.js +83 -0
- package/dist/server/server/agent/provider-launch-config.js.map +1 -0
- package/dist/server/server/agent/provider-manifest.d.ts +20 -0
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -0
- package/dist/server/server/agent/provider-manifest.js +97 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -0
- package/dist/server/server/agent/provider-registry.d.ts +18 -0
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -0
- package/dist/server/server/agent/provider-registry.js +45 -0
- package/dist/server/server/agent/provider-registry.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +42 -0
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +73 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts +35 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude-agent.js +2056 -0
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +13 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +67 -0
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +15 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +640 -0
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +34 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js +2476 -0
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +9 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +486 -0
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +33 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +75 -0
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +37 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode-agent.js +822 -0
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +1363 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +534 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +18 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +119 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -0
- package/dist/server/server/agent/recordings-debug.d.ts +3 -0
- package/dist/server/server/agent/recordings-debug.d.ts.map +1 -0
- package/dist/server/server/agent/recordings-debug.js +19 -0
- package/dist/server/server/agent/recordings-debug.js.map +1 -0
- package/dist/server/server/agent/stt-debug.d.ts +10 -0
- package/dist/server/server/agent/stt-debug.d.ts.map +1 -0
- package/dist/server/server/agent/stt-debug.js +33 -0
- package/dist/server/server/agent/stt-debug.js.map +1 -0
- package/dist/server/server/agent/stt-manager.d.ts +32 -0
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -0
- package/dist/server/server/agent/stt-manager.js +231 -0
- package/dist/server/server/agent/stt-manager.js.map +1 -0
- package/dist/server/server/agent/system-prompt.d.ts +3 -0
- package/dist/server/server/agent/system-prompt.d.ts.map +1 -0
- package/dist/server/server/agent/system-prompt.js +19 -0
- package/dist/server/server/agent/system-prompt.js.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts +7 -0
- package/dist/server/server/agent/tool-name-normalization.d.ts.map +1 -0
- package/dist/server/server/agent/tool-name-normalization.js +45 -0
- package/dist/server/server/agent/tool-name-normalization.js.map +1 -0
- package/dist/server/server/agent/tts-debug.d.ts +8 -0
- package/dist/server/server/agent/tts-debug.d.ts.map +1 -0
- package/dist/server/server/agent/tts-debug.js +24 -0
- package/dist/server/server/agent/tts-debug.js.map +1 -0
- package/dist/server/server/agent/tts-manager.d.ts +33 -0
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -0
- package/dist/server/server/agent/tts-manager.js +261 -0
- package/dist/server/server/agent/tts-manager.js.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts +15 -0
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts.map +1 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js +53 -0
- package/dist/server/server/agent/wait-for-agent-tracker.js.map +1 -0
- package/dist/server/server/allowed-hosts.d.ts +13 -0
- package/dist/server/server/allowed-hosts.d.ts.map +1 -0
- package/dist/server/server/allowed-hosts.js +94 -0
- package/dist/server/server/allowed-hosts.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts +49 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -0
- package/dist/server/server/bootstrap.js +483 -0
- package/dist/server/server/bootstrap.js.map +1 -0
- package/dist/server/server/config.d.ts +13 -0
- package/dist/server/server/config.d.ts.map +1 -0
- package/dist/server/server/config.js +84 -0
- package/dist/server/server/config.js.map +1 -0
- package/dist/server/server/connection-offer.d.ts +19 -0
- package/dist/server/server/connection-offer.d.ts.map +1 -0
- package/dist/server/server/connection-offer.js +60 -0
- package/dist/server/server/connection-offer.js.map +1 -0
- package/dist/server/server/daemon-keypair.d.ts +8 -0
- package/dist/server/server/daemon-keypair.d.ts.map +1 -0
- package/dist/server/server/daemon-keypair.js +40 -0
- package/dist/server/server/daemon-keypair.js.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts +76 -0
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -0
- package/dist/server/server/dictation/dictation-stream-manager.js +481 -0
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -0
- package/dist/server/server/exports.d.ts +11 -0
- package/dist/server/server/exports.d.ts.map +1 -0
- package/dist/server/server/exports.js +11 -0
- package/dist/server/server/exports.js.map +1 -0
- package/dist/server/server/file-download/token-store.d.ts +25 -0
- package/dist/server/server/file-download/token-store.d.ts.map +1 -0
- package/dist/server/server/file-download/token-store.js +40 -0
- package/dist/server/server/file-download/token-store.js.map +1 -0
- package/dist/server/server/file-explorer/service.d.ts +41 -0
- package/dist/server/server/file-explorer/service.d.ts.map +1 -0
- package/dist/server/server/file-explorer/service.js +163 -0
- package/dist/server/server/file-explorer/service.js.map +1 -0
- package/dist/server/server/index.d.ts +2 -0
- package/dist/server/server/index.d.ts.map +1 -0
- package/dist/server/server/index.js +90 -0
- package/dist/server/server/index.js.map +1 -0
- package/dist/server/server/json-utils.d.ts +11 -0
- package/dist/server/server/json-utils.d.ts.map +1 -0
- package/dist/server/server/json-utils.js +45 -0
- package/dist/server/server/json-utils.js.map +1 -0
- package/dist/server/server/logger.d.ts +12 -0
- package/dist/server/server/logger.d.ts.map +1 -0
- package/dist/server/server/logger.js +29 -0
- package/dist/server/server/logger.js.map +1 -0
- package/dist/server/server/messages.d.ts +9 -0
- package/dist/server/server/messages.d.ts.map +1 -0
- package/dist/server/server/messages.js +29 -0
- package/dist/server/server/messages.js.map +1 -0
- package/dist/server/server/pairing-offer.d.ts +16 -0
- package/dist/server/server/pairing-offer.d.ts.map +1 -0
- package/dist/server/server/pairing-offer.js +45 -0
- package/dist/server/server/pairing-offer.js.map +1 -0
- package/dist/server/server/pairing-qr.d.ts +7 -0
- package/dist/server/server/pairing-qr.d.ts.map +1 -0
- package/dist/server/server/pairing-qr.js +45 -0
- package/dist/server/server/pairing-qr.js.map +1 -0
- package/dist/server/server/paseo-home.d.ts +2 -0
- package/dist/server/server/paseo-home.d.ts.map +1 -0
- package/dist/server/server/paseo-home.js +19 -0
- package/dist/server/server/paseo-home.js.map +1 -0
- package/dist/server/server/path-utils.d.ts +3 -0
- package/dist/server/server/path-utils.d.ts.map +1 -0
- package/dist/server/server/path-utils.js +20 -0
- package/dist/server/server/path-utils.js.map +1 -0
- package/dist/server/server/persisted-config.d.ts +500 -0
- package/dist/server/server/persisted-config.d.ts.map +1 -0
- package/dist/server/server/persisted-config.js +212 -0
- package/dist/server/server/persisted-config.js.map +1 -0
- package/dist/server/server/persistence-hooks.d.ts +24 -0
- package/dist/server/server/persistence-hooks.d.ts.map +1 -0
- package/dist/server/server/persistence-hooks.js +60 -0
- package/dist/server/server/persistence-hooks.js.map +1 -0
- package/dist/server/server/pid-lock.d.ts +19 -0
- package/dist/server/server/pid-lock.d.ts.map +1 -0
- package/dist/server/server/pid-lock.js +115 -0
- package/dist/server/server/pid-lock.js.map +1 -0
- package/dist/server/server/push/push-service.d.ts +21 -0
- package/dist/server/server/push/push-service.d.ts.map +1 -0
- package/dist/server/server/push/push-service.js +68 -0
- package/dist/server/server/push/push-service.js.map +1 -0
- package/dist/server/server/push/token-store.d.ts +18 -0
- package/dist/server/server/push/token-store.d.ts.map +1 -0
- package/dist/server/server/push/token-store.js +70 -0
- package/dist/server/server/push/token-store.js.map +1 -0
- package/dist/server/server/relay-transport.d.ts +22 -0
- package/dist/server/server/relay-transport.d.ts.map +1 -0
- package/dist/server/server/relay-transport.js +374 -0
- package/dist/server/server/relay-transport.js.map +1 -0
- package/dist/server/server/server-id.d.ts +17 -0
- package/dist/server/server/server-id.d.ts.map +1 -0
- package/dist/server/server/server-id.js +63 -0
- package/dist/server/server/server-id.js.map +1 -0
- package/dist/server/server/session.d.ts +360 -0
- package/dist/server/server/session.d.ts.map +1 -0
- package/dist/server/server/session.js +4615 -0
- package/dist/server/server/session.js.map +1 -0
- package/dist/server/server/speech/audio.d.ts +10 -0
- package/dist/server/server/speech/audio.d.ts.map +1 -0
- package/dist/server/server/speech/audio.js +101 -0
- package/dist/server/server/speech/audio.js.map +1 -0
- package/dist/server/server/speech/providers/local/config.d.ts +26 -0
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/config.js +93 -0
- package/dist/server/server/speech/providers/local/config.js.map +1 -0
- package/dist/server/server/speech/providers/local/models.d.ts +12 -0
- package/dist/server/server/speech/providers/local/models.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/models.js +18 -0
- package/dist/server/server/speech/providers/local/models.js.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts +24 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +422 -0
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts +30 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/runtime.js +254 -0
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +117 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +166 -0
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +17 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +151 -0
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +68 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts +37 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +79 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +11 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +7 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +44 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +131 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +132 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +112 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts +23 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +140 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +95 -0
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -0
- package/dist/server/server/speech/providers/openai/config.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/config.js +94 -0
- package/dist/server/server/speech/providers/openai/config.js.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts +42 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +165 -0
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts +27 -0
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/runtime.js +103 -0
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts +22 -0
- package/dist/server/server/speech/providers/openai/stt.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/stt.js +208 -0
- package/dist/server/server/speech/providers/openai/stt.js.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts +18 -0
- package/dist/server/server/speech/providers/openai/tts.d.ts.map +1 -0
- package/dist/server/server/speech/providers/openai/tts.js +46 -0
- package/dist/server/server/speech/providers/openai/tts.js.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -0
- package/dist/server/server/speech/speech-config-resolver.js +64 -0
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -0
- package/dist/server/server/speech/speech-provider.d.ts +59 -0
- package/dist/server/server/speech/speech-provider.d.ts.map +1 -0
- package/dist/server/server/speech/speech-provider.js +2 -0
- package/dist/server/server/speech/speech-provider.js.map +1 -0
- package/dist/server/server/speech/speech-runtime.d.ts +20 -0
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -0
- package/dist/server/server/speech/speech-runtime.js +119 -0
- package/dist/server/server/speech/speech-runtime.js.map +1 -0
- package/dist/server/server/speech/speech-types.d.ts +20 -0
- package/dist/server/server/speech/speech-types.d.ts.map +1 -0
- package/dist/server/server/speech/speech-types.js +7 -0
- package/dist/server/server/speech/speech-types.js.map +1 -0
- package/dist/server/server/terminal-mcp/index.d.ts +4 -0
- package/dist/server/server/terminal-mcp/index.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/index.js +3 -0
- package/dist/server/server/terminal-mcp/index.js.map +1 -0
- package/dist/server/server/terminal-mcp/server.d.ts +10 -0
- package/dist/server/server/terminal-mcp/server.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/server.js +217 -0
- package/dist/server/server/terminal-mcp/server.js.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts +123 -0
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js +351 -0
- package/dist/server/server/terminal-mcp/terminal-manager.js.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts +207 -0
- package/dist/server/server/terminal-mcp/tmux.d.ts.map +1 -0
- package/dist/server/server/terminal-mcp/tmux.js +924 -0
- package/dist/server/server/terminal-mcp/tmux.js.map +1 -0
- package/dist/server/server/types.d.ts +5 -0
- package/dist/server/server/types.d.ts.map +1 -0
- package/dist/server/server/types.js +3 -0
- package/dist/server/server/types.js.map +1 -0
- package/dist/server/server/utils/diff-highlighter.d.ts +52 -0
- package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/diff-highlighter.js +244 -0
- package/dist/server/server/utils/diff-highlighter.js.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts +10 -0
- package/dist/server/server/utils/syntax-highlighter.d.ts.map +1 -0
- package/dist/server/server/utils/syntax-highlighter.js +141 -0
- package/dist/server/server/utils/syntax-highlighter.js.map +1 -0
- package/dist/server/server/voice-config.d.ts +14 -0
- package/dist/server/server/voice-config.d.ts.map +1 -0
- package/dist/server/server/voice-config.js +51 -0
- package/dist/server/server/voice-config.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts +17 -0
- package/dist/server/server/voice-mcp-bridge-command.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge-command.js +31 -0
- package/dist/server/server/voice-mcp-bridge-command.js.map +1 -0
- package/dist/server/server/voice-mcp-bridge.d.ts +18 -0
- package/dist/server/server/voice-mcp-bridge.d.ts.map +1 -0
- package/dist/server/server/voice-mcp-bridge.js +109 -0
- package/dist/server/server/voice-mcp-bridge.js.map +1 -0
- package/dist/server/server/voice-permission-policy.d.ts +4 -0
- package/dist/server/server/voice-permission-policy.d.ts.map +1 -0
- package/dist/server/server/voice-permission-policy.js +13 -0
- package/dist/server/server/voice-permission-policy.js.map +1 -0
- package/dist/server/server/voice-types.d.ts +17 -0
- package/dist/server/server/voice-types.d.ts.map +1 -0
- package/dist/server/server/voice-types.js +2 -0
- package/dist/server/server/voice-types.js.map +1 -0
- package/dist/server/server/websocket-server.d.ts +80 -0
- package/dist/server/server/websocket-server.d.ts.map +1 -0
- package/dist/server/server/websocket-server.js +447 -0
- package/dist/server/server/websocket-server.js.map +1 -0
- package/dist/server/shared/agent-lifecycle.d.ts +3 -0
- package/dist/server/shared/agent-lifecycle.d.ts.map +1 -0
- package/dist/server/shared/agent-lifecycle.js +8 -0
- package/dist/server/shared/agent-lifecycle.js.map +1 -0
- package/dist/server/shared/connection-offer.d.ts +62 -0
- package/dist/server/shared/connection-offer.d.ts.map +1 -0
- package/dist/server/shared/connection-offer.js +17 -0
- package/dist/server/shared/connection-offer.js.map +1 -0
- package/dist/server/shared/daemon-endpoints.d.ts +19 -0
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -0
- package/dist/server/shared/daemon-endpoints.js +98 -0
- package/dist/server/shared/daemon-endpoints.js.map +1 -0
- package/dist/server/shared/messages.d.ts +36729 -0
- package/dist/server/shared/messages.d.ts.map +1 -0
- package/dist/server/shared/messages.js +1666 -0
- package/dist/server/shared/messages.js.map +1 -0
- package/dist/server/shared/path-utils.d.ts +2 -0
- package/dist/server/shared/path-utils.d.ts.map +1 -0
- package/dist/server/shared/path-utils.js +16 -0
- package/dist/server/shared/path-utils.js.map +1 -0
- package/dist/server/shared/tool-call-display.d.ts +11 -0
- package/dist/server/shared/tool-call-display.d.ts.map +1 -0
- package/dist/server/shared/tool-call-display.js +82 -0
- package/dist/server/shared/tool-call-display.js.map +1 -0
- package/dist/server/terminal/terminal-manager.d.ts +14 -0
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -0
- package/dist/server/terminal/terminal-manager.js +67 -0
- package/dist/server/terminal/terminal-manager.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +67 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -0
- package/dist/server/terminal/terminal.js +190 -0
- package/dist/server/terminal/terminal.js.map +1 -0
- package/dist/server/utils/checkout-git.d.ts +138 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -0
- package/dist/server/utils/checkout-git.js +1079 -0
- package/dist/server/utils/checkout-git.js.map +1 -0
- package/dist/server/utils/path.d.ts +5 -0
- package/dist/server/utils/path.d.ts.map +1 -0
- package/dist/server/utils/path.js +15 -0
- package/dist/server/utils/path.js.map +1 -0
- package/dist/server/utils/project-icon.d.ts +39 -0
- package/dist/server/utils/project-icon.d.ts.map +1 -0
- package/dist/server/utils/project-icon.js +391 -0
- package/dist/server/utils/project-icon.js.map +1 -0
- package/dist/server/utils/worktree-metadata.d.ts +21 -0
- package/dist/server/utils/worktree-metadata.d.ts.map +1 -0
- package/dist/server/utils/worktree-metadata.js +74 -0
- package/dist/server/utils/worktree-metadata.js.map +1 -0
- package/dist/server/utils/worktree.d.ts +95 -0
- package/dist/server/utils/worktree.d.ts.map +1 -0
- package/dist/server/utils/worktree.js +568 -0
- package/dist/server/utils/worktree.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,1066 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { AGENT_LIFECYCLE_STATUSES, } from "../../shared/agent-lifecycle.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export { AGENT_LIFECYCLE_STATUSES };
|
|
7
|
+
function attachPersistenceCwd(handle, cwd) {
|
|
8
|
+
if (!handle) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
...handle,
|
|
13
|
+
metadata: {
|
|
14
|
+
...(handle.metadata ?? {}),
|
|
15
|
+
cwd,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const DEFAULT_MAX_TIMELINE_ITEMS = 2000;
|
|
20
|
+
const BUSY_STATUSES = [
|
|
21
|
+
"initializing",
|
|
22
|
+
"running",
|
|
23
|
+
];
|
|
24
|
+
const AgentIdSchema = z.string().uuid();
|
|
25
|
+
function isAgentBusy(status) {
|
|
26
|
+
return BUSY_STATUSES.includes(status);
|
|
27
|
+
}
|
|
28
|
+
function createAbortError(signal, fallbackMessage) {
|
|
29
|
+
const reason = signal?.reason;
|
|
30
|
+
const message = typeof reason === "string"
|
|
31
|
+
? reason
|
|
32
|
+
: reason instanceof Error
|
|
33
|
+
? reason.message
|
|
34
|
+
: fallbackMessage;
|
|
35
|
+
return Object.assign(new Error(message), { name: "AbortError" });
|
|
36
|
+
}
|
|
37
|
+
function validateAgentId(agentId, source) {
|
|
38
|
+
const result = AgentIdSchema.safeParse(agentId);
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
throw new Error(`${source}: agentId must be a UUID`);
|
|
41
|
+
}
|
|
42
|
+
return result.data;
|
|
43
|
+
}
|
|
44
|
+
export class AgentManager {
|
|
45
|
+
constructor(options) {
|
|
46
|
+
this.clients = new Map();
|
|
47
|
+
this.agents = new Map();
|
|
48
|
+
this.subscribers = new Set();
|
|
49
|
+
this.previousStatuses = new Map();
|
|
50
|
+
this.backgroundTasks = new Set();
|
|
51
|
+
this.maxTimelineItems =
|
|
52
|
+
options?.maxTimelineItems ?? DEFAULT_MAX_TIMELINE_ITEMS;
|
|
53
|
+
this.idFactory = options?.idFactory ?? (() => randomUUID());
|
|
54
|
+
this.registry = options?.registry;
|
|
55
|
+
this.onAgentAttention = options?.onAgentAttention;
|
|
56
|
+
this.logger = options.logger.child({ module: "agent", component: "agent-manager" });
|
|
57
|
+
if (options?.clients) {
|
|
58
|
+
for (const [provider, client] of Object.entries(options.clients)) {
|
|
59
|
+
if (client) {
|
|
60
|
+
this.registerClient(provider, client);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
registerClient(provider, client) {
|
|
66
|
+
this.clients.set(provider, client);
|
|
67
|
+
}
|
|
68
|
+
setAgentAttentionCallback(callback) {
|
|
69
|
+
this.onAgentAttention = callback;
|
|
70
|
+
}
|
|
71
|
+
subscribe(callback, options) {
|
|
72
|
+
const targetAgentId = options?.agentId == null
|
|
73
|
+
? null
|
|
74
|
+
: validateAgentId(options.agentId, "subscribe");
|
|
75
|
+
const record = {
|
|
76
|
+
callback,
|
|
77
|
+
agentId: targetAgentId,
|
|
78
|
+
};
|
|
79
|
+
this.subscribers.add(record);
|
|
80
|
+
if (options?.replayState !== false) {
|
|
81
|
+
if (record.agentId) {
|
|
82
|
+
const agent = this.agents.get(record.agentId);
|
|
83
|
+
if (agent) {
|
|
84
|
+
callback({
|
|
85
|
+
type: "agent_state",
|
|
86
|
+
agent: { ...agent },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// For global subscribers, skip internal agents during replay
|
|
92
|
+
for (const agent of this.agents.values()) {
|
|
93
|
+
if (agent.internal) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
callback({
|
|
97
|
+
type: "agent_state",
|
|
98
|
+
agent: { ...agent },
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return () => {
|
|
104
|
+
this.subscribers.delete(record);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
listAgents() {
|
|
108
|
+
return Array.from(this.agents.values())
|
|
109
|
+
.filter((agent) => !agent.internal)
|
|
110
|
+
.map((agent) => ({
|
|
111
|
+
...agent,
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
async listPersistedAgents(options) {
|
|
115
|
+
if (options?.provider) {
|
|
116
|
+
const client = this.requireClient(options.provider);
|
|
117
|
+
if (!client.listPersistedAgents) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
return client.listPersistedAgents({ limit: options.limit });
|
|
121
|
+
}
|
|
122
|
+
const descriptors = [];
|
|
123
|
+
for (const [provider, client] of this.clients.entries()) {
|
|
124
|
+
if (!client.listPersistedAgents) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const entries = await client.listPersistedAgents({
|
|
129
|
+
limit: options?.limit,
|
|
130
|
+
});
|
|
131
|
+
descriptors.push(...entries);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
this.logger.warn({ err: error, provider }, "Failed to list persisted agents for provider");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const limit = options?.limit ?? 20;
|
|
138
|
+
return descriptors
|
|
139
|
+
.sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
|
|
140
|
+
.slice(0, limit);
|
|
141
|
+
}
|
|
142
|
+
getAgent(id) {
|
|
143
|
+
const agent = this.agents.get(id);
|
|
144
|
+
return agent ? { ...agent } : null;
|
|
145
|
+
}
|
|
146
|
+
getTimeline(id) {
|
|
147
|
+
const agent = this.requireAgent(id);
|
|
148
|
+
return [...agent.timeline];
|
|
149
|
+
}
|
|
150
|
+
async createAgent(config, agentId, options) {
|
|
151
|
+
// Generate agent ID early so we can use it in MCP config
|
|
152
|
+
const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "createAgent");
|
|
153
|
+
const normalizedConfig = await this.normalizeConfig(config, {
|
|
154
|
+
labels: options?.labels,
|
|
155
|
+
agentId: resolvedAgentId,
|
|
156
|
+
});
|
|
157
|
+
const client = this.requireClient(normalizedConfig.provider);
|
|
158
|
+
const available = await client.isAvailable();
|
|
159
|
+
if (!available) {
|
|
160
|
+
throw new Error(`Provider '${normalizedConfig.provider}' is not available. Please ensure the CLI is installed.`);
|
|
161
|
+
}
|
|
162
|
+
const session = await client.createSession(normalizedConfig);
|
|
163
|
+
return this.registerSession(session, normalizedConfig, resolvedAgentId, { labels: options?.labels });
|
|
164
|
+
}
|
|
165
|
+
// Reconstruct an agent from provider persistence. Callers should explicitly
|
|
166
|
+
// hydrate timeline history after resume.
|
|
167
|
+
async resumeAgentFromPersistence(handle, overrides, agentId, options) {
|
|
168
|
+
const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "resumeAgentFromPersistence");
|
|
169
|
+
const metadata = (handle.metadata ?? {});
|
|
170
|
+
const mergedConfig = {
|
|
171
|
+
...metadata,
|
|
172
|
+
...overrides,
|
|
173
|
+
provider: handle.provider,
|
|
174
|
+
};
|
|
175
|
+
const normalizedConfig = await this.normalizeConfig(mergedConfig);
|
|
176
|
+
const resumeOverrides = normalizedConfig.model !== mergedConfig.model
|
|
177
|
+
? { ...overrides, model: normalizedConfig.model }
|
|
178
|
+
: overrides;
|
|
179
|
+
const client = this.requireClient(handle.provider);
|
|
180
|
+
const session = await client.resumeSession(handle, resumeOverrides);
|
|
181
|
+
return this.registerSession(session, normalizedConfig, resolvedAgentId, options);
|
|
182
|
+
}
|
|
183
|
+
// Hot-reload an active agent session with config overrides while preserving
|
|
184
|
+
// in-memory timeline state.
|
|
185
|
+
async reloadAgentSession(agentId, overrides) {
|
|
186
|
+
const existing = this.requireAgent(agentId);
|
|
187
|
+
const preservedTimeline = [...existing.timeline];
|
|
188
|
+
const preservedHistoryPrimed = existing.historyPrimed;
|
|
189
|
+
const preservedLastUsage = existing.lastUsage;
|
|
190
|
+
const preservedLastError = existing.lastError;
|
|
191
|
+
const preservedAttention = existing.attention;
|
|
192
|
+
const handle = existing.persistence;
|
|
193
|
+
const provider = handle?.provider ?? existing.provider;
|
|
194
|
+
const client = this.requireClient(provider);
|
|
195
|
+
const refreshConfig = {
|
|
196
|
+
...existing.config,
|
|
197
|
+
...overrides,
|
|
198
|
+
provider,
|
|
199
|
+
};
|
|
200
|
+
const normalizedConfig = await this.normalizeConfig(refreshConfig);
|
|
201
|
+
const session = handle
|
|
202
|
+
? await client.resumeSession(handle, normalizedConfig)
|
|
203
|
+
: await client.createSession(normalizedConfig);
|
|
204
|
+
// Remove the existing agent entry before swapping sessions
|
|
205
|
+
this.agents.delete(agentId);
|
|
206
|
+
try {
|
|
207
|
+
await existing.session.close();
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
this.logger.warn({ err: error, agentId }, "Failed to close previous session during refresh");
|
|
211
|
+
}
|
|
212
|
+
// Preserve existing labels and timeline during reload.
|
|
213
|
+
return this.registerSession(session, normalizedConfig, agentId, {
|
|
214
|
+
labels: existing.labels,
|
|
215
|
+
createdAt: existing.createdAt,
|
|
216
|
+
updatedAt: existing.updatedAt,
|
|
217
|
+
lastUserMessageAt: existing.lastUserMessageAt,
|
|
218
|
+
timeline: preservedTimeline,
|
|
219
|
+
historyPrimed: preservedHistoryPrimed,
|
|
220
|
+
lastUsage: preservedLastUsage,
|
|
221
|
+
lastError: preservedLastError,
|
|
222
|
+
attention: preservedAttention,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
async closeAgent(agentId) {
|
|
226
|
+
const agent = this.requireAgent(agentId);
|
|
227
|
+
this.agents.delete(agentId);
|
|
228
|
+
// Clean up previousStatus to prevent memory leak
|
|
229
|
+
this.previousStatuses.delete(agentId);
|
|
230
|
+
const session = agent.session;
|
|
231
|
+
const closedAgent = {
|
|
232
|
+
...agent,
|
|
233
|
+
lifecycle: "closed",
|
|
234
|
+
session: null,
|
|
235
|
+
pendingRun: null,
|
|
236
|
+
};
|
|
237
|
+
await session.close();
|
|
238
|
+
this.emitState(closedAgent);
|
|
239
|
+
}
|
|
240
|
+
async setAgentMode(agentId, modeId) {
|
|
241
|
+
const agent = this.requireAgent(agentId);
|
|
242
|
+
await agent.session.setMode(modeId);
|
|
243
|
+
agent.currentModeId = modeId;
|
|
244
|
+
// Update runtimeInfo to reflect the new mode
|
|
245
|
+
if (agent.runtimeInfo) {
|
|
246
|
+
agent.runtimeInfo = { ...agent.runtimeInfo, modeId };
|
|
247
|
+
}
|
|
248
|
+
this.emitState(agent);
|
|
249
|
+
}
|
|
250
|
+
async setAgentModel(agentId, modelId) {
|
|
251
|
+
const agent = this.requireAgent(agentId);
|
|
252
|
+
const normalizedModelId = typeof modelId === "string" && modelId.trim().length > 0 ? modelId : null;
|
|
253
|
+
if (agent.session.setModel) {
|
|
254
|
+
await agent.session.setModel(normalizedModelId);
|
|
255
|
+
}
|
|
256
|
+
agent.config.model = normalizedModelId ?? undefined;
|
|
257
|
+
if (agent.runtimeInfo) {
|
|
258
|
+
agent.runtimeInfo = { ...agent.runtimeInfo, model: normalizedModelId };
|
|
259
|
+
}
|
|
260
|
+
this.emitState(agent);
|
|
261
|
+
}
|
|
262
|
+
async setAgentThinkingOption(agentId, thinkingOptionId) {
|
|
263
|
+
const agent = this.requireAgent(agentId);
|
|
264
|
+
const normalizedThinkingOptionId = typeof thinkingOptionId === "string" && thinkingOptionId.trim().length > 0
|
|
265
|
+
? thinkingOptionId
|
|
266
|
+
: null;
|
|
267
|
+
if (agent.session.setThinkingOption) {
|
|
268
|
+
await agent.session.setThinkingOption(normalizedThinkingOptionId);
|
|
269
|
+
}
|
|
270
|
+
agent.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined;
|
|
271
|
+
this.emitState(agent);
|
|
272
|
+
}
|
|
273
|
+
async setTitle(agentId, title) {
|
|
274
|
+
const agent = this.requireAgent(agentId);
|
|
275
|
+
await this.registry?.setTitle(agentId, title);
|
|
276
|
+
this.emitState(agent);
|
|
277
|
+
}
|
|
278
|
+
notifyAgentState(agentId) {
|
|
279
|
+
const agent = this.agents.get(agentId);
|
|
280
|
+
if (!agent || agent.internal) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
this.emitState(agent);
|
|
284
|
+
}
|
|
285
|
+
async clearAgentAttention(agentId) {
|
|
286
|
+
const agent = this.requireAgent(agentId);
|
|
287
|
+
if (agent.attention.requiresAttention) {
|
|
288
|
+
agent.attention = { requiresAttention: false };
|
|
289
|
+
await this.persistSnapshot(agent);
|
|
290
|
+
this.emitState(agent);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async runAgent(agentId, prompt, options) {
|
|
294
|
+
const events = this.streamAgent(agentId, prompt, options);
|
|
295
|
+
const timeline = [];
|
|
296
|
+
let finalText = "";
|
|
297
|
+
let usage;
|
|
298
|
+
let canceled = false;
|
|
299
|
+
for await (const event of events) {
|
|
300
|
+
if (event.type === "timeline") {
|
|
301
|
+
timeline.push(event.item);
|
|
302
|
+
}
|
|
303
|
+
else if (event.type === "turn_completed") {
|
|
304
|
+
usage = event.usage;
|
|
305
|
+
}
|
|
306
|
+
else if (event.type === "turn_failed") {
|
|
307
|
+
throw new Error(event.error);
|
|
308
|
+
}
|
|
309
|
+
else if (event.type === "turn_canceled") {
|
|
310
|
+
canceled = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
finalText = this.getLastAssistantMessageFromTimeline(timeline) ?? "";
|
|
314
|
+
const agent = this.requireAgent(agentId);
|
|
315
|
+
const sessionId = agent.persistence?.sessionId;
|
|
316
|
+
if (!sessionId) {
|
|
317
|
+
throw new Error(`Agent ${agentId} has no persistence.sessionId after run completed`);
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
sessionId,
|
|
321
|
+
finalText,
|
|
322
|
+
usage,
|
|
323
|
+
timeline,
|
|
324
|
+
canceled,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
recordUserMessage(agentId, text, options) {
|
|
328
|
+
const agent = this.requireAgent(agentId);
|
|
329
|
+
const item = {
|
|
330
|
+
type: "user_message",
|
|
331
|
+
text,
|
|
332
|
+
messageId: options?.messageId,
|
|
333
|
+
};
|
|
334
|
+
agent.updatedAt = new Date();
|
|
335
|
+
agent.lastUserMessageAt = agent.updatedAt;
|
|
336
|
+
this.recordTimeline(agent, item);
|
|
337
|
+
this.dispatchStream(agentId, {
|
|
338
|
+
type: "timeline",
|
|
339
|
+
item,
|
|
340
|
+
provider: agent.provider,
|
|
341
|
+
});
|
|
342
|
+
this.emitState(agent);
|
|
343
|
+
}
|
|
344
|
+
async appendTimelineItem(agentId, item) {
|
|
345
|
+
const agent = this.requireAgent(agentId);
|
|
346
|
+
agent.updatedAt = new Date();
|
|
347
|
+
this.recordTimeline(agent, item);
|
|
348
|
+
this.dispatchStream(agentId, {
|
|
349
|
+
type: "timeline",
|
|
350
|
+
item,
|
|
351
|
+
provider: agent.provider,
|
|
352
|
+
});
|
|
353
|
+
await this.persistSnapshot(agent);
|
|
354
|
+
}
|
|
355
|
+
streamAgent(agentId, prompt, options) {
|
|
356
|
+
const existingAgent = this.requireAgent(agentId);
|
|
357
|
+
if (existingAgent.pendingRun) {
|
|
358
|
+
throw new Error(`Agent ${agentId} already has an active run`);
|
|
359
|
+
}
|
|
360
|
+
const agent = existingAgent;
|
|
361
|
+
const iterator = agent.session.stream(prompt, options);
|
|
362
|
+
agent.lastError = undefined;
|
|
363
|
+
let finalized = false;
|
|
364
|
+
const finalize = (error) => {
|
|
365
|
+
if (finalized) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
finalized = true;
|
|
369
|
+
if (agent.pendingRun !== streamForwarder) {
|
|
370
|
+
if (error) {
|
|
371
|
+
agent.lastError = error;
|
|
372
|
+
}
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const mutableAgent = agent;
|
|
376
|
+
mutableAgent.pendingRun = null;
|
|
377
|
+
mutableAgent.lifecycle = error ? "error" : "idle";
|
|
378
|
+
mutableAgent.lastError = error;
|
|
379
|
+
const persistenceHandle = mutableAgent.session.describePersistence() ??
|
|
380
|
+
(mutableAgent.runtimeInfo?.sessionId
|
|
381
|
+
? { provider: mutableAgent.provider, sessionId: mutableAgent.runtimeInfo.sessionId }
|
|
382
|
+
: null);
|
|
383
|
+
if (persistenceHandle) {
|
|
384
|
+
mutableAgent.persistence = attachPersistenceCwd(persistenceHandle, mutableAgent.cwd);
|
|
385
|
+
}
|
|
386
|
+
this.emitState(mutableAgent);
|
|
387
|
+
};
|
|
388
|
+
const self = this;
|
|
389
|
+
const streamForwarder = (async function* streamForwarder() {
|
|
390
|
+
let finalizeError;
|
|
391
|
+
try {
|
|
392
|
+
for await (const event of iterator) {
|
|
393
|
+
self.handleStreamEvent(agent, event);
|
|
394
|
+
yield event;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
finalizeError =
|
|
399
|
+
error instanceof Error ? error.message : "Agent stream failed";
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
402
|
+
finally {
|
|
403
|
+
await self.refreshRuntimeInfo(agent);
|
|
404
|
+
// Ensure we always clear the pending run and emit state when the stream is
|
|
405
|
+
// cancelled early (e.g., via .return()) so the UI can exit the cancelling state.
|
|
406
|
+
finalize(finalizeError);
|
|
407
|
+
}
|
|
408
|
+
})();
|
|
409
|
+
agent.pendingRun = streamForwarder;
|
|
410
|
+
agent.lifecycle = "running";
|
|
411
|
+
self.emitState(agent);
|
|
412
|
+
return streamForwarder;
|
|
413
|
+
}
|
|
414
|
+
async waitForAgentRunStart(agentId, options) {
|
|
415
|
+
const snapshot = this.getAgent(agentId);
|
|
416
|
+
if (!snapshot) {
|
|
417
|
+
throw new Error(`Agent ${agentId} not found`);
|
|
418
|
+
}
|
|
419
|
+
if (snapshot.lifecycle === "running") {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (!("pendingRun" in snapshot) || !snapshot.pendingRun) {
|
|
423
|
+
throw new Error(`Agent ${agentId} has no pending run`);
|
|
424
|
+
}
|
|
425
|
+
if (options?.signal?.aborted) {
|
|
426
|
+
throw createAbortError(options.signal, "wait_for_agent_start aborted");
|
|
427
|
+
}
|
|
428
|
+
await new Promise((resolve, reject) => {
|
|
429
|
+
if (options?.signal?.aborted) {
|
|
430
|
+
reject(createAbortError(options.signal, "wait_for_agent_start aborted"));
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
let unsubscribe = null;
|
|
434
|
+
let abortHandler = null;
|
|
435
|
+
const cleanup = () => {
|
|
436
|
+
if (unsubscribe) {
|
|
437
|
+
try {
|
|
438
|
+
unsubscribe();
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
// ignore cleanup errors
|
|
442
|
+
}
|
|
443
|
+
unsubscribe = null;
|
|
444
|
+
}
|
|
445
|
+
if (abortHandler && options?.signal) {
|
|
446
|
+
try {
|
|
447
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
// ignore cleanup errors
|
|
451
|
+
}
|
|
452
|
+
abortHandler = null;
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
const finishOk = () => {
|
|
456
|
+
cleanup();
|
|
457
|
+
resolve();
|
|
458
|
+
};
|
|
459
|
+
const finishErr = (error) => {
|
|
460
|
+
cleanup();
|
|
461
|
+
reject(error);
|
|
462
|
+
};
|
|
463
|
+
if (options?.signal) {
|
|
464
|
+
abortHandler = () => finishErr(createAbortError(options.signal, "wait_for_agent_start aborted"));
|
|
465
|
+
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
466
|
+
}
|
|
467
|
+
unsubscribe = this.subscribe((event) => {
|
|
468
|
+
if (event.type === "agent_state") {
|
|
469
|
+
if (event.agent.id !== agentId) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (event.agent.lifecycle === "running") {
|
|
473
|
+
finishOk();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (event.agent.lifecycle === "error") {
|
|
477
|
+
finishErr(new Error(event.agent.lastError ?? `Agent ${agentId} failed to start`));
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if ("pendingRun" in event.agent && !event.agent.pendingRun) {
|
|
481
|
+
finishErr(new Error(`Agent ${agentId} run finished before starting`));
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
}, { agentId, replayState: true });
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
async respondToPermission(agentId, requestId, response) {
|
|
490
|
+
const agent = this.requireAgent(agentId);
|
|
491
|
+
await agent.session.respondToPermission(requestId, response);
|
|
492
|
+
agent.pendingPermissions.delete(requestId);
|
|
493
|
+
// Update currentModeId - the session may have changed mode internally
|
|
494
|
+
// (e.g., plan approval changes mode from "plan" to "acceptEdits")
|
|
495
|
+
try {
|
|
496
|
+
agent.currentModeId = await agent.session.getCurrentMode();
|
|
497
|
+
}
|
|
498
|
+
catch {
|
|
499
|
+
// Ignore errors from getCurrentMode - mode tracking is best effort
|
|
500
|
+
}
|
|
501
|
+
this.emitState(agent);
|
|
502
|
+
}
|
|
503
|
+
async cancelAgentRun(agentId) {
|
|
504
|
+
const agent = this.requireAgent(agentId);
|
|
505
|
+
const pendingRun = agent.pendingRun;
|
|
506
|
+
if (!pendingRun || typeof pendingRun.return !== "function") {
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
await agent.session.interrupt();
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
this.logger.error({ err: error, agentId }, "Failed to interrupt session");
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
// Await the generator's .return() to ensure the finally block runs
|
|
517
|
+
// and pendingRun is properly cleared before we return.
|
|
518
|
+
await pendingRun.return(undefined);
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
this.logger.error({ err: error, agentId }, "Failed to cancel run");
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
// Clear any pending permissions that weren't cleaned up by handleStreamEvent.
|
|
525
|
+
// Due to microtask ordering, .return() may force the generator to its finally
|
|
526
|
+
// block before it consumes the turn_canceled event, skipping our cleanup code.
|
|
527
|
+
if (agent.pendingPermissions.size > 0) {
|
|
528
|
+
for (const [requestId] of agent.pendingPermissions) {
|
|
529
|
+
this.dispatchStream(agent.id, {
|
|
530
|
+
type: "permission_resolved",
|
|
531
|
+
provider: agent.provider,
|
|
532
|
+
requestId,
|
|
533
|
+
resolution: { behavior: "deny", message: "Interrupted" },
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
agent.pendingPermissions.clear();
|
|
537
|
+
this.emitState(agent);
|
|
538
|
+
}
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
getPendingPermissions(agentId) {
|
|
542
|
+
const agent = this.requireAgent(agentId);
|
|
543
|
+
return Array.from(agent.pendingPermissions.values());
|
|
544
|
+
}
|
|
545
|
+
peekPendingPermission(agent) {
|
|
546
|
+
const iterator = agent.pendingPermissions.values().next();
|
|
547
|
+
return iterator.done ? null : iterator.value;
|
|
548
|
+
}
|
|
549
|
+
async hydrateTimelineFromProvider(agentId) {
|
|
550
|
+
const agent = this.requireAgent(agentId);
|
|
551
|
+
await this.hydrateTimeline(agent);
|
|
552
|
+
}
|
|
553
|
+
getLastAssistantMessage(agentId) {
|
|
554
|
+
const agent = this.agents.get(agentId);
|
|
555
|
+
if (!agent) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
return this.getLastAssistantMessageFromTimeline(agent.timeline);
|
|
559
|
+
}
|
|
560
|
+
getLastAssistantMessageFromTimeline(timeline) {
|
|
561
|
+
// Collect the last contiguous assistant messages (Claude streams chunks)
|
|
562
|
+
const chunks = [];
|
|
563
|
+
for (let i = timeline.length - 1; i >= 0; i--) {
|
|
564
|
+
const item = timeline[i];
|
|
565
|
+
if (item.type !== "assistant_message") {
|
|
566
|
+
if (chunks.length) {
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
chunks.push(item.text);
|
|
572
|
+
}
|
|
573
|
+
if (!chunks.length) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
return chunks.reverse().join("");
|
|
577
|
+
}
|
|
578
|
+
async waitForAgentEvent(agentId, options) {
|
|
579
|
+
const snapshot = this.getAgent(agentId);
|
|
580
|
+
if (!snapshot) {
|
|
581
|
+
throw new Error(`Agent ${agentId} not found`);
|
|
582
|
+
}
|
|
583
|
+
const hasPendingRun = "pendingRun" in snapshot && Boolean(snapshot.pendingRun);
|
|
584
|
+
const immediatePermission = this.peekPendingPermission(snapshot);
|
|
585
|
+
if (immediatePermission) {
|
|
586
|
+
return {
|
|
587
|
+
status: snapshot.lifecycle,
|
|
588
|
+
permission: immediatePermission,
|
|
589
|
+
lastMessage: this.getLastAssistantMessage(agentId)
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const initialStatus = snapshot.lifecycle;
|
|
593
|
+
const initialBusy = isAgentBusy(initialStatus) || hasPendingRun;
|
|
594
|
+
const waitForActive = options?.waitForActive ?? false;
|
|
595
|
+
if (!waitForActive && !initialBusy) {
|
|
596
|
+
return {
|
|
597
|
+
status: initialStatus,
|
|
598
|
+
permission: null,
|
|
599
|
+
lastMessage: this.getLastAssistantMessage(agentId)
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (waitForActive && !initialBusy && !hasPendingRun) {
|
|
603
|
+
return {
|
|
604
|
+
status: initialStatus,
|
|
605
|
+
permission: null,
|
|
606
|
+
lastMessage: this.getLastAssistantMessage(agentId)
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
if (options?.signal?.aborted) {
|
|
610
|
+
throw createAbortError(options.signal, "wait_for_agent aborted");
|
|
611
|
+
}
|
|
612
|
+
return await new Promise((resolve, reject) => {
|
|
613
|
+
// Bug #1 Fix: Check abort signal AGAIN inside Promise constructor
|
|
614
|
+
// to avoid race condition between pre-Promise check and abort listener registration
|
|
615
|
+
if (options?.signal?.aborted) {
|
|
616
|
+
reject(createAbortError(options.signal, "wait_for_agent aborted"));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
let currentStatus = initialStatus;
|
|
620
|
+
let hasStarted = initialBusy || hasPendingRun;
|
|
621
|
+
// Bug #3 Fix: Declare unsubscribe and abortHandler upfront so cleanup can reference them
|
|
622
|
+
let unsubscribe = null;
|
|
623
|
+
let abortHandler = null;
|
|
624
|
+
const cleanup = () => {
|
|
625
|
+
// Clean up subscription
|
|
626
|
+
if (unsubscribe) {
|
|
627
|
+
try {
|
|
628
|
+
unsubscribe();
|
|
629
|
+
}
|
|
630
|
+
catch {
|
|
631
|
+
// ignore cleanup errors
|
|
632
|
+
}
|
|
633
|
+
unsubscribe = null;
|
|
634
|
+
}
|
|
635
|
+
// Clean up abort listener
|
|
636
|
+
if (abortHandler && options?.signal) {
|
|
637
|
+
try {
|
|
638
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
// ignore cleanup errors
|
|
642
|
+
}
|
|
643
|
+
abortHandler = null;
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
const finish = (permission) => {
|
|
647
|
+
cleanup();
|
|
648
|
+
resolve({
|
|
649
|
+
status: currentStatus,
|
|
650
|
+
permission,
|
|
651
|
+
lastMessage: this.getLastAssistantMessage(agentId)
|
|
652
|
+
});
|
|
653
|
+
};
|
|
654
|
+
// Bug #3 Fix: Set up abort handler BEFORE subscription
|
|
655
|
+
// to ensure cleanup handlers exist before callback can fire
|
|
656
|
+
if (options?.signal) {
|
|
657
|
+
abortHandler = () => {
|
|
658
|
+
cleanup();
|
|
659
|
+
reject(createAbortError(options.signal, "wait_for_agent aborted"));
|
|
660
|
+
};
|
|
661
|
+
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
662
|
+
}
|
|
663
|
+
// Bug #3 Fix: Now subscribe with cleanup handlers already in place
|
|
664
|
+
// This prevents race condition if callback fires synchronously with replayState: true
|
|
665
|
+
unsubscribe = this.subscribe((event) => {
|
|
666
|
+
if (event.type === "agent_state") {
|
|
667
|
+
currentStatus = event.agent.lifecycle;
|
|
668
|
+
const pending = this.peekPendingPermission(event.agent);
|
|
669
|
+
if (pending) {
|
|
670
|
+
finish(pending);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (isAgentBusy(event.agent.lifecycle)) {
|
|
674
|
+
hasStarted = true;
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (!waitForActive || hasStarted) {
|
|
678
|
+
finish(null);
|
|
679
|
+
}
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (event.type === "agent_stream") {
|
|
683
|
+
if (event.event.type === "permission_requested") {
|
|
684
|
+
finish(event.event.request);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if (event.event.type === "turn_failed") {
|
|
688
|
+
currentStatus = "error";
|
|
689
|
+
hasStarted = true;
|
|
690
|
+
finish(null);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (event.event.type === "turn_completed") {
|
|
694
|
+
currentStatus = "idle";
|
|
695
|
+
hasStarted = true;
|
|
696
|
+
finish(null);
|
|
697
|
+
}
|
|
698
|
+
if (event.event.type === "turn_canceled") {
|
|
699
|
+
currentStatus = "idle";
|
|
700
|
+
hasStarted = true;
|
|
701
|
+
finish(null);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}, { agentId, replayState: true });
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
async registerSession(session, config, agentId, options) {
|
|
708
|
+
const resolvedAgentId = validateAgentId(agentId, "registerSession");
|
|
709
|
+
if (this.agents.has(resolvedAgentId)) {
|
|
710
|
+
throw new Error(`Agent with id ${resolvedAgentId} already exists`);
|
|
711
|
+
}
|
|
712
|
+
const now = new Date();
|
|
713
|
+
const managed = {
|
|
714
|
+
id: resolvedAgentId,
|
|
715
|
+
provider: config.provider,
|
|
716
|
+
cwd: config.cwd,
|
|
717
|
+
session,
|
|
718
|
+
capabilities: session.capabilities,
|
|
719
|
+
config,
|
|
720
|
+
runtimeInfo: undefined,
|
|
721
|
+
lifecycle: "initializing",
|
|
722
|
+
createdAt: options?.createdAt ?? now,
|
|
723
|
+
updatedAt: options?.updatedAt ?? now,
|
|
724
|
+
availableModes: [],
|
|
725
|
+
currentModeId: null,
|
|
726
|
+
pendingPermissions: new Map(),
|
|
727
|
+
pendingRun: null,
|
|
728
|
+
timeline: options?.timeline ? [...options.timeline] : [],
|
|
729
|
+
persistence: attachPersistenceCwd(session.describePersistence(), config.cwd),
|
|
730
|
+
historyPrimed: options?.historyPrimed ?? false,
|
|
731
|
+
lastUserMessageAt: options?.lastUserMessageAt ?? null,
|
|
732
|
+
lastUsage: options?.lastUsage,
|
|
733
|
+
lastError: options?.lastError,
|
|
734
|
+
attention: options?.attention != null
|
|
735
|
+
? options.attention.requiresAttention
|
|
736
|
+
? {
|
|
737
|
+
requiresAttention: true,
|
|
738
|
+
attentionReason: options.attention.attentionReason,
|
|
739
|
+
attentionTimestamp: new Date(options.attention.attentionTimestamp),
|
|
740
|
+
}
|
|
741
|
+
: { requiresAttention: false }
|
|
742
|
+
: { requiresAttention: false },
|
|
743
|
+
internal: config.internal ?? false,
|
|
744
|
+
labels: options?.labels ?? {},
|
|
745
|
+
};
|
|
746
|
+
this.agents.set(resolvedAgentId, managed);
|
|
747
|
+
// Initialize previousStatus to track transitions
|
|
748
|
+
this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
|
|
749
|
+
await this.refreshRuntimeInfo(managed);
|
|
750
|
+
await this.persistSnapshot(managed, {
|
|
751
|
+
title: config.title ?? null,
|
|
752
|
+
});
|
|
753
|
+
this.emitState(managed);
|
|
754
|
+
await this.refreshSessionState(managed);
|
|
755
|
+
managed.lifecycle = "idle";
|
|
756
|
+
await this.persistSnapshot(managed);
|
|
757
|
+
this.emitState(managed);
|
|
758
|
+
return { ...managed };
|
|
759
|
+
}
|
|
760
|
+
async persistSnapshot(agent, options) {
|
|
761
|
+
if (!this.registry) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
// Don't persist internal agents - they're ephemeral system tasks
|
|
765
|
+
if (agent.internal) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
await this.registry.applySnapshot(agent, options);
|
|
769
|
+
}
|
|
770
|
+
async refreshSessionState(agent) {
|
|
771
|
+
try {
|
|
772
|
+
const modes = await agent.session.getAvailableModes();
|
|
773
|
+
agent.availableModes = modes;
|
|
774
|
+
}
|
|
775
|
+
catch {
|
|
776
|
+
agent.availableModes = [];
|
|
777
|
+
}
|
|
778
|
+
try {
|
|
779
|
+
agent.currentModeId = await agent.session.getCurrentMode();
|
|
780
|
+
}
|
|
781
|
+
catch {
|
|
782
|
+
agent.currentModeId = null;
|
|
783
|
+
}
|
|
784
|
+
try {
|
|
785
|
+
const pending = agent.session.getPendingPermissions();
|
|
786
|
+
agent.pendingPermissions = new Map(pending.map((request) => [request.id, request]));
|
|
787
|
+
}
|
|
788
|
+
catch {
|
|
789
|
+
agent.pendingPermissions.clear();
|
|
790
|
+
}
|
|
791
|
+
await this.refreshRuntimeInfo(agent);
|
|
792
|
+
}
|
|
793
|
+
async refreshRuntimeInfo(agent) {
|
|
794
|
+
try {
|
|
795
|
+
const newInfo = await agent.session.getRuntimeInfo();
|
|
796
|
+
const changed = newInfo.model !== agent.runtimeInfo?.model ||
|
|
797
|
+
newInfo.sessionId !== agent.runtimeInfo?.sessionId ||
|
|
798
|
+
newInfo.modeId !== agent.runtimeInfo?.modeId;
|
|
799
|
+
agent.runtimeInfo = newInfo;
|
|
800
|
+
if (!agent.persistence && newInfo.sessionId) {
|
|
801
|
+
agent.persistence = attachPersistenceCwd({ provider: agent.provider, sessionId: newInfo.sessionId }, agent.cwd);
|
|
802
|
+
}
|
|
803
|
+
// Emit state if runtimeInfo changed so clients get the updated model
|
|
804
|
+
if (changed) {
|
|
805
|
+
this.emitState(agent);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
catch {
|
|
809
|
+
// Keep existing runtimeInfo if refresh fails.
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
async hydrateTimeline(agent) {
|
|
813
|
+
if (agent.historyPrimed) {
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
agent.historyPrimed = true;
|
|
817
|
+
try {
|
|
818
|
+
for await (const event of agent.session.streamHistory()) {
|
|
819
|
+
this.handleStreamEvent(agent, event, { fromHistory: true });
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
catch {
|
|
823
|
+
// ignore history failures
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
handleStreamEvent(agent, event, options) {
|
|
827
|
+
// Only update timestamp for live events, not history replay
|
|
828
|
+
if (!options?.fromHistory) {
|
|
829
|
+
agent.updatedAt = new Date();
|
|
830
|
+
}
|
|
831
|
+
switch (event.type) {
|
|
832
|
+
case "thread_started":
|
|
833
|
+
// Update persistence with the new session ID from the provider.
|
|
834
|
+
// persistence.sessionId is the single source of truth for session identity.
|
|
835
|
+
{
|
|
836
|
+
const handle = agent.session.describePersistence();
|
|
837
|
+
if (handle) {
|
|
838
|
+
agent.persistence = attachPersistenceCwd(handle, agent.cwd);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
break;
|
|
842
|
+
case "timeline":
|
|
843
|
+
this.recordTimeline(agent, event.item);
|
|
844
|
+
if (!options?.fromHistory &&
|
|
845
|
+
event.item.type === "user_message") {
|
|
846
|
+
agent.lastUserMessageAt = new Date();
|
|
847
|
+
this.emitState(agent);
|
|
848
|
+
}
|
|
849
|
+
break;
|
|
850
|
+
case "turn_completed":
|
|
851
|
+
agent.lastUsage = event.usage;
|
|
852
|
+
agent.lastError = undefined;
|
|
853
|
+
void this.refreshRuntimeInfo(agent);
|
|
854
|
+
break;
|
|
855
|
+
case "turn_failed":
|
|
856
|
+
agent.lastError = event.error;
|
|
857
|
+
for (const [requestId] of agent.pendingPermissions) {
|
|
858
|
+
agent.pendingPermissions.delete(requestId);
|
|
859
|
+
if (!options?.fromHistory) {
|
|
860
|
+
this.dispatchStream(agent.id, {
|
|
861
|
+
type: "permission_resolved",
|
|
862
|
+
provider: event.provider,
|
|
863
|
+
requestId,
|
|
864
|
+
resolution: { behavior: "deny", message: "Turn failed" },
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
this.emitState(agent);
|
|
869
|
+
break;
|
|
870
|
+
case "turn_canceled":
|
|
871
|
+
agent.lastError = undefined;
|
|
872
|
+
for (const [requestId] of agent.pendingPermissions) {
|
|
873
|
+
agent.pendingPermissions.delete(requestId);
|
|
874
|
+
if (!options?.fromHistory) {
|
|
875
|
+
this.dispatchStream(agent.id, {
|
|
876
|
+
type: "permission_resolved",
|
|
877
|
+
provider: event.provider,
|
|
878
|
+
requestId,
|
|
879
|
+
resolution: { behavior: "deny", message: "Interrupted" },
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
this.emitState(agent);
|
|
884
|
+
break;
|
|
885
|
+
case "permission_requested":
|
|
886
|
+
agent.pendingPermissions.set(event.request.id, event.request);
|
|
887
|
+
this.emitState(agent);
|
|
888
|
+
break;
|
|
889
|
+
case "permission_resolved":
|
|
890
|
+
agent.pendingPermissions.delete(event.requestId);
|
|
891
|
+
this.emitState(agent);
|
|
892
|
+
break;
|
|
893
|
+
default:
|
|
894
|
+
break;
|
|
895
|
+
}
|
|
896
|
+
// Skip dispatching individual stream events during history replay.
|
|
897
|
+
// The caller will send a batched agent_stream_snapshot after priming.
|
|
898
|
+
if (!options?.fromHistory) {
|
|
899
|
+
this.dispatchStream(agent.id, event);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
recordTimeline(agent, item) {
|
|
903
|
+
agent.timeline.push(item);
|
|
904
|
+
if (agent.timeline.length > this.maxTimelineItems) {
|
|
905
|
+
agent.timeline.splice(0, agent.timeline.length - this.maxTimelineItems);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
emitState(agent) {
|
|
909
|
+
// Check if attention should be set based on status change
|
|
910
|
+
this.checkAndSetAttention(agent);
|
|
911
|
+
this.dispatch({
|
|
912
|
+
type: "agent_state",
|
|
913
|
+
agent: { ...agent },
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
checkAndSetAttention(agent) {
|
|
917
|
+
const previousStatus = this.previousStatuses.get(agent.id);
|
|
918
|
+
const currentStatus = agent.lifecycle;
|
|
919
|
+
// Track the new status
|
|
920
|
+
this.previousStatuses.set(agent.id, currentStatus);
|
|
921
|
+
// Skip attention tracking for internal agents
|
|
922
|
+
if (agent.internal) {
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
// Skip if already requires attention
|
|
926
|
+
if (agent.attention.requiresAttention) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
// Check if agent transitioned from running to idle (finished)
|
|
930
|
+
if (previousStatus === "running" && currentStatus === "idle") {
|
|
931
|
+
agent.attention = {
|
|
932
|
+
requiresAttention: true,
|
|
933
|
+
attentionReason: "finished",
|
|
934
|
+
attentionTimestamp: new Date(),
|
|
935
|
+
};
|
|
936
|
+
this.broadcastAgentAttention(agent, "finished");
|
|
937
|
+
this.enqueueBackgroundPersist(agent);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
// Check if agent entered error state
|
|
941
|
+
if (currentStatus === "error") {
|
|
942
|
+
agent.attention = {
|
|
943
|
+
requiresAttention: true,
|
|
944
|
+
attentionReason: "error",
|
|
945
|
+
attentionTimestamp: new Date(),
|
|
946
|
+
};
|
|
947
|
+
this.broadcastAgentAttention(agent, "error");
|
|
948
|
+
this.enqueueBackgroundPersist(agent);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
// Check if agent has pending permissions
|
|
952
|
+
if (agent.pendingPermissions.size > 0) {
|
|
953
|
+
agent.attention = {
|
|
954
|
+
requiresAttention: true,
|
|
955
|
+
attentionReason: "permission",
|
|
956
|
+
attentionTimestamp: new Date(),
|
|
957
|
+
};
|
|
958
|
+
this.broadcastAgentAttention(agent, "permission");
|
|
959
|
+
this.enqueueBackgroundPersist(agent);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
enqueueBackgroundPersist(agent) {
|
|
964
|
+
const task = this.persistSnapshot(agent).catch((err) => {
|
|
965
|
+
this.logger.error({ err, agentId: agent.id }, "Failed to persist agent snapshot");
|
|
966
|
+
});
|
|
967
|
+
this.trackBackgroundTask(task);
|
|
968
|
+
}
|
|
969
|
+
trackBackgroundTask(task) {
|
|
970
|
+
this.backgroundTasks.add(task);
|
|
971
|
+
void task.finally(() => {
|
|
972
|
+
this.backgroundTasks.delete(task);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Flush any background persistence work (best-effort).
|
|
977
|
+
* Used by daemon shutdown paths to avoid unhandled rejections after cleanup.
|
|
978
|
+
*/
|
|
979
|
+
async flush() {
|
|
980
|
+
// Drain tasks, including tasks spawned while awaiting.
|
|
981
|
+
while (this.backgroundTasks.size > 0) {
|
|
982
|
+
const pending = Array.from(this.backgroundTasks);
|
|
983
|
+
await Promise.allSettled(pending);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
broadcastAgentAttention(agent, reason) {
|
|
987
|
+
this.onAgentAttention?.({
|
|
988
|
+
agentId: agent.id,
|
|
989
|
+
provider: agent.provider,
|
|
990
|
+
reason,
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
dispatchStream(agentId, event) {
|
|
994
|
+
this.dispatch({ type: "agent_stream", agentId, event });
|
|
995
|
+
}
|
|
996
|
+
dispatch(event) {
|
|
997
|
+
for (const subscriber of this.subscribers) {
|
|
998
|
+
if (subscriber.agentId &&
|
|
999
|
+
event.type === "agent_stream" &&
|
|
1000
|
+
subscriber.agentId !== event.agentId) {
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
1003
|
+
if (subscriber.agentId &&
|
|
1004
|
+
event.type === "agent_state" &&
|
|
1005
|
+
subscriber.agentId !== event.agent.id) {
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
// Skip internal agents for global subscribers (those without a specific agentId)
|
|
1009
|
+
if (!subscriber.agentId) {
|
|
1010
|
+
if (event.type === "agent_state" && event.agent.internal) {
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (event.type === "agent_stream") {
|
|
1014
|
+
const agent = this.agents.get(event.agentId);
|
|
1015
|
+
if (agent?.internal) {
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
subscriber.callback(event);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
async normalizeConfig(config, _options) {
|
|
1024
|
+
const normalized = { ...config };
|
|
1025
|
+
// Always resolve cwd to absolute path for consistent history file lookup
|
|
1026
|
+
if (normalized.cwd) {
|
|
1027
|
+
normalized.cwd = resolve(normalized.cwd);
|
|
1028
|
+
try {
|
|
1029
|
+
const cwdStats = await stat(normalized.cwd);
|
|
1030
|
+
if (!cwdStats.isDirectory()) {
|
|
1031
|
+
throw new Error(`Working directory is not a directory: ${normalized.cwd}`);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
catch (error) {
|
|
1035
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
1036
|
+
throw new Error(`Working directory does not exist: ${normalized.cwd}`);
|
|
1037
|
+
}
|
|
1038
|
+
if (error instanceof Error) {
|
|
1039
|
+
throw error;
|
|
1040
|
+
}
|
|
1041
|
+
throw new Error(`Failed to access working directory: ${normalized.cwd}`);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
if (typeof normalized.model === "string") {
|
|
1045
|
+
const trimmed = normalized.model.trim();
|
|
1046
|
+
normalized.model = trimmed.length > 0 ? trimmed : undefined;
|
|
1047
|
+
}
|
|
1048
|
+
return normalized;
|
|
1049
|
+
}
|
|
1050
|
+
requireClient(provider) {
|
|
1051
|
+
const client = this.clients.get(provider);
|
|
1052
|
+
if (!client) {
|
|
1053
|
+
throw new Error(`No client registered for provider '${provider}'`);
|
|
1054
|
+
}
|
|
1055
|
+
return client;
|
|
1056
|
+
}
|
|
1057
|
+
requireAgent(id) {
|
|
1058
|
+
const normalizedId = validateAgentId(id, "requireAgent");
|
|
1059
|
+
const agent = this.agents.get(normalizedId);
|
|
1060
|
+
if (!agent) {
|
|
1061
|
+
throw new Error(`Unknown agent '${normalizedId}'`);
|
|
1062
|
+
}
|
|
1063
|
+
return agent;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
//# sourceMappingURL=agent-manager.js.map
|