@getpaseo/server 0.1.29 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/daemon-runner.js +1 -1
- package/dist/scripts/daemon-runner.js.map +1 -1
- package/dist/scripts/dev-runner.js +1 -1
- package/dist/scripts/dev-runner.js.map +1 -1
- package/dist/server/client/daemon-client-relay-e2ee-transport.d.ts.map +1 -1
- package/dist/server/client/daemon-client-relay-e2ee-transport.js.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.d.ts.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +108 -103
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +417 -407
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -1
- package/dist/server/server/agent/activity-curator.js +5 -4
- package/dist/server/server/agent/activity-curator.js.map +1 -1
- package/dist/server/server/agent/agent-management-mcp.d.ts.map +1 -1
- package/dist/server/server/agent/agent-management-mcp.js +13 -17
- package/dist/server/server/agent/agent-management-mcp.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +26 -26
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +1 -3
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +4 -12
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -1
- package/dist/server/server/agent/agent-response-loop.js +6 -6
- package/dist/server/server/agent/agent-response-loop.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +23 -0
- 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.map +1 -1
- package/dist/server/server/agent/agent-storage.js +2 -4
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/dictation-debug.d.ts.map +1 -1
- package/dist/server/server/agent/dictation-debug.js.map +1 -1
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +19 -27
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/pcm16-resampler.d.ts.map +1 -1
- package/dist/server/server/agent/pcm16-resampler.js.map +1 -1
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js +4 -2
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts +10 -1
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
- package/dist/server/server/agent/provider-manifest.js +25 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -1
- package/dist/server/server/agent/provider-registry.d.ts +2 -2
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.js +1 -1
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/providers/claude/model-catalog.js +10 -10
- package/dist/server/server/agent/providers/claude/model-catalog.js.map +1 -1
- package/dist/server/server/agent/providers/claude/partial-json.d.ts +5 -0
- package/dist/server/server/agent/providers/claude/partial-json.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/partial-json.js +306 -0
- package/dist/server/server/agent/providers/claude/partial-json.js.map +1 -0
- package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +20 -0
- package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js +230 -0
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js.map +1 -0
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +11 -0
- 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 +37 -20
- 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 +21 -11
- 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.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +23 -11
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +508 -1141
- 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.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +2 -2
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -1
- 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 +14 -11
- 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.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +347 -163
- 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.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +21 -32
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +2 -2
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +2 -9
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +5 -5
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +277 -1
- 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 +149 -15
- 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.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +1 -3
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -1
- package/dist/server/server/agent/stt-manager.js +1 -2
- package/dist/server/server/agent/stt-manager.js.map +1 -1
- package/dist/server/server/agent/system-prompt.js +5 -5
- package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
- 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 +27 -9
- package/dist/server/server/agent/tts-manager.js.map +1 -1
- package/dist/server/server/agent/wait-for-agent-tracker.d.ts.map +1 -1
- package/dist/server/server/agent/wait-for-agent-tracker.js.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
- package/dist/server/server/agent-attention-policy.js.map +1 -1
- package/dist/server/server/allowed-hosts.d.ts.map +1 -1
- package/dist/server/server/allowed-hosts.js.map +1 -1
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +46 -5
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +4 -11
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/connection-offer.d.ts +1 -1
- package/dist/server/server/connection-offer.d.ts.map +1 -1
- package/dist/server/server/connection-offer.js +2 -3
- package/dist/server/server/connection-offer.js.map +1 -1
- package/dist/server/server/daemon-version.d.ts.map +1 -1
- package/dist/server/server/daemon-version.js +1 -1
- package/dist/server/server/daemon-version.js.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.js +4 -1
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -1
- package/dist/server/server/exports.d.ts +1 -1
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +1 -1
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/file-explorer/service.d.ts +1 -1
- package/dist/server/server/file-explorer/service.d.ts.map +1 -1
- package/dist/server/server/file-explorer/service.js +5 -8
- package/dist/server/server/file-explorer/service.js.map +1 -1
- package/dist/server/server/index.js +1 -1
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/logger.d.ts.map +1 -1
- package/dist/server/server/logger.js.map +1 -1
- package/dist/server/server/messages.d.ts.map +1 -1
- package/dist/server/server/messages.js.map +1 -1
- package/dist/server/server/package-version.d.ts.map +1 -1
- package/dist/server/server/package-version.js +1 -2
- package/dist/server/server/package-version.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/persistence-hooks.d.ts.map +1 -1
- package/dist/server/server/persistence-hooks.js.map +1 -1
- package/dist/server/server/pid-lock.d.ts.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.map +1 -1
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +6 -2
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/session.d.ts +49 -37
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +1234 -998
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/audio.d.ts.map +1 -1
- package/dist/server/server/speech/audio.js.map +1 -1
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/config.js +5 -14
- package/dist/server/server/speech/providers/local/config.js.map +1 -1
- package/dist/server/server/speech/providers/local/models.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/models.js +1 -1
- package/dist/server/server/speech/providers/local/models.js.map +1 -1
- 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 +21 -7
- 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.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.js +1 -23
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -1
- 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.map +1 -1
- 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.map +1 -1
- 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 +9 -4
- 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.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +7 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-online-recognizer.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 +5 -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.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +2 -4
- 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 +1 -3
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -1
- 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 +2 -4
- 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.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +4 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js +1 -1
- package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.js.map +1 -1
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/config.js +5 -24
- 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 +6 -3
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.js +2 -6
- 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 +1 -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.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 +3 -7
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -1
- package/dist/server/server/speech/speech-provider.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.js.map +1 -1
- package/dist/server/server/speech/turn-detection-provider.d.ts.map +1 -1
- package/dist/server/server/terminal-mcp/server.d.ts.map +1 -1
- package/dist/server/server/terminal-mcp/server.js +3 -11
- package/dist/server/server/terminal-mcp/server.js.map +1 -1
- package/dist/server/server/terminal-mcp/terminal-manager.d.ts.map +1 -1
- package/dist/server/server/terminal-mcp/terminal-manager.js +2 -14
- package/dist/server/server/terminal-mcp/terminal-manager.js.map +1 -1
- package/dist/server/server/terminal-mcp/tmux.d.ts +1 -1
- package/dist/server/server/terminal-mcp/tmux.d.ts.map +1 -1
- package/dist/server/server/terminal-mcp/tmux.js +20 -123
- package/dist/server/server/terminal-mcp/tmux.js.map +1 -1
- package/dist/server/server/utils/diff-highlighter.d.ts +11 -3
- package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -1
- package/dist/server/server/utils/diff-highlighter.js +49 -36
- package/dist/server/server/utils/diff-highlighter.js.map +1 -1
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.d.ts.map +1 -1
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.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 -3
- package/dist/server/server/voice/voice-turn-controller.js.map +1 -1
- package/dist/server/server/voice-config.d.ts.map +1 -1
- package/dist/server/server/voice-config.js.map +1 -1
- package/dist/server/server/voice-mcp-bridge.d.ts.map +1 -1
- package/dist/server/server/voice-mcp-bridge.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +1 -0
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +20 -22
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-registry-bootstrap.d.ts +3 -3
- package/dist/server/server/workspace-registry-bootstrap.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-bootstrap.js +6 -6
- package/dist/server/server/workspace-registry-bootstrap.js.map +1 -1
- package/dist/server/server/workspace-registry-model.d.ts +14 -3
- package/dist/server/server/workspace-registry-model.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-model.js +40 -15
- package/dist/server/server/workspace-registry-model.js.map +1 -1
- package/dist/server/server/workspace-registry.d.ts +5 -5
- package/dist/server/server/workspace-registry.d.ts.map +1 -1
- package/dist/server/server/workspace-registry.js +16 -13
- package/dist/server/server/workspace-registry.js.map +1 -1
- package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
- package/dist/server/server/worktree-bootstrap.js +17 -6
- package/dist/server/server/worktree-bootstrap.js.map +1 -1
- package/dist/server/shared/agent-attention-notification.d.ts.map +1 -1
- package/dist/server/shared/agent-attention-notification.js.map +1 -1
- package/dist/server/shared/agent-lifecycle.d.ts.map +1 -1
- package/dist/server/shared/daemon-endpoints.d.ts +1 -0
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
- package/dist/server/shared/daemon-endpoints.js +11 -2
- package/dist/server/shared/daemon-endpoints.js.map +1 -1
- package/dist/server/shared/messages.d.ts +1228 -2982
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +330 -302
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/terminal-stream-protocol.d.ts +36 -0
- package/dist/server/shared/terminal-stream-protocol.d.ts.map +1 -0
- package/dist/server/shared/terminal-stream-protocol.js +99 -0
- package/dist/server/shared/terminal-stream-protocol.js.map +1 -0
- package/dist/server/shared/tool-call-display.d.ts.map +1 -1
- package/dist/server/shared/tool-call-display.js +6 -3
- package/dist/server/shared/tool-call-display.js.map +1 -1
- package/dist/server/terminal/terminal.d.ts +5 -48
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +44 -98
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +1 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +111 -120
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/directory-suggestions.d.ts +1 -1
- package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
- package/dist/server/utils/directory-suggestions.js +40 -40
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/server/utils/project-icon.d.ts.map +1 -1
- package/dist/server/utils/project-icon.js +2 -11
- package/dist/server/utils/project-icon.js.map +1 -1
- package/dist/server/utils/worktree.d.ts +2 -0
- package/dist/server/utils/worktree.d.ts.map +1 -1
- package/dist/server/utils/worktree.js +22 -19
- package/dist/server/utils/worktree.js.map +1 -1
- package/dist/src/server/agent/activity-curator.js +5 -4
- package/dist/src/server/agent/activity-curator.js.map +1 -1
- package/dist/src/server/agent/agent-manager.js +26 -26
- package/dist/src/server/agent/agent-manager.js.map +1 -1
- package/dist/src/server/agent/agent-metadata-generator.js +1 -3
- package/dist/src/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/src/server/agent/agent-projections.js +4 -12
- package/dist/src/server/agent/agent-projections.js.map +1 -1
- package/dist/src/server/agent/agent-response-loop.js +6 -6
- package/dist/src/server/agent/agent-response-loop.js.map +1 -1
- package/dist/src/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/src/server/agent/agent-storage.js +2 -4
- package/dist/src/server/agent/agent-storage.js.map +1 -1
- package/dist/src/server/agent/dictation-debug.js.map +1 -1
- package/dist/src/server/agent/mcp-server.js +19 -27
- package/dist/src/server/agent/mcp-server.js.map +1 -1
- package/dist/src/server/agent/pcm16-resampler.js.map +1 -1
- package/dist/src/server/agent/provider-launch-config.js +4 -2
- package/dist/src/server/agent/provider-launch-config.js.map +1 -1
- package/dist/src/server/agent/provider-manifest.js +25 -0
- package/dist/src/server/agent/provider-manifest.js.map +1 -1
- package/dist/src/server/agent/provider-registry.js +1 -1
- package/dist/src/server/agent/provider-registry.js.map +1 -1
- package/dist/src/server/agent/providers/claude/model-catalog.js +10 -10
- package/dist/src/server/agent/providers/claude/model-catalog.js.map +1 -1
- package/dist/src/server/agent/providers/claude/partial-json.js +306 -0
- package/dist/src/server/agent/providers/claude/partial-json.js.map +1 -0
- package/dist/src/server/agent/providers/claude/sidechain-tracker.js +230 -0
- package/dist/src/server/agent/providers/claude/sidechain-tracker.js.map +1 -0
- package/dist/src/server/agent/providers/claude/task-notification-tool-call.js +37 -20
- package/dist/src/server/agent/providers/claude/task-notification-tool-call.js.map +1 -1
- package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js +21 -11
- package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
- package/dist/src/server/agent/providers/claude/tool-call-mapper.js +23 -11
- package/dist/src/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/src/server/agent/providers/claude-agent.js +508 -1141
- package/dist/src/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js +2 -2
- package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -1
- package/dist/src/server/agent/providers/codex/tool-call-mapper.js +14 -11
- package/dist/src/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/src/server/agent/providers/codex-app-server-agent.js +347 -163
- package/dist/src/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/src/server/agent/providers/codex-rollout-timeline.js +21 -32
- package/dist/src/server/agent/providers/codex-rollout-timeline.js.map +1 -1
- package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js +2 -2
- package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/src/server/agent/providers/opencode/tool-call-mapper.js +2 -9
- package/dist/src/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
- package/dist/src/server/agent/providers/opencode-agent.js +5 -5
- package/dist/src/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/src/server/agent/providers/tool-call-detail-primitives.js +149 -15
- package/dist/src/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/src/server/agent/providers/tool-call-mapper-utils.js +1 -3
- package/dist/src/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
- package/dist/src/server/agent/stt-manager.js +1 -2
- package/dist/src/server/agent/stt-manager.js.map +1 -1
- package/dist/src/server/agent/timeline-projection.js.map +1 -1
- package/dist/src/server/agent/tts-manager.js +27 -9
- package/dist/src/server/agent/tts-manager.js.map +1 -1
- package/dist/src/server/agent/wait-for-agent-tracker.js.map +1 -1
- package/dist/src/server/agent-attention-policy.js.map +1 -1
- package/dist/src/server/allowed-hosts.js.map +1 -1
- package/dist/src/server/bootstrap.js +46 -5
- package/dist/src/server/bootstrap.js.map +1 -1
- package/dist/src/server/config.js +4 -11
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/connection-offer.js +2 -3
- package/dist/src/server/connection-offer.js.map +1 -1
- package/dist/src/server/daemon-version.js +1 -1
- package/dist/src/server/daemon-version.js.map +1 -1
- package/dist/src/server/dictation/dictation-stream-manager.js +4 -1
- package/dist/src/server/dictation/dictation-stream-manager.js.map +1 -1
- package/dist/src/server/file-explorer/service.js +5 -8
- package/dist/src/server/file-explorer/service.js.map +1 -1
- package/dist/src/server/messages.js.map +1 -1
- package/dist/src/server/package-version.js +1 -2
- package/dist/src/server/package-version.js.map +1 -1
- package/dist/src/server/pairing-offer.js +45 -0
- package/dist/src/server/pairing-offer.js.map +1 -0
- package/dist/src/server/pairing-qr.js +45 -0
- package/dist/src/server/pairing-qr.js.map +1 -0
- package/dist/src/server/persisted-config.js.map +1 -1
- package/dist/src/server/persistence-hooks.js.map +1 -1
- package/dist/src/server/pid-lock.js.map +1 -1
- package/dist/src/server/push/push-service.js.map +1 -1
- package/dist/src/server/relay-transport.js +6 -2
- package/dist/src/server/relay-transport.js.map +1 -1
- package/dist/src/server/session.js +1234 -998
- package/dist/src/server/session.js.map +1 -1
- package/dist/src/server/speech/audio.js.map +1 -1
- package/dist/src/server/speech/providers/local/config.js +5 -14
- package/dist/src/server/speech/providers/local/config.js.map +1 -1
- package/dist/src/server/speech/providers/local/models.js +1 -1
- package/dist/src/server/speech/providers/local/models.js.map +1 -1
- package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js +21 -7
- package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -1
- package/dist/src/server/speech/providers/local/runtime.js +1 -23
- package/dist/src/server/speech/providers/local/runtime.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/model-catalog.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +9 -4
- package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +7 -2
- package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +5 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +2 -4
- package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js +1 -3
- package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js +2 -4
- package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js +4 -1
- package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js +1 -1
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js.map +1 -1
- package/dist/src/server/speech/providers/local/sherpa/silero-vad-session.js.map +1 -1
- package/dist/src/server/speech/providers/openai/config.js +5 -24
- package/dist/src/server/speech/providers/openai/config.js.map +1 -1
- package/dist/src/server/speech/providers/openai/realtime-transcription-session.js +6 -3
- package/dist/src/server/speech/providers/openai/realtime-transcription-session.js.map +1 -1
- package/dist/src/server/speech/providers/openai/runtime.js +2 -6
- package/dist/src/server/speech/providers/openai/runtime.js.map +1 -1
- package/dist/src/server/speech/providers/openai/stt.js +1 -3
- package/dist/src/server/speech/providers/openai/stt.js.map +1 -1
- package/dist/src/server/speech/providers/openai/tts.js.map +1 -1
- package/dist/src/server/speech/speech-config-resolver.js +3 -7
- package/dist/src/server/speech/speech-config-resolver.js.map +1 -1
- package/dist/src/server/speech/speech-runtime.js.map +1 -1
- package/dist/src/server/utils/diff-highlighter.js +49 -36
- package/dist/src/server/utils/diff-highlighter.js.map +1 -1
- package/dist/src/server/voice/fixed-duration-pcm-ring-buffer.js.map +1 -1
- package/dist/src/server/voice/voice-turn-controller.js +1 -3
- package/dist/src/server/voice/voice-turn-controller.js.map +1 -1
- package/dist/src/server/voice-config.js.map +1 -1
- package/dist/src/server/voice-mcp-bridge.js.map +1 -1
- package/dist/src/server/websocket-server.js +20 -22
- package/dist/src/server/websocket-server.js.map +1 -1
- package/dist/src/server/workspace-registry-bootstrap.js +6 -6
- package/dist/src/server/workspace-registry-bootstrap.js.map +1 -1
- package/dist/src/server/workspace-registry-model.js +40 -15
- package/dist/src/server/workspace-registry-model.js.map +1 -1
- package/dist/src/server/workspace-registry.js +16 -13
- package/dist/src/server/workspace-registry.js.map +1 -1
- package/dist/src/server/worktree-bootstrap.js +17 -6
- package/dist/src/server/worktree-bootstrap.js.map +1 -1
- package/dist/src/shared/agent-attention-notification.js.map +1 -1
- package/dist/src/shared/daemon-endpoints.js +11 -2
- package/dist/src/shared/daemon-endpoints.js.map +1 -1
- package/dist/src/shared/messages.js +330 -302
- package/dist/src/shared/messages.js.map +1 -1
- package/dist/src/shared/terminal-stream-protocol.js +99 -0
- package/dist/src/shared/terminal-stream-protocol.js.map +1 -0
- package/dist/src/shared/tool-call-display.js +6 -3
- package/dist/src/shared/tool-call-display.js.map +1 -1
- package/dist/src/terminal/terminal.js +44 -98
- package/dist/src/terminal/terminal.js.map +1 -1
- package/dist/src/utils/checkout-git.js +111 -120
- package/dist/src/utils/checkout-git.js.map +1 -1
- package/dist/src/utils/directory-suggestions.js +40 -40
- package/dist/src/utils/directory-suggestions.js.map +1 -1
- package/dist/src/utils/project-icon.js +2 -11
- package/dist/src/utils/project-icon.js.map +1 -1
- package/dist/src/utils/worktree.js +22 -19
- package/dist/src/utils/worktree.js.map +1 -1
- package/package.json +3 -11
- package/dist/server/client/daemon-client-terminal-stream-manager.d.ts +0 -43
- package/dist/server/client/daemon-client-terminal-stream-manager.d.ts.map +0 -1
- package/dist/server/client/daemon-client-terminal-stream-manager.js +0 -134
- package/dist/server/client/daemon-client-terminal-stream-manager.js.map +0 -1
- package/dist/server/server/utils/syntax-highlighter.d.ts +0 -10
- package/dist/server/server/utils/syntax-highlighter.d.ts.map +0 -1
- package/dist/server/server/utils/syntax-highlighter.js +0 -145
- package/dist/server/server/utils/syntax-highlighter.js.map +0 -1
- package/dist/server/shared/binary-mux.d.ts +0 -31
- package/dist/server/shared/binary-mux.d.ts.map +0 -1
- package/dist/server/shared/binary-mux.js +0 -114
- package/dist/server/shared/binary-mux.js.map +0 -1
- package/dist/server/shared/terminal-key-input.d.ts +0 -9
- package/dist/server/shared/terminal-key-input.d.ts.map +0 -1
- package/dist/server/shared/terminal-key-input.js +0 -132
- package/dist/server/shared/terminal-key-input.js.map +0 -1
- package/dist/src/server/utils/syntax-highlighter.js +0 -145
- package/dist/src/server/utils/syntax-highlighter.js.map +0 -1
- package/dist/src/shared/binary-mux.js +0 -114
- package/dist/src/shared/binary-mux.js.map +0 -1
|
@@ -6,34 +6,14 @@ import os from "node:os";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { query, } from "@anthropic-ai/claude-agent-sdk";
|
|
8
8
|
import { mapClaudeCanceledToolCall, mapClaudeCompletedToolCall, mapClaudeFailedToolCall, mapClaudeRunningToolCall, } from "./claude/tool-call-mapper.js";
|
|
9
|
-
import {
|
|
9
|
+
import { coerceTaskNotificationHistoryRecordToSystemMessage, mapTaskNotificationSystemRecordToToolCall, mapTaskNotificationUserContentToToolCall, } from "./claude/task-notification-tool-call.js";
|
|
10
10
|
import { buildClaudeModelFamilyAliases, buildClaudeSelectableModelIds, listClaudeCatalogModels, } from "./claude/model-catalog.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { parsePartialJsonObject } from "./claude/partial-json.js";
|
|
12
|
+
import { ClaudeSidechainTracker } from "./claude/sidechain-tracker.js";
|
|
13
|
+
import { applyProviderEnv } from "../provider-launch-config.js";
|
|
13
14
|
import { getOrchestratorModeInstructions } from "../orchestrator-instructions.js";
|
|
14
|
-
/*
|
|
15
|
-
* Routing invariant:
|
|
16
|
-
* While a foreground Claude turn is active, identifier-less assistant/stream/result
|
|
17
|
-
* events must stay attached to that foreground run unless we have explicit evidence
|
|
18
|
-
* that a distinct autonomous run has started.
|
|
19
|
-
*
|
|
20
|
-
* We previously allowed task_notification metadata to reserve autonomous ownership,
|
|
21
|
-
* then consumed that reservation on the next unbound chunk. In practice Claude often
|
|
22
|
-
* emits task_notification records and foreground tool-use stream chunks interleaved
|
|
23
|
-
* within the same turn. That let a foreground turn's terminal result get misrouted
|
|
24
|
-
* into an autonomous side run, which stranded the agent in "running" because the
|
|
25
|
-
* foreground stream never received turn_completed.
|
|
26
|
-
*
|
|
27
|
-
* The rule below is intentionally conservative: foreground turns get first claim on
|
|
28
|
-
* same-turn traffic, and autonomous wake reservations are only consumed once no
|
|
29
|
-
* foreground turn is active. This keeps task_notification advisory instead of letting
|
|
30
|
-
* it steal ownership from the active user turn.
|
|
31
|
-
*/
|
|
32
15
|
const fsPromises = promises;
|
|
33
|
-
const CLAUDE_SETTING_SOURCES = [
|
|
34
|
-
"user",
|
|
35
|
-
"project",
|
|
36
|
-
];
|
|
16
|
+
const CLAUDE_SETTING_SOURCES = ["user", "project"];
|
|
37
17
|
function normalizeModelIdCandidate(modelId) {
|
|
38
18
|
if (typeof modelId !== "string") {
|
|
39
19
|
return null;
|
|
@@ -174,6 +154,8 @@ const REWIND_COMMAND = {
|
|
|
174
154
|
argumentHint: "[user_message_uuid]",
|
|
175
155
|
};
|
|
176
156
|
const INTERRUPT_TOOL_USE_PLACEHOLDER = "[Request interrupted by user for tool use]";
|
|
157
|
+
const INTERRUPT_PLACEHOLDER_PATTERN = /^\[Request interrupted by user(?:[^\]]*)\]$/;
|
|
158
|
+
const NO_RESPONSE_REQUESTED_PLACEHOLDER = "No response requested.";
|
|
177
159
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
178
160
|
function resolveClaudeSpawnCommand(spawnOptions, runtimeSettings) {
|
|
179
161
|
const commandConfig = runtimeSettings?.command;
|
|
@@ -202,9 +184,7 @@ function applyRuntimeSettingsToClaudeOptions(options, runtimeSettings) {
|
|
|
202
184
|
// The SDK defaults to spawning "node" via PATH lookup, which fails when
|
|
203
185
|
// running from the managed runtime bundle where node isn't in PATH.
|
|
204
186
|
// Always use process.execPath — the actual node binary running the daemon.
|
|
205
|
-
const command = resolved.command === spawnOptions.command
|
|
206
|
-
? process.execPath
|
|
207
|
-
: resolved.command;
|
|
187
|
+
const command = resolved.command === spawnOptions.command ? process.execPath : resolved.command;
|
|
208
188
|
return spawn(command, resolved.args, {
|
|
209
189
|
cwd: spawnOptions.cwd,
|
|
210
190
|
env: applyProviderEnv(spawnOptions.env, runtimeSettings),
|
|
@@ -227,32 +207,20 @@ function summarizeClaudeOptionsForLog(options) {
|
|
|
227
207
|
const prompt = systemPromptRaw;
|
|
228
208
|
const promptType = typeof prompt.type === "string" ? prompt.type : "custom";
|
|
229
209
|
return {
|
|
230
|
-
mode: promptType === "preset"
|
|
231
|
-
|
|
232
|
-
: "custom",
|
|
233
|
-
preset: typeof prompt.preset === "string" && prompt.preset.length > 0
|
|
234
|
-
? prompt.preset
|
|
235
|
-
: null,
|
|
210
|
+
mode: promptType === "preset" ? "preset" : "custom",
|
|
211
|
+
preset: typeof prompt.preset === "string" && prompt.preset.length > 0 ? prompt.preset : null,
|
|
236
212
|
};
|
|
237
213
|
})();
|
|
238
|
-
const mcpServerNames = options.mcpServers
|
|
239
|
-
? Object.keys(options.mcpServers).sort()
|
|
240
|
-
: [];
|
|
214
|
+
const mcpServerNames = options.mcpServers ? Object.keys(options.mcpServers).sort() : [];
|
|
241
215
|
return {
|
|
242
216
|
cwd: typeof options.cwd === "string" ? options.cwd : null,
|
|
243
|
-
permissionMode: typeof options.permissionMode === "string"
|
|
244
|
-
? options.permissionMode
|
|
245
|
-
: null,
|
|
217
|
+
permissionMode: typeof options.permissionMode === "string" ? options.permissionMode : null,
|
|
246
218
|
model: typeof options.model === "string" ? options.model : null,
|
|
247
219
|
includePartialMessages: options.includePartialMessages === true,
|
|
248
|
-
settingSources: Array.isArray(options.settingSources)
|
|
249
|
-
? options.settingSources
|
|
250
|
-
: [],
|
|
220
|
+
settingSources: Array.isArray(options.settingSources) ? options.settingSources : [],
|
|
251
221
|
enableFileCheckpointing: options.enableFileCheckpointing === true,
|
|
252
222
|
hasResume: typeof options.resume === "string" && options.resume.length > 0,
|
|
253
|
-
maxThinkingTokens: typeof options.maxThinkingTokens === "number"
|
|
254
|
-
? options.maxThinkingTokens
|
|
255
|
-
: null,
|
|
223
|
+
maxThinkingTokens: typeof options.maxThinkingTokens === "number" ? options.maxThinkingTokens : null,
|
|
256
224
|
hasEnv: !!options.env,
|
|
257
225
|
envKeyCount: Object.keys(options.env ?? {}).length,
|
|
258
226
|
hasMcpServers: mcpServerNames.length > 0,
|
|
@@ -337,10 +305,59 @@ function coerceToolResultContentToString(content) {
|
|
|
337
305
|
}
|
|
338
306
|
return deterministicStringify(content);
|
|
339
307
|
}
|
|
308
|
+
function normalizeClaudeTranscriptText(value) {
|
|
309
|
+
if (typeof value !== "string") {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
const normalized = value.trim();
|
|
313
|
+
return normalized.length > 0 ? normalized : null;
|
|
314
|
+
}
|
|
315
|
+
function isClaudeInterruptPlaceholderText(value) {
|
|
316
|
+
const normalized = normalizeClaudeTranscriptText(value);
|
|
317
|
+
return normalized !== null && INTERRUPT_PLACEHOLDER_PATTERN.test(normalized);
|
|
318
|
+
}
|
|
319
|
+
function isClaudeNoResponsePlaceholderText(value) {
|
|
320
|
+
return normalizeClaudeTranscriptText(value) === NO_RESPONSE_REQUESTED_PLACEHOLDER;
|
|
321
|
+
}
|
|
322
|
+
function isClaudeTranscriptNoiseText(value) {
|
|
323
|
+
return isClaudeInterruptPlaceholderText(value) || isClaudeNoResponsePlaceholderText(value);
|
|
324
|
+
}
|
|
325
|
+
function collectClaudeTextContentParts(content) {
|
|
326
|
+
if (typeof content === "string") {
|
|
327
|
+
const normalized = normalizeClaudeTranscriptText(content);
|
|
328
|
+
return normalized ? [normalized] : [];
|
|
329
|
+
}
|
|
330
|
+
if (!Array.isArray(content)) {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
const parts = [];
|
|
334
|
+
for (const block of content) {
|
|
335
|
+
if (!block || typeof block !== "object") {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const text = normalizeClaudeTranscriptText(block.text);
|
|
339
|
+
if (text) {
|
|
340
|
+
parts.push(text);
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
const input = normalizeClaudeTranscriptText(block.input);
|
|
344
|
+
if (input) {
|
|
345
|
+
parts.push(input);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return parts;
|
|
349
|
+
}
|
|
350
|
+
function isClaudeTranscriptNoiseContent(content) {
|
|
351
|
+
const parts = collectClaudeTextContentParts(content);
|
|
352
|
+
return parts.length > 0 && parts.every((part) => isClaudeTranscriptNoiseText(part));
|
|
353
|
+
}
|
|
340
354
|
export function extractUserMessageText(content) {
|
|
341
355
|
if (typeof content === "string") {
|
|
342
356
|
const normalized = content.trim();
|
|
343
|
-
|
|
357
|
+
if (!normalized || isClaudeTranscriptNoiseText(normalized)) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
return normalized;
|
|
344
361
|
}
|
|
345
362
|
if (!Array.isArray(content)) {
|
|
346
363
|
return null;
|
|
@@ -352,12 +369,18 @@ export function extractUserMessageText(content) {
|
|
|
352
369
|
}
|
|
353
370
|
const text = typeof block.text === "string" ? block.text : undefined;
|
|
354
371
|
if (text && text.trim()) {
|
|
355
|
-
|
|
372
|
+
const trimmed = text.trim();
|
|
373
|
+
if (!isClaudeTranscriptNoiseText(trimmed)) {
|
|
374
|
+
parts.push(trimmed);
|
|
375
|
+
}
|
|
356
376
|
continue;
|
|
357
377
|
}
|
|
358
378
|
const input = typeof block.input === "string" ? block.input : undefined;
|
|
359
379
|
if (input && input.trim()) {
|
|
360
|
-
|
|
380
|
+
const trimmed = input.trim();
|
|
381
|
+
if (!isClaudeTranscriptNoiseText(trimmed)) {
|
|
382
|
+
parts.push(trimmed);
|
|
383
|
+
}
|
|
361
384
|
}
|
|
362
385
|
}
|
|
363
386
|
if (parts.length === 0) {
|
|
@@ -366,8 +389,6 @@ export function extractUserMessageText(content) {
|
|
|
366
389
|
const combined = parts.join("\n\n").trim();
|
|
367
390
|
return combined.length > 0 ? combined : null;
|
|
368
391
|
}
|
|
369
|
-
const MAX_SUB_AGENT_LOG_ENTRIES = 200;
|
|
370
|
-
const MAX_SUB_AGENT_SUMMARY_CHARS = 160;
|
|
371
392
|
function isMetadata(value) {
|
|
372
393
|
return typeof value === "object" && value !== null;
|
|
373
394
|
}
|
|
@@ -507,179 +528,10 @@ function resolvePermissionKind(toolName, input) {
|
|
|
507
528
|
}
|
|
508
529
|
return "tool";
|
|
509
530
|
}
|
|
510
|
-
const ACTIVE_RUN_STATES = new Set([
|
|
511
|
-
"queued",
|
|
512
|
-
"awaiting_response",
|
|
513
|
-
"streaming",
|
|
514
|
-
"finalizing",
|
|
515
|
-
]);
|
|
516
|
-
class RunTracker {
|
|
517
|
-
constructor() {
|
|
518
|
-
this.runs = new Map();
|
|
519
|
-
this.runByTaskId = new Map();
|
|
520
|
-
this.runByParentMessageId = new Map();
|
|
521
|
-
this.runByMessageId = new Map();
|
|
522
|
-
}
|
|
523
|
-
createRun(input) {
|
|
524
|
-
const run = {
|
|
525
|
-
id: input.id,
|
|
526
|
-
owner: input.owner,
|
|
527
|
-
queue: input.queue,
|
|
528
|
-
state: "queued",
|
|
529
|
-
promptReplaySeen: input.promptReplaySeen ?? true,
|
|
530
|
-
taskIds: new Set(),
|
|
531
|
-
parentMessageIds: new Set(),
|
|
532
|
-
messageIds: new Set(),
|
|
533
|
-
};
|
|
534
|
-
this.runs.set(run.id, run);
|
|
535
|
-
return run;
|
|
536
|
-
}
|
|
537
|
-
getRun(runId) {
|
|
538
|
-
return this.runs.get(runId) ?? null;
|
|
539
|
-
}
|
|
540
|
-
getForegroundRun() {
|
|
541
|
-
for (const run of this.runs.values()) {
|
|
542
|
-
if (run.owner === "foreground" && this.isActive(run.state)) {
|
|
543
|
-
return run;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
return null;
|
|
547
|
-
}
|
|
548
|
-
listActiveRuns(owner) {
|
|
549
|
-
const runs = [];
|
|
550
|
-
for (const run of this.runs.values()) {
|
|
551
|
-
if (!this.isActive(run.state)) {
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
if (owner && run.owner !== owner) {
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
runs.push(run);
|
|
558
|
-
}
|
|
559
|
-
return runs;
|
|
560
|
-
}
|
|
561
|
-
hasActiveRuns(owner) {
|
|
562
|
-
for (const run of this.runs.values()) {
|
|
563
|
-
if (!this.isActive(run.state)) {
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
if (owner && run.owner !== owner) {
|
|
567
|
-
continue;
|
|
568
|
-
}
|
|
569
|
-
return true;
|
|
570
|
-
}
|
|
571
|
-
return false;
|
|
572
|
-
}
|
|
573
|
-
getLatestActiveRun(owner) {
|
|
574
|
-
let latest = null;
|
|
575
|
-
for (const run of this.runs.values()) {
|
|
576
|
-
if (!this.isActive(run.state)) {
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
if (owner && run.owner !== owner) {
|
|
580
|
-
continue;
|
|
581
|
-
}
|
|
582
|
-
latest = run;
|
|
583
|
-
}
|
|
584
|
-
return latest;
|
|
585
|
-
}
|
|
586
|
-
isRunActive(run) {
|
|
587
|
-
if (!run) {
|
|
588
|
-
return false;
|
|
589
|
-
}
|
|
590
|
-
return this.isActive(run.state);
|
|
591
|
-
}
|
|
592
|
-
resolveByIdentifiers(identifiers) {
|
|
593
|
-
if (identifiers.taskId) {
|
|
594
|
-
const run = this.resolveMappedRun(this.runByTaskId, identifiers.taskId);
|
|
595
|
-
if (run) {
|
|
596
|
-
return { run, reason: "task_id" };
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
if (identifiers.parentMessageId) {
|
|
600
|
-
const run = this.resolveMappedRun(this.runByParentMessageId, identifiers.parentMessageId);
|
|
601
|
-
if (run) {
|
|
602
|
-
return { run, reason: "parent_message_id" };
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (identifiers.messageId) {
|
|
606
|
-
const run = this.resolveMappedRun(this.runByMessageId, identifiers.messageId);
|
|
607
|
-
if (run) {
|
|
608
|
-
return { run, reason: "message_id" };
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return { run: null, reason: "metadata" };
|
|
612
|
-
}
|
|
613
|
-
bindIdentifiers(run, identifiers) {
|
|
614
|
-
if (identifiers.taskId) {
|
|
615
|
-
run.taskIds.add(identifiers.taskId);
|
|
616
|
-
this.runByTaskId.set(identifiers.taskId, run.id);
|
|
617
|
-
}
|
|
618
|
-
if (identifiers.parentMessageId) {
|
|
619
|
-
run.parentMessageIds.add(identifiers.parentMessageId);
|
|
620
|
-
this.runByParentMessageId.set(identifiers.parentMessageId, run.id);
|
|
621
|
-
}
|
|
622
|
-
if (identifiers.messageId) {
|
|
623
|
-
run.messageIds.add(identifiers.messageId);
|
|
624
|
-
this.runByMessageId.set(identifiers.messageId, run.id);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
transition(run, nextState) {
|
|
628
|
-
run.state = nextState;
|
|
629
|
-
}
|
|
630
|
-
complete(run, terminalState) {
|
|
631
|
-
run.state = terminalState;
|
|
632
|
-
this.clearRunIndex(run);
|
|
633
|
-
}
|
|
634
|
-
deriveLifecycle(pendingPermissionCount) {
|
|
635
|
-
for (const run of this.runs.values()) {
|
|
636
|
-
if (this.isActive(run.state)) {
|
|
637
|
-
return "running";
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
if (pendingPermissionCount > 0) {
|
|
641
|
-
return "permission";
|
|
642
|
-
}
|
|
643
|
-
for (const run of this.runs.values()) {
|
|
644
|
-
if (run.state === "error") {
|
|
645
|
-
return "error";
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
return "idle";
|
|
649
|
-
}
|
|
650
|
-
resolveMappedRun(mapping, identifier) {
|
|
651
|
-
const runId = mapping.get(identifier);
|
|
652
|
-
if (!runId) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
const run = this.runs.get(runId);
|
|
656
|
-
if (!run || !this.isActive(run.state)) {
|
|
657
|
-
mapping.delete(identifier);
|
|
658
|
-
return null;
|
|
659
|
-
}
|
|
660
|
-
return run;
|
|
661
|
-
}
|
|
662
|
-
clearRunIndex(run) {
|
|
663
|
-
for (const taskId of run.taskIds) {
|
|
664
|
-
this.runByTaskId.delete(taskId);
|
|
665
|
-
}
|
|
666
|
-
for (const parentMessageId of run.parentMessageIds) {
|
|
667
|
-
this.runByParentMessageId.delete(parentMessageId);
|
|
668
|
-
}
|
|
669
|
-
for (const messageId of run.messageIds) {
|
|
670
|
-
this.runByMessageId.delete(messageId);
|
|
671
|
-
}
|
|
672
|
-
run.taskIds.clear();
|
|
673
|
-
run.parentMessageIds.clear();
|
|
674
|
-
run.messageIds.clear();
|
|
675
|
-
}
|
|
676
|
-
isActive(state) {
|
|
677
|
-
return ACTIVE_RUN_STATES.has(state);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
531
|
class TimelineAssembler {
|
|
681
532
|
constructor() {
|
|
682
533
|
this.messages = new Map();
|
|
534
|
+
this.finalizedMessageIds = new Set();
|
|
683
535
|
this.activeMessageByRun = new Map();
|
|
684
536
|
this.syntheticMessageCounter = 0;
|
|
685
537
|
}
|
|
@@ -699,6 +551,9 @@ class TimelineAssembler {
|
|
|
699
551
|
if (!messageId) {
|
|
700
552
|
return [];
|
|
701
553
|
}
|
|
554
|
+
if (this.finalizedMessageIds.has(messageId)) {
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
702
557
|
const state = this.ensureMessageState(messageId, runId);
|
|
703
558
|
const fragments = this.extractFragments(message.message?.content);
|
|
704
559
|
return this.applyAbsoluteFragments(state, fragments);
|
|
@@ -798,13 +653,16 @@ class TimelineAssembler {
|
|
|
798
653
|
if (runId && this.activeMessageByRun.get(runId) === messageId) {
|
|
799
654
|
this.activeMessageByRun.delete(runId);
|
|
800
655
|
}
|
|
656
|
+
this.finalizedMessageIds.add(messageId);
|
|
657
|
+
this.messages.delete(messageId);
|
|
801
658
|
return items;
|
|
802
659
|
}
|
|
803
660
|
emitNewContent(state) {
|
|
804
661
|
const items = [];
|
|
805
662
|
const nextAssistantText = state.assistantText.slice(state.emittedAssistantLength);
|
|
806
663
|
if (nextAssistantText.length > 0 &&
|
|
807
|
-
nextAssistantText !== INTERRUPT_TOOL_USE_PLACEHOLDER
|
|
664
|
+
nextAssistantText !== INTERRUPT_TOOL_USE_PLACEHOLDER &&
|
|
665
|
+
!isClaudeTranscriptNoiseText(nextAssistantText)) {
|
|
808
666
|
state.emittedAssistantLength = state.assistantText.length;
|
|
809
667
|
items.push({ type: "assistant_message", text: nextAssistantText });
|
|
810
668
|
}
|
|
@@ -885,29 +743,13 @@ class TimelineAssembler {
|
|
|
885
743
|
}
|
|
886
744
|
readMessageIdFromAssistantMessage(message) {
|
|
887
745
|
const candidate = message;
|
|
888
|
-
return readTrimmedString(candidate.message_id) ??
|
|
889
|
-
readTrimmedString(candidate.message?.id) ??
|
|
890
|
-
null;
|
|
746
|
+
return (readTrimmedString(candidate.message_id) ?? readTrimmedString(candidate.message?.id) ?? null);
|
|
891
747
|
}
|
|
892
748
|
readMessageIdFromStreamEvent(event) {
|
|
893
749
|
const message = event.message;
|
|
894
|
-
return
|
|
895
|
-
readTrimmedString(message?.id) ??
|
|
896
|
-
null);
|
|
750
|
+
return readTrimmedString(event.message_id) ?? readTrimmedString(message?.id) ?? null;
|
|
897
751
|
}
|
|
898
752
|
}
|
|
899
|
-
function isMetadataOnlySdkMessage(message) {
|
|
900
|
-
if (message.type === "system") {
|
|
901
|
-
return true;
|
|
902
|
-
}
|
|
903
|
-
if (message.type !== "user") {
|
|
904
|
-
return false;
|
|
905
|
-
}
|
|
906
|
-
if (isSyntheticUserEntry(message)) {
|
|
907
|
-
return true;
|
|
908
|
-
}
|
|
909
|
-
return isTaskNotificationUserContent(message.message?.content);
|
|
910
|
-
}
|
|
911
753
|
function isSyntheticUserEntry(entry) {
|
|
912
754
|
if (!entry || typeof entry !== "object") {
|
|
913
755
|
return false;
|
|
@@ -1024,29 +866,30 @@ class ClaudeAgentSession {
|
|
|
1024
866
|
this.toolUseInputBuffers = new Map();
|
|
1025
867
|
this.pendingPermissions = new Map();
|
|
1026
868
|
this.activeForegroundTurn = null;
|
|
869
|
+
this.autonomousTurn = null;
|
|
1027
870
|
this.liveEventQueue = new Pushable();
|
|
1028
|
-
this.runTracker = new RunTracker();
|
|
1029
871
|
this.timelineAssembler = new TimelineAssembler();
|
|
872
|
+
this.sidechainTracker = new ClaudeSidechainTracker({
|
|
873
|
+
getToolInput: (toolUseId) => this.toolUseCache.get(toolUseId)?.input ?? null,
|
|
874
|
+
});
|
|
1030
875
|
this.persistedHistory = [];
|
|
1031
876
|
this.historyPending = false;
|
|
877
|
+
this.historyOffsetSessionId = null;
|
|
878
|
+
this.historyReadOffsetBytes = 0;
|
|
879
|
+
this.historyLineFragment = "";
|
|
1032
880
|
this.turnState = "idle";
|
|
1033
|
-
this.
|
|
1034
|
-
this.pendingAutonomousWakeReservations = 0;
|
|
1035
|
-
this.nextRunOrdinal = 1;
|
|
881
|
+
this.nextTurnOrdinal = 1;
|
|
1036
882
|
this.cancelCurrentTurn = null;
|
|
1037
|
-
this.pendingInterruptPromise = null;
|
|
1038
883
|
this.activeTurnPromise = null;
|
|
1039
884
|
this.cachedRuntimeInfo = null;
|
|
1040
885
|
this.lastOptionsModel = null;
|
|
1041
886
|
this.selectableModelIds = buildClaudeSelectableModelIds();
|
|
1042
887
|
this.selectableModelFamilyAliases = buildClaudeModelFamilyAliases();
|
|
1043
|
-
this.activeSidechains = new Map();
|
|
1044
888
|
this.compacting = false;
|
|
1045
889
|
this.queryPumpPromise = null;
|
|
1046
890
|
this.queryRestartNeeded = false;
|
|
891
|
+
this.pendingInterruptAbort = false;
|
|
1047
892
|
this.userMessageIds = [];
|
|
1048
|
-
this.localUserMessageIds = new Set();
|
|
1049
|
-
this.suppressLocalReplayActivity = false;
|
|
1050
893
|
this.recentStderr = "";
|
|
1051
894
|
this.closed = false;
|
|
1052
895
|
this.handlePermissionRequest = async (toolName, input, options) => {
|
|
@@ -1201,34 +1044,25 @@ class ClaudeAgentSession {
|
|
|
1201
1044
|
if (this.cancelCurrentTurn) {
|
|
1202
1045
|
this.cancelCurrentTurn();
|
|
1203
1046
|
}
|
|
1204
|
-
this.suppressLocalReplayActivity = false;
|
|
1205
|
-
this.pendingAutonomousWakeReservations = 0;
|
|
1206
1047
|
const slashCommand = this.resolveSlashCommandInvocation(prompt);
|
|
1207
1048
|
if (slashCommand?.commandName === REWIND_COMMAND_NAME) {
|
|
1208
1049
|
yield* this.streamRewindCommand(slashCommand);
|
|
1209
1050
|
return;
|
|
1210
1051
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
this.runTracker.hasActiveRuns("autonomous")) {
|
|
1214
|
-
await this.transitionAutonomousToForeground();
|
|
1052
|
+
if (this.autonomousTurn) {
|
|
1053
|
+
this.completeAutonomousTurn();
|
|
1215
1054
|
}
|
|
1216
1055
|
const sdkMessage = this.toSdkUserMessage(prompt);
|
|
1217
1056
|
const queue = new Pushable();
|
|
1218
|
-
const run = this.createRun("foreground", queue);
|
|
1219
|
-
this.runTracker.bindIdentifiers(run, {
|
|
1220
|
-
taskId: null,
|
|
1221
|
-
parentMessageId: null,
|
|
1222
|
-
messageId: typeof sdkMessage.uuid === "string" ? sdkMessage.uuid : null,
|
|
1223
|
-
});
|
|
1224
1057
|
const foregroundTurn = {
|
|
1225
|
-
|
|
1058
|
+
id: this.createTurnId("foreground"),
|
|
1226
1059
|
queue,
|
|
1060
|
+
hasVisibleActivity: false,
|
|
1227
1061
|
};
|
|
1228
1062
|
this.activeForegroundTurn = foregroundTurn;
|
|
1229
|
-
this.preReplayMetadataSeen = false;
|
|
1230
1063
|
this.transitionTurnState("foreground", "foreground stream started");
|
|
1231
1064
|
this.clearRecentStderr();
|
|
1065
|
+
queue.push({ type: "turn_started", provider: "claude" });
|
|
1232
1066
|
let finishedNaturally = false;
|
|
1233
1067
|
let cancelIssued = false;
|
|
1234
1068
|
let queueDrainedWithoutTerminal = false;
|
|
@@ -1239,19 +1073,16 @@ class ClaudeAgentSession {
|
|
|
1239
1073
|
return;
|
|
1240
1074
|
}
|
|
1241
1075
|
cancelIssued = true;
|
|
1242
|
-
if (this.activeForegroundTurn?.runId === run.id) {
|
|
1243
|
-
this.activeForegroundTurn = null;
|
|
1244
|
-
}
|
|
1245
1076
|
if (this.cancelCurrentTurn === requestCancel) {
|
|
1246
1077
|
this.cancelCurrentTurn = null;
|
|
1247
1078
|
}
|
|
1248
1079
|
this.rejectAllPendingPermissions(new Error("Permission request aborted"));
|
|
1249
|
-
this.
|
|
1080
|
+
this.finishForegroundTurn({
|
|
1250
1081
|
type: "turn_canceled",
|
|
1251
1082
|
provider: "claude",
|
|
1252
1083
|
reason: "Interrupted",
|
|
1253
1084
|
});
|
|
1254
|
-
|
|
1085
|
+
void this.interruptActiveTurn().catch((error) => {
|
|
1255
1086
|
this.logger.warn({ err: error }, "Failed to interrupt during cancel");
|
|
1256
1087
|
});
|
|
1257
1088
|
};
|
|
@@ -1265,7 +1096,7 @@ class ClaudeAgentSession {
|
|
|
1265
1096
|
this.input.push(sdkMessage);
|
|
1266
1097
|
}
|
|
1267
1098
|
catch (error) {
|
|
1268
|
-
this.
|
|
1099
|
+
this.finishForegroundTurn(this.buildTurnFailedEvent(error instanceof Error ? error.message : "Claude stream failed"));
|
|
1269
1100
|
finishedNaturally = true;
|
|
1270
1101
|
}
|
|
1271
1102
|
try {
|
|
@@ -1305,16 +1136,8 @@ class ClaudeAgentSession {
|
|
|
1305
1136
|
this.cancelCurrentTurn();
|
|
1306
1137
|
return;
|
|
1307
1138
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
this.flushPendingToolCalls();
|
|
1311
|
-
for (const run of autonomousRuns) {
|
|
1312
|
-
this.emitRunEvent(run, {
|
|
1313
|
-
type: "turn_canceled",
|
|
1314
|
-
provider: "claude",
|
|
1315
|
-
reason: "Interrupted",
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1139
|
+
if (this.autonomousTurn) {
|
|
1140
|
+
this.cancelAutonomousTurn("Interrupted");
|
|
1318
1141
|
}
|
|
1319
1142
|
await this.interruptActiveTurn();
|
|
1320
1143
|
}
|
|
@@ -1463,12 +1286,12 @@ class ClaudeAgentSession {
|
|
|
1463
1286
|
this.cancelCurrentTurn?.();
|
|
1464
1287
|
this.activeForegroundTurn?.queue.end();
|
|
1465
1288
|
this.activeForegroundTurn = null;
|
|
1289
|
+
this.autonomousTurn = null;
|
|
1466
1290
|
this.cancelCurrentTurn = null;
|
|
1467
1291
|
this.turnState = "idle";
|
|
1468
|
-
this.suppressLocalReplayActivity = false;
|
|
1469
|
-
this.pendingAutonomousWakeReservations = 0;
|
|
1470
1292
|
this.liveEventQueue.end();
|
|
1471
1293
|
this.activeTurnPromise = null;
|
|
1294
|
+
this.sidechainTracker.clear();
|
|
1472
1295
|
this.input?.end();
|
|
1473
1296
|
await this.awaitWithTimeout(this.query?.interrupt?.(), "close query interrupt");
|
|
1474
1297
|
await this.awaitWithTimeout(this.query?.return?.(), "close query return");
|
|
@@ -1511,15 +1334,11 @@ class ClaudeAgentSession {
|
|
|
1511
1334
|
}
|
|
1512
1335
|
const withoutPrefix = trimmed.slice(1);
|
|
1513
1336
|
const firstWhitespaceIdx = withoutPrefix.search(/\s/);
|
|
1514
|
-
const commandName = firstWhitespaceIdx === -1
|
|
1515
|
-
? withoutPrefix
|
|
1516
|
-
: withoutPrefix.slice(0, firstWhitespaceIdx);
|
|
1337
|
+
const commandName = firstWhitespaceIdx === -1 ? withoutPrefix : withoutPrefix.slice(0, firstWhitespaceIdx);
|
|
1517
1338
|
if (!commandName || commandName.includes("/")) {
|
|
1518
1339
|
return null;
|
|
1519
1340
|
}
|
|
1520
|
-
const rawArgs = firstWhitespaceIdx === -1
|
|
1521
|
-
? ""
|
|
1522
|
-
: withoutPrefix.slice(firstWhitespaceIdx + 1).trim();
|
|
1341
|
+
const rawArgs = firstWhitespaceIdx === -1 ? "" : withoutPrefix.slice(firstWhitespaceIdx + 1).trim();
|
|
1523
1342
|
return rawArgs.length > 0
|
|
1524
1343
|
? { commandName, args: rawArgs, rawInput: trimmed }
|
|
1525
1344
|
: { commandName, rawInput: trimmed };
|
|
@@ -1551,9 +1370,7 @@ class ClaudeAgentSession {
|
|
|
1551
1370
|
yield {
|
|
1552
1371
|
type: "turn_failed",
|
|
1553
1372
|
provider: "claude",
|
|
1554
|
-
error: error instanceof Error
|
|
1555
|
-
? error.message
|
|
1556
|
-
: "Failed to rewind tracked files",
|
|
1373
|
+
error: error instanceof Error ? error.message : "Failed to rewind tracked files",
|
|
1557
1374
|
};
|
|
1558
1375
|
}
|
|
1559
1376
|
}
|
|
@@ -1591,8 +1408,7 @@ class ClaudeAgentSession {
|
|
|
1591
1408
|
}
|
|
1592
1409
|
return {
|
|
1593
1410
|
messageId: null,
|
|
1594
|
-
error: rewindResult.error ??
|
|
1595
|
-
`No file checkpoint found for message ${candidate}.`,
|
|
1411
|
+
error: rewindResult.error ?? `No file checkpoint found for message ${candidate}.`,
|
|
1596
1412
|
};
|
|
1597
1413
|
}
|
|
1598
1414
|
const candidates = this.getRewindCandidateUserMessageIds();
|
|
@@ -1614,16 +1430,12 @@ class ClaudeAgentSession {
|
|
|
1614
1430
|
}
|
|
1615
1431
|
}
|
|
1616
1432
|
catch (error) {
|
|
1617
|
-
lastError =
|
|
1618
|
-
error instanceof Error
|
|
1619
|
-
? error.message
|
|
1620
|
-
: "Failed to rewind tracked files.";
|
|
1433
|
+
lastError = error instanceof Error ? error.message : "Failed to rewind tracked files.";
|
|
1621
1434
|
}
|
|
1622
1435
|
}
|
|
1623
1436
|
return {
|
|
1624
1437
|
messageId: null,
|
|
1625
|
-
error: lastError ??
|
|
1626
|
-
"No rewind checkpoints are currently available for this session.",
|
|
1438
|
+
error: lastError ?? "No rewind checkpoints are currently available for this session.",
|
|
1627
1439
|
};
|
|
1628
1440
|
}
|
|
1629
1441
|
async rewindFilesOnce(messageId) {
|
|
@@ -1647,9 +1459,7 @@ class ClaudeAgentSession {
|
|
|
1647
1459
|
getRewindCandidateUserMessageIds() {
|
|
1648
1460
|
const candidates = [];
|
|
1649
1461
|
const pushUnique = (value) => {
|
|
1650
|
-
if (typeof value === "string" &&
|
|
1651
|
-
value.length > 0 &&
|
|
1652
|
-
!candidates.includes(value)) {
|
|
1462
|
+
if (typeof value === "string" && value.length > 0 && !candidates.includes(value)) {
|
|
1653
1463
|
candidates.push(value);
|
|
1654
1464
|
}
|
|
1655
1465
|
};
|
|
@@ -1718,7 +1528,9 @@ class ClaudeAgentSession {
|
|
|
1718
1528
|
try {
|
|
1719
1529
|
await this.query.return?.();
|
|
1720
1530
|
}
|
|
1721
|
-
catch {
|
|
1531
|
+
catch {
|
|
1532
|
+
/* ignore */
|
|
1533
|
+
}
|
|
1722
1534
|
this.query = null;
|
|
1723
1535
|
this.input = null;
|
|
1724
1536
|
this.queryRestartNeeded = false;
|
|
@@ -1850,7 +1662,6 @@ class ClaudeAgentSession {
|
|
|
1850
1662
|
}
|
|
1851
1663
|
const messageId = randomUUID();
|
|
1852
1664
|
this.rememberUserMessageId(messageId);
|
|
1853
|
-
this.localUserMessageIds.add(messageId);
|
|
1854
1665
|
return {
|
|
1855
1666
|
type: "user",
|
|
1856
1667
|
message: {
|
|
@@ -1862,24 +1673,6 @@ class ClaudeAgentSession {
|
|
|
1862
1673
|
session_id: this.claudeSessionId ?? "",
|
|
1863
1674
|
};
|
|
1864
1675
|
}
|
|
1865
|
-
async awaitPendingInterruptPromise() {
|
|
1866
|
-
if (!this.pendingInterruptPromise) {
|
|
1867
|
-
return;
|
|
1868
|
-
}
|
|
1869
|
-
await this.pendingInterruptPromise;
|
|
1870
|
-
this.pendingInterruptPromise = null;
|
|
1871
|
-
}
|
|
1872
|
-
createRun(owner, queue) {
|
|
1873
|
-
const runId = `${owner}-run-${this.nextRunOrdinal++}`;
|
|
1874
|
-
const run = this.runTracker.createRun({
|
|
1875
|
-
id: runId,
|
|
1876
|
-
owner,
|
|
1877
|
-
queue,
|
|
1878
|
-
promptReplaySeen: owner === "autonomous",
|
|
1879
|
-
});
|
|
1880
|
-
this.logger.debug({ runId, owner, state: run.state }, "Created Claude run");
|
|
1881
|
-
return run;
|
|
1882
|
-
}
|
|
1883
1676
|
transitionTurnState(next, reason) {
|
|
1884
1677
|
if (this.turnState === next) {
|
|
1885
1678
|
return;
|
|
@@ -1887,20 +1680,17 @@ class ClaudeAgentSession {
|
|
|
1887
1680
|
this.logger.debug({ from: this.turnState, to: next, reason }, "Claude turn state transition");
|
|
1888
1681
|
this.turnState = next;
|
|
1889
1682
|
}
|
|
1890
|
-
|
|
1891
|
-
if (this.
|
|
1683
|
+
syncTurnState(reason) {
|
|
1684
|
+
if (this.activeForegroundTurn) {
|
|
1892
1685
|
this.transitionTurnState("foreground", reason);
|
|
1893
1686
|
return;
|
|
1894
1687
|
}
|
|
1895
|
-
if (this.
|
|
1688
|
+
if (this.autonomousTurn) {
|
|
1896
1689
|
this.transitionTurnState("autonomous", reason);
|
|
1897
1690
|
return;
|
|
1898
1691
|
}
|
|
1899
1692
|
this.transitionTurnState("idle", reason);
|
|
1900
1693
|
}
|
|
1901
|
-
failRun(run, errorMessage) {
|
|
1902
|
-
this.emitRunEvent(run, this.buildTurnFailedEvent(errorMessage));
|
|
1903
|
-
}
|
|
1904
1694
|
buildTurnFailedEvent(errorMessage) {
|
|
1905
1695
|
const normalized = errorMessage.trim() || "Claude run failed";
|
|
1906
1696
|
const exitCodeMatch = normalized.match(/\bcode\s+(\d+)\b/i);
|
|
@@ -1926,274 +1716,106 @@ class ClaudeAgentSession {
|
|
|
1926
1716
|
this.recentStderr = "";
|
|
1927
1717
|
}
|
|
1928
1718
|
getRecentStderrDiagnostic() {
|
|
1929
|
-
|
|
1930
|
-
return text.length > 0 ? text : undefined;
|
|
1719
|
+
return this.recentStderr.trim() || undefined;
|
|
1931
1720
|
}
|
|
1932
|
-
|
|
1933
|
-
this.
|
|
1934
|
-
this.emitRunEvent(run, event);
|
|
1721
|
+
createTurnId(owner) {
|
|
1722
|
+
return `${owner}-turn-${this.nextTurnOrdinal++}`;
|
|
1935
1723
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
event.type === "turn_completed" ||
|
|
1724
|
+
isTerminalTurnEvent(event) {
|
|
1725
|
+
return (event.type === "turn_completed" ||
|
|
1939
1726
|
event.type === "turn_failed" ||
|
|
1940
|
-
event.type === "turn_canceled")
|
|
1941
|
-
this.logger.trace({
|
|
1942
|
-
runId: run.id,
|
|
1943
|
-
owner: run.owner,
|
|
1944
|
-
runState: run.state,
|
|
1945
|
-
eventType: event.type,
|
|
1946
|
-
routedTo: run.owner === "foreground" && run.queue ? "foreground_queue" : "live_queue",
|
|
1947
|
-
}, "Claude run event emitted");
|
|
1948
|
-
}
|
|
1949
|
-
if (run.owner === "foreground" && run.queue) {
|
|
1950
|
-
run.queue.push(event);
|
|
1951
|
-
if (event.type === "turn_completed" ||
|
|
1952
|
-
event.type === "turn_failed" ||
|
|
1953
|
-
event.type === "turn_canceled") {
|
|
1954
|
-
run.queue.end();
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
else {
|
|
1958
|
-
this.liveEventQueue.push(event);
|
|
1959
|
-
}
|
|
1960
|
-
this.handleRunTerminalEvent(run, event);
|
|
1727
|
+
event.type === "turn_canceled");
|
|
1961
1728
|
}
|
|
1962
|
-
|
|
1963
|
-
if (
|
|
1964
|
-
|
|
1965
|
-
}
|
|
1966
|
-
else if (event.type === "turn_failed") {
|
|
1967
|
-
this.runTracker.complete(run, "error");
|
|
1968
|
-
}
|
|
1969
|
-
else if (event.type === "turn_canceled") {
|
|
1970
|
-
this.runTracker.complete(run, "interrupted");
|
|
1971
|
-
}
|
|
1972
|
-
else {
|
|
1973
|
-
return;
|
|
1729
|
+
shouldRecoverInterruptedQueryAbort(error, consecutiveRecoveries) {
|
|
1730
|
+
if (consecutiveRecoveries >= 3) {
|
|
1731
|
+
return false;
|
|
1974
1732
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1733
|
+
const message = typeof error === "string"
|
|
1734
|
+
? error
|
|
1735
|
+
: error instanceof Error
|
|
1736
|
+
? `${error.message}\n${error.stack ?? ""}`
|
|
1737
|
+
: JSON.stringify(error);
|
|
1738
|
+
return message.toLowerCase().includes("request was aborted");
|
|
1739
|
+
}
|
|
1740
|
+
finishForegroundTurn(event) {
|
|
1741
|
+
if (event.type === "turn_failed" || event.type === "turn_canceled") {
|
|
1742
|
+
this.flushPendingToolCalls();
|
|
1978
1743
|
}
|
|
1979
|
-
this.
|
|
1980
|
-
runId: run.id,
|
|
1981
|
-
owner: run.owner,
|
|
1982
|
-
eventType: event.type,
|
|
1983
|
-
runState: run.state,
|
|
1984
|
-
hasActiveForegroundTurn: Boolean(this.activeForegroundTurn),
|
|
1985
|
-
}, "Claude run terminal event handled");
|
|
1986
|
-
this.transitionTurnStateFromActiveRuns(`run ${run.id} terminal`);
|
|
1744
|
+
this.dispatchForegroundEvents([event]);
|
|
1987
1745
|
}
|
|
1988
|
-
|
|
1989
|
-
const
|
|
1990
|
-
if (
|
|
1991
|
-
this.
|
|
1746
|
+
dispatchForegroundEvents(events) {
|
|
1747
|
+
const foregroundTurn = this.activeForegroundTurn;
|
|
1748
|
+
if (!foregroundTurn) {
|
|
1749
|
+
this.dispatchLiveEvents(events);
|
|
1992
1750
|
return;
|
|
1993
1751
|
}
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
this.
|
|
1998
|
-
type: "turn_canceled",
|
|
1999
|
-
provider: "claude",
|
|
2000
|
-
reason: "Interrupted by foreground prompt",
|
|
2001
|
-
});
|
|
2002
|
-
}
|
|
2003
|
-
this.pendingInterruptPromise = this.interruptActiveTurn().catch((error) => {
|
|
2004
|
-
this.logger.warn({ err: error }, "Failed to interrupt autonomous run during foreground transition");
|
|
2005
|
-
});
|
|
2006
|
-
await this.awaitPendingInterruptPromise();
|
|
2007
|
-
this.transitionTurnStateFromActiveRuns("autonomous interrupted for foreground");
|
|
2008
|
-
}
|
|
2009
|
-
routeMessage(normalized) {
|
|
2010
|
-
if (normalized.metadataOnly) {
|
|
2011
|
-
if ((normalized.message.type === "user" &&
|
|
2012
|
-
isTaskNotificationUserContent(normalized.message.message?.content)) ||
|
|
2013
|
-
(normalized.message.type === "system" &&
|
|
2014
|
-
normalized.message.subtype === "task_notification")) {
|
|
2015
|
-
this.reserveAutonomousWake("task_notification");
|
|
2016
|
-
}
|
|
2017
|
-
this.notePreReplayMetadata(normalized.message);
|
|
2018
|
-
return { run: null, reason: "metadata" };
|
|
2019
|
-
}
|
|
2020
|
-
const hasIdentifiers = Boolean(normalized.identifiers.taskId ||
|
|
2021
|
-
normalized.identifiers.parentMessageId ||
|
|
2022
|
-
normalized.identifiers.messageId);
|
|
2023
|
-
const byIdentifiers = this.runTracker.resolveByIdentifiers(normalized.identifiers);
|
|
2024
|
-
if (byIdentifiers.run) {
|
|
2025
|
-
return byIdentifiers;
|
|
2026
|
-
}
|
|
2027
|
-
const foregroundRun = this.activeForegroundTurn
|
|
2028
|
-
? this.runTracker.getRun(this.activeForegroundTurn.runId)
|
|
2029
|
-
: null;
|
|
2030
|
-
// A previously unseen task_id during foreground ownership is deterministic
|
|
2031
|
-
// evidence of a distinct autonomous wake/run, not foreground response text.
|
|
2032
|
-
if (this.turnState === "foreground" &&
|
|
2033
|
-
foregroundRun &&
|
|
2034
|
-
normalized.identifiers.taskId) {
|
|
2035
|
-
const incomingTaskId = normalized.identifiers.taskId;
|
|
2036
|
-
// Foreground must claim its first task_id; otherwise early foreground
|
|
2037
|
-
// result events can be misrouted to autonomous fallback runs.
|
|
2038
|
-
if (foregroundRun.taskIds.size === 0) {
|
|
2039
|
-
if (foregroundRun.state !== "finalizing") {
|
|
2040
|
-
return { run: foregroundRun, reason: "foreground" };
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
else if (foregroundRun.taskIds.has(incomingTaskId)) {
|
|
2044
|
-
return { run: foregroundRun, reason: "foreground" };
|
|
2045
|
-
}
|
|
2046
|
-
const autonomousRun = this.createRun("autonomous", null);
|
|
2047
|
-
this.emitRunEvent(autonomousRun, { type: "turn_started", provider: "claude" });
|
|
2048
|
-
return { run: autonomousRun, reason: "task_id_new" };
|
|
2049
|
-
}
|
|
2050
|
-
if (this.turnState === "foreground" &&
|
|
2051
|
-
foregroundRun &&
|
|
2052
|
-
this.shouldPreferForegroundRun({
|
|
2053
|
-
run: foregroundRun,
|
|
2054
|
-
message: normalized.message,
|
|
2055
|
-
})) {
|
|
2056
|
-
return { run: foregroundRun, reason: "foreground" };
|
|
2057
|
-
}
|
|
2058
|
-
if (this.pendingAutonomousWakeReservations > 0 &&
|
|
2059
|
-
!normalized.identifiers.taskId &&
|
|
2060
|
-
!normalized.identifiers.parentMessageId &&
|
|
2061
|
-
!normalized.identifiers.messageId) {
|
|
2062
|
-
const reservedAutonomousRun = this.claimOrCreateAutonomousRun("reservation_unbound");
|
|
2063
|
-
return {
|
|
2064
|
-
run: reservedAutonomousRun,
|
|
2065
|
-
reason: "reserved_autonomous",
|
|
2066
|
-
};
|
|
2067
|
-
}
|
|
2068
|
-
if (!hasIdentifiers) {
|
|
2069
|
-
const activeAutonomousRun = this.runTracker.getLatestActiveRun("autonomous");
|
|
2070
|
-
if (activeAutonomousRun) {
|
|
2071
|
-
return { run: activeAutonomousRun, reason: "unbound_autonomous" };
|
|
2072
|
-
}
|
|
2073
|
-
if (!foregroundRun &&
|
|
2074
|
-
(normalized.message.type === "assistant" ||
|
|
2075
|
-
normalized.message.type === "stream_event" ||
|
|
2076
|
-
normalized.message.type === "result" ||
|
|
2077
|
-
normalized.message.type === "tool_progress")) {
|
|
2078
|
-
const autonomousRun = this.claimOrCreateAutonomousRun("unbound_implicit");
|
|
2079
|
-
return { run: autonomousRun, reason: "unbound_autonomous" };
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
if (this.pendingAutonomousWakeReservations > 0) {
|
|
2083
|
-
const reservedAutonomousRun = this.claimOrCreateAutonomousRun("reservation_fallback");
|
|
2084
|
-
return { run: reservedAutonomousRun, reason: "reserved_autonomous" };
|
|
2085
|
-
}
|
|
2086
|
-
this.logger.debug({
|
|
2087
|
-
messageType: normalized.message.type,
|
|
2088
|
-
hasIdentifiers,
|
|
2089
|
-
taskId: normalized.identifiers.taskId,
|
|
2090
|
-
parentMessageId: normalized.identifiers.parentMessageId,
|
|
2091
|
-
messageId: normalized.identifiers.messageId,
|
|
2092
|
-
turnState: this.turnState,
|
|
2093
|
-
pendingAutonomousWakeReservations: this.pendingAutonomousWakeReservations,
|
|
2094
|
-
}, "Ignoring unmatched Claude SDK message without explicit run start signal");
|
|
2095
|
-
return {
|
|
2096
|
-
run: null,
|
|
2097
|
-
reason: "ignored_unmatched",
|
|
2098
|
-
dispatchWithoutRun: false,
|
|
2099
|
-
};
|
|
2100
|
-
}
|
|
2101
|
-
shouldPreferForegroundRun(input) {
|
|
2102
|
-
const { run, message } = input;
|
|
2103
|
-
if (run.state === "completed" ||
|
|
2104
|
-
run.state === "interrupted" ||
|
|
2105
|
-
run.state === "error") {
|
|
2106
|
-
return false;
|
|
1752
|
+
let terminalSeen = false;
|
|
1753
|
+
for (const event of events) {
|
|
1754
|
+
foregroundTurn.queue.push(event);
|
|
1755
|
+
terminalSeen || (terminalSeen = this.isTerminalTurnEvent(event));
|
|
2107
1756
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
// was observed pre-replay, stay conservative and wait for replay.
|
|
2111
|
-
if (!run.promptReplaySeen) {
|
|
2112
|
-
if (this.isToolUseBoundaryStreamEvent(input.message)) {
|
|
2113
|
-
return true;
|
|
2114
|
-
}
|
|
2115
|
-
// Keep pre-replay result events with the foreground run so stale result
|
|
2116
|
-
// bursts cannot consume autonomous wake reservations.
|
|
2117
|
-
if (message.type === "result") {
|
|
2118
|
-
return true;
|
|
2119
|
-
}
|
|
2120
|
-
if (message.type === "assistant" ||
|
|
2121
|
-
message.type === "stream_event" ||
|
|
2122
|
-
message.type === "tool_progress") {
|
|
2123
|
-
return !this.preReplayMetadataSeen;
|
|
2124
|
-
}
|
|
2125
|
-
return true;
|
|
1757
|
+
if (!terminalSeen) {
|
|
1758
|
+
return;
|
|
2126
1759
|
}
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
1760
|
+
foregroundTurn.queue.end();
|
|
1761
|
+
if (this.activeForegroundTurn === foregroundTurn) {
|
|
1762
|
+
this.activeForegroundTurn = null;
|
|
2130
1763
|
}
|
|
2131
|
-
|
|
1764
|
+
this.syncTurnState("foreground turn terminal");
|
|
2132
1765
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
1766
|
+
dispatchLiveEvents(events) {
|
|
1767
|
+
let terminalSeen = false;
|
|
1768
|
+
for (const event of events) {
|
|
1769
|
+
this.liveEventQueue.push(event);
|
|
1770
|
+
terminalSeen || (terminalSeen = this.isTerminalTurnEvent(event));
|
|
2136
1771
|
}
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
1772
|
+
if (terminalSeen && this.autonomousTurn) {
|
|
1773
|
+
this.autonomousTurn = null;
|
|
1774
|
+
this.syncTurnState("autonomous turn terminal");
|
|
2140
1775
|
}
|
|
2141
|
-
const delta = "delta" in event && event.delta && typeof event.delta === "object"
|
|
2142
|
-
? event.delta
|
|
2143
|
-
: null;
|
|
2144
|
-
return delta?.stop_reason === "tool_use";
|
|
2145
1776
|
}
|
|
2146
|
-
|
|
2147
|
-
if (this.
|
|
1777
|
+
startAutonomousTurn() {
|
|
1778
|
+
if (this.autonomousTurn) {
|
|
2148
1779
|
return;
|
|
2149
1780
|
}
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
1781
|
+
this.autonomousTurn = {
|
|
1782
|
+
id: this.createTurnId("autonomous"),
|
|
1783
|
+
};
|
|
1784
|
+
this.liveEventQueue.push({ type: "turn_started", provider: "claude" });
|
|
1785
|
+
this.syncTurnState("autonomous turn started");
|
|
1786
|
+
}
|
|
1787
|
+
completeAutonomousTurn() {
|
|
1788
|
+
if (!this.autonomousTurn) {
|
|
2154
1789
|
return;
|
|
2155
1790
|
}
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
1791
|
+
this.autonomousTurn = null;
|
|
1792
|
+
this.liveEventQueue.push({ type: "turn_completed", provider: "claude" });
|
|
1793
|
+
this.syncTurnState("autonomous turn completed");
|
|
1794
|
+
}
|
|
1795
|
+
cancelAutonomousTurn(reason) {
|
|
1796
|
+
if (!this.autonomousTurn) {
|
|
2162
1797
|
return;
|
|
2163
1798
|
}
|
|
2164
|
-
this.
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
1799
|
+
this.flushPendingToolCalls();
|
|
1800
|
+
this.autonomousTurn = null;
|
|
1801
|
+
this.liveEventQueue.push({
|
|
1802
|
+
type: "turn_canceled",
|
|
1803
|
+
provider: "claude",
|
|
2169
1804
|
reason,
|
|
2170
|
-
|
|
2171
|
-
|
|
1805
|
+
});
|
|
1806
|
+
this.syncTurnState("autonomous turn canceled");
|
|
2172
1807
|
}
|
|
2173
|
-
|
|
2174
|
-
const
|
|
2175
|
-
if (
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
this.logger.debug({
|
|
2180
|
-
reason,
|
|
2181
|
-
runId: existing.id,
|
|
2182
|
-
pendingAutonomousWakeReservations: this.pendingAutonomousWakeReservations,
|
|
2183
|
-
}, "Claimed autonomous wake reservation on existing run");
|
|
2184
|
-
return existing;
|
|
1808
|
+
failActiveTurns(errorMessage) {
|
|
1809
|
+
const failure = this.buildTurnFailedEvent(errorMessage);
|
|
1810
|
+
if (this.activeForegroundTurn) {
|
|
1811
|
+
this.flushPendingToolCalls();
|
|
1812
|
+
this.dispatchForegroundEvents([failure]);
|
|
1813
|
+
return;
|
|
2185
1814
|
}
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
this.pendingAutonomousWakeReservations -= 1;
|
|
1815
|
+
if (this.autonomousTurn) {
|
|
1816
|
+
this.flushPendingToolCalls();
|
|
1817
|
+
this.dispatchLiveEvents([failure]);
|
|
2190
1818
|
}
|
|
2191
|
-
this.logger.debug({
|
|
2192
|
-
reason,
|
|
2193
|
-
runId: run.id,
|
|
2194
|
-
pendingAutonomousWakeReservations: this.pendingAutonomousWakeReservations,
|
|
2195
|
-
}, "Claimed autonomous wake reservation with new run");
|
|
2196
|
-
return run;
|
|
2197
1819
|
}
|
|
2198
1820
|
startQueryPump() {
|
|
2199
1821
|
if (this.closed || this.queryPumpPromise) {
|
|
@@ -2210,139 +1832,83 @@ class ClaudeAgentSession {
|
|
|
2210
1832
|
});
|
|
2211
1833
|
}
|
|
2212
1834
|
async runQueryPump() {
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
}
|
|
2238
|
-
this.logger.trace({ err: error }, "Claude query pump next() failed");
|
|
2239
|
-
for (const run of this.runTracker.listActiveRuns()) {
|
|
2240
|
-
this.failRun(run, error instanceof Error ? error.message : "Claude stream failed");
|
|
2241
|
-
}
|
|
2242
|
-
this.input?.end();
|
|
2243
|
-
await this.awaitWithTimeout(q.return?.(), "query pump return after failure");
|
|
2244
|
-
if (this.query === q) {
|
|
2245
|
-
this.query = null;
|
|
2246
|
-
this.input = null;
|
|
2247
|
-
}
|
|
2248
|
-
await this.waitForLiveHistoryPoll();
|
|
2249
|
-
continue;
|
|
2250
|
-
}
|
|
2251
|
-
if (next.done) {
|
|
2252
|
-
if (this.query !== q) {
|
|
2253
|
-
this.logger.trace({
|
|
2254
|
-
claudeSessionId: this.claudeSessionId,
|
|
2255
|
-
activeRunCount: this.runTracker.listActiveRuns().length,
|
|
2256
|
-
staleQuery: true,
|
|
2257
|
-
}, "Ignoring replaced Claude query pump completion");
|
|
2258
|
-
await this.awaitWithTimeout(q.return?.(), "query pump return on stale done");
|
|
2259
|
-
continue;
|
|
2260
|
-
}
|
|
2261
|
-
this.logger.trace({
|
|
2262
|
-
claudeSessionId: this.claudeSessionId,
|
|
2263
|
-
activeRunCount: this.runTracker.listActiveRuns().length,
|
|
2264
|
-
}, "Claude query pump next() returned done");
|
|
2265
|
-
this.input?.end();
|
|
2266
|
-
await this.awaitWithTimeout(q.return?.(), "query pump return on done");
|
|
2267
|
-
if (this.query === q) {
|
|
2268
|
-
this.query = null;
|
|
2269
|
-
this.input = null;
|
|
1835
|
+
let activeQuery;
|
|
1836
|
+
try {
|
|
1837
|
+
activeQuery = await this.ensureQuery();
|
|
1838
|
+
}
|
|
1839
|
+
catch (error) {
|
|
1840
|
+
this.logger.trace({ err: error }, "Failed to initialize Claude query pump");
|
|
1841
|
+
this.failActiveTurns(error instanceof Error ? error.message : "Claude stream failed");
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
let consecutiveInterruptAbortRecoveries = 0;
|
|
1845
|
+
try {
|
|
1846
|
+
while (!this.closed && this.query === activeQuery) {
|
|
1847
|
+
try {
|
|
1848
|
+
for await (const message of activeQuery) {
|
|
1849
|
+
consecutiveInterruptAbortRecoveries = 0;
|
|
1850
|
+
if (await this.handleMissingResumedConversation(message, activeQuery)) {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
this.routeSdkMessageFromPump(message);
|
|
1854
|
+
}
|
|
1855
|
+
if (!this.closed && this.query === activeQuery) {
|
|
1856
|
+
this.failActiveTurns("Claude stream ended before terminal result");
|
|
1857
|
+
}
|
|
1858
|
+
return;
|
|
2270
1859
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
this.
|
|
1860
|
+
catch (error) {
|
|
1861
|
+
if (!this.closed &&
|
|
1862
|
+
this.query === activeQuery &&
|
|
1863
|
+
this.shouldRecoverInterruptedQueryAbort(error, consecutiveInterruptAbortRecoveries)) {
|
|
1864
|
+
consecutiveInterruptAbortRecoveries += 1;
|
|
1865
|
+
this.logger.debug({ recoveries: consecutiveInterruptAbortRecoveries }, "Recovering Claude query pump after interrupt abort");
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
if (!this.closed && this.query === activeQuery) {
|
|
1869
|
+
this.failActiveTurns(error instanceof Error ? error.message : "Claude stream failed");
|
|
2275
1870
|
}
|
|
1871
|
+
return;
|
|
2276
1872
|
}
|
|
2277
|
-
await this.waitForLiveHistoryPoll();
|
|
2278
|
-
continue;
|
|
2279
|
-
}
|
|
2280
|
-
const sdkMessage = next.value;
|
|
2281
|
-
if (!sdkMessage) {
|
|
2282
|
-
continue;
|
|
2283
|
-
}
|
|
2284
|
-
if (this.query !== q) {
|
|
2285
|
-
this.logger.trace({
|
|
2286
|
-
claudeSessionId: this.claudeSessionId,
|
|
2287
|
-
messageType: sdkMessage.type,
|
|
2288
|
-
staleQuery: true,
|
|
2289
|
-
}, "Ignoring Claude SDK message from replaced query");
|
|
2290
|
-
await this.awaitWithTimeout(q.return?.(), "query pump return on stale message");
|
|
2291
|
-
continue;
|
|
2292
1873
|
}
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
this.
|
|
2298
|
-
}
|
|
2299
|
-
catch (error) {
|
|
2300
|
-
this.logger.trace({ err: error }, "Failed to route Claude SDK message from query pump");
|
|
1874
|
+
}
|
|
1875
|
+
finally {
|
|
1876
|
+
if (this.query === activeQuery) {
|
|
1877
|
+
this.query = null;
|
|
1878
|
+
this.input = null;
|
|
2301
1879
|
}
|
|
2302
1880
|
}
|
|
2303
1881
|
}
|
|
2304
1882
|
routeSdkMessageFromPump(message) {
|
|
2305
|
-
|
|
1883
|
+
const routeToForeground = Boolean(this.activeForegroundTurn);
|
|
1884
|
+
const assistantishMessage = message.type === "assistant" ||
|
|
1885
|
+
message.type === "stream_event" ||
|
|
1886
|
+
message.type === "tool_progress";
|
|
1887
|
+
if (!routeToForeground && assistantishMessage) {
|
|
1888
|
+
this.startAutonomousTurn();
|
|
1889
|
+
}
|
|
1890
|
+
if (!routeToForeground && !this.autonomousTurn && message.type === "result") {
|
|
2306
1891
|
return;
|
|
2307
1892
|
}
|
|
1893
|
+
const turnId = this.activeForegroundTurn?.id ?? this.autonomousTurn?.id ?? null;
|
|
2308
1894
|
const identifiers = readEventIdentifiers(message);
|
|
2309
|
-
const metadataOnly = isMetadataOnlySdkMessage(message);
|
|
2310
|
-
const route = this.routeMessage({
|
|
2311
|
-
message,
|
|
2312
|
-
identifiers,
|
|
2313
|
-
metadataOnly,
|
|
2314
|
-
});
|
|
2315
|
-
const suppressTerminalEvents = this.shouldSuppressReplayResultTerminal({
|
|
2316
|
-
run: route.run,
|
|
2317
|
-
message,
|
|
2318
|
-
});
|
|
2319
1895
|
this.logger.trace({
|
|
2320
1896
|
claudeSessionId: this.claudeSessionId,
|
|
2321
1897
|
messageType: message.type,
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
runOwner: route.run?.owner ?? null,
|
|
2325
|
-
suppressTerminalEvents,
|
|
2326
|
-
metadataOnly,
|
|
1898
|
+
routedTo: routeToForeground ? "foreground_queue" : "live_queue",
|
|
1899
|
+
turnId,
|
|
2327
1900
|
}, "Claude query pump routed SDK message");
|
|
2328
|
-
if (route.run) {
|
|
2329
|
-
this.transitionTurnStateFromActiveRuns(`routed via ${route.reason}`);
|
|
2330
|
-
this.runTracker.bindIdentifiers(route.run, identifiers);
|
|
2331
|
-
if (!suppressTerminalEvents) {
|
|
2332
|
-
this.updateRunLifecycleForMessage(route.run, message, identifiers);
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
1901
|
const messageEvents = this.translateMessageToEvents(message, {
|
|
2336
1902
|
suppressAssistantText: true,
|
|
2337
1903
|
suppressReasoning: true,
|
|
2338
|
-
suppressTerminalEvents,
|
|
2339
1904
|
});
|
|
2340
|
-
const
|
|
1905
|
+
const assistantTimelineEvents = this.timelineAssembler
|
|
1906
|
+
.consume({
|
|
2341
1907
|
message,
|
|
2342
|
-
runId:
|
|
1908
|
+
runId: turnId,
|
|
2343
1909
|
messageIdHint: identifiers.messageId,
|
|
2344
|
-
})
|
|
2345
|
-
|
|
1910
|
+
})
|
|
1911
|
+
.map((item) => ({
|
|
2346
1912
|
type: "timeline",
|
|
2347
1913
|
item,
|
|
2348
1914
|
provider: "claude",
|
|
@@ -2351,16 +1917,26 @@ class ClaudeAgentSession {
|
|
|
2351
1917
|
if (events.length === 0) {
|
|
2352
1918
|
return;
|
|
2353
1919
|
}
|
|
2354
|
-
if (
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
this.
|
|
1920
|
+
if (this.pendingInterruptAbort &&
|
|
1921
|
+
message.type === "result" &&
|
|
1922
|
+
events.some((event) => event.type === "turn_completed" || event.type === "turn_failed") &&
|
|
1923
|
+
(!this.activeForegroundTurn || !this.activeForegroundTurn.hasVisibleActivity)) {
|
|
1924
|
+
this.pendingInterruptAbort = false;
|
|
1925
|
+
this.logger.debug("Suppressing stale Claude interrupt terminal result");
|
|
2359
1926
|
return;
|
|
2360
1927
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
1928
|
+
if (this.activeForegroundTurn &&
|
|
1929
|
+
events.some((event) => event.type === "timeline" ||
|
|
1930
|
+
event.type === "permission_requested" ||
|
|
1931
|
+
event.type === "permission_resolved")) {
|
|
1932
|
+
this.activeForegroundTurn.hasVisibleActivity = true;
|
|
1933
|
+
this.pendingInterruptAbort = false;
|
|
2363
1934
|
}
|
|
1935
|
+
if (routeToForeground) {
|
|
1936
|
+
this.dispatchForegroundEvents(events);
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
this.dispatchLiveEvents(events);
|
|
2364
1940
|
}
|
|
2365
1941
|
async handleMissingResumedConversation(message, query) {
|
|
2366
1942
|
const staleResumeError = this.readMissingResumedConversationError(message);
|
|
@@ -2371,10 +1947,7 @@ class ClaudeAgentSession {
|
|
|
2371
1947
|
claudeSessionId: this.claudeSessionId,
|
|
2372
1948
|
error: staleResumeError,
|
|
2373
1949
|
}, "Claude resumed session no longer exists; invalidating persisted session");
|
|
2374
|
-
|
|
2375
|
-
this.failRun(run, staleResumeError);
|
|
2376
|
-
}
|
|
2377
|
-
this.transitionTurnStateFromActiveRuns("missing resumed conversation");
|
|
1950
|
+
this.failActiveTurns(staleResumeError);
|
|
2378
1951
|
this.input?.end();
|
|
2379
1952
|
await this.awaitWithTimeout(query.return?.(), "query pump return on missing resumed conversation");
|
|
2380
1953
|
if (this.query === query) {
|
|
@@ -2385,373 +1958,36 @@ class ClaudeAgentSession {
|
|
|
2385
1958
|
this.persistence = null;
|
|
2386
1959
|
this.persistedHistory = [];
|
|
2387
1960
|
this.historyPending = false;
|
|
1961
|
+
this.historyOffsetSessionId = null;
|
|
1962
|
+
this.historyReadOffsetBytes = 0;
|
|
1963
|
+
this.historyLineFragment = "";
|
|
2388
1964
|
this.cachedRuntimeInfo = null;
|
|
2389
1965
|
this.queryRestartNeeded = false;
|
|
1966
|
+
this.autonomousTurn = null;
|
|
1967
|
+
this.activeForegroundTurn = null;
|
|
1968
|
+
this.syncTurnState("missing resumed conversation");
|
|
2390
1969
|
return true;
|
|
2391
1970
|
}
|
|
2392
|
-
shouldSuppressReplayResultTerminal(input) {
|
|
2393
|
-
const { run, message } = input;
|
|
2394
|
-
if (!run || run.owner !== "foreground" || message.type !== "result") {
|
|
2395
|
-
return false;
|
|
2396
|
-
}
|
|
2397
|
-
if (run.promptReplaySeen) {
|
|
2398
|
-
return false;
|
|
2399
|
-
}
|
|
2400
|
-
if (run.state === "streaming" || run.state === "finalizing") {
|
|
2401
|
-
return false;
|
|
2402
|
-
}
|
|
2403
|
-
const resultSubtype = "subtype" in message && typeof message.subtype === "string"
|
|
2404
|
-
? message.subtype
|
|
2405
|
-
: null;
|
|
2406
|
-
// Pre-replay success results are stale in practice (leftover from an
|
|
2407
|
-
// earlier query segment) and must not end the current foreground run.
|
|
2408
|
-
if (resultSubtype === "success") {
|
|
2409
|
-
this.logger.trace({
|
|
2410
|
-
runId: run.id,
|
|
2411
|
-
runOwner: run.owner,
|
|
2412
|
-
runState: run.state,
|
|
2413
|
-
promptReplaySeen: run.promptReplaySeen,
|
|
2414
|
-
resultSubtype,
|
|
2415
|
-
}, "Suppressing pre-replay foreground success result terminal event");
|
|
2416
|
-
return true;
|
|
2417
|
-
}
|
|
2418
|
-
// For non-success results, keep the metadata-churn guard to avoid
|
|
2419
|
-
// suppressing legitimate hard failures.
|
|
2420
|
-
return this.preReplayMetadataSeen;
|
|
2421
|
-
}
|
|
2422
|
-
dispatchMetadataEvents(events) {
|
|
2423
|
-
for (const event of events) {
|
|
2424
|
-
this.pushEvent(event);
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
updateRunLifecycleForMessage(run, message, identifiers) {
|
|
2428
|
-
const previousState = run.state;
|
|
2429
|
-
if (message.type === "user" &&
|
|
2430
|
-
identifiers.messageId &&
|
|
2431
|
-
run.messageIds.has(identifiers.messageId)) {
|
|
2432
|
-
run.promptReplaySeen = true;
|
|
2433
|
-
this.preReplayMetadataSeen = false;
|
|
2434
|
-
}
|
|
2435
|
-
if (run.state === "queued") {
|
|
2436
|
-
this.runTracker.transition(run, "awaiting_response");
|
|
2437
|
-
}
|
|
2438
|
-
if (message.type === "assistant" ||
|
|
2439
|
-
message.type === "stream_event" ||
|
|
2440
|
-
message.type === "tool_progress") {
|
|
2441
|
-
this.runTracker.transition(run, "streaming");
|
|
2442
|
-
return;
|
|
2443
|
-
}
|
|
2444
|
-
if (message.type === "result") {
|
|
2445
|
-
this.runTracker.transition(run, "finalizing");
|
|
2446
|
-
}
|
|
2447
|
-
else {
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2450
|
-
if (run.state !== previousState) {
|
|
2451
|
-
this.logger.trace({
|
|
2452
|
-
runId: run.id,
|
|
2453
|
-
owner: run.owner,
|
|
2454
|
-
messageType: message.type,
|
|
2455
|
-
previousState,
|
|
2456
|
-
nextState: run.state,
|
|
2457
|
-
taskId: identifiers.taskId,
|
|
2458
|
-
parentMessageId: identifiers.parentMessageId,
|
|
2459
|
-
messageId: identifiers.messageId,
|
|
2460
|
-
}, "Updated Claude run lifecycle from SDK message");
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
shouldSuppressLocalReplayActivity(message) {
|
|
2464
|
-
const localReplay = this.isLocalReplayUserMessage(message);
|
|
2465
|
-
if (!this.activeForegroundTurn && localReplay) {
|
|
2466
|
-
this.suppressLocalReplayActivity = true;
|
|
2467
|
-
this.logger.debug({ uuid: message.uuid }, "Suppressing local replay user message from live pump");
|
|
2468
|
-
return true;
|
|
2469
|
-
}
|
|
2470
|
-
if (!this.suppressLocalReplayActivity) {
|
|
2471
|
-
return false;
|
|
2472
|
-
}
|
|
2473
|
-
// Suppress only replay scaffolding. Do not suppress autonomous
|
|
2474
|
-
// assistant/result events; otherwise task-notification replies can be dropped.
|
|
2475
|
-
if (localReplay) {
|
|
2476
|
-
return true;
|
|
2477
|
-
}
|
|
2478
|
-
if (message.type === "system") {
|
|
2479
|
-
return true;
|
|
2480
|
-
}
|
|
2481
|
-
const identifiers = readEventIdentifiers(message);
|
|
2482
|
-
const hasIdentifiers = Boolean(identifiers.taskId || identifiers.parentMessageId || identifiers.messageId);
|
|
2483
|
-
if (message.type !== "user" && !hasIdentifiers) {
|
|
2484
|
-
if (this.pendingAutonomousWakeReservations > 0) {
|
|
2485
|
-
this.suppressLocalReplayActivity = false;
|
|
2486
|
-
return false;
|
|
2487
|
-
}
|
|
2488
|
-
return true;
|
|
2489
|
-
}
|
|
2490
|
-
if (message.type === "user") {
|
|
2491
|
-
this.suppressLocalReplayActivity = false;
|
|
2492
|
-
return false;
|
|
2493
|
-
}
|
|
2494
|
-
this.suppressLocalReplayActivity = false;
|
|
2495
|
-
return false;
|
|
2496
|
-
}
|
|
2497
|
-
isLocalReplayUserMessage(message) {
|
|
2498
|
-
if (message.type !== "user") {
|
|
2499
|
-
return false;
|
|
2500
|
-
}
|
|
2501
|
-
const uuid = readTrimmedString(message.uuid);
|
|
2502
|
-
if (!uuid) {
|
|
2503
|
-
return false;
|
|
2504
|
-
}
|
|
2505
|
-
return this.localUserMessageIds.has(uuid);
|
|
2506
|
-
}
|
|
2507
1971
|
async interruptActiveTurn() {
|
|
2508
1972
|
const queryToInterrupt = this.query;
|
|
2509
1973
|
if (!queryToInterrupt || typeof queryToInterrupt.interrupt !== "function") {
|
|
2510
1974
|
this.logger.trace("interruptActiveTurn: no query to interrupt");
|
|
2511
1975
|
return;
|
|
2512
1976
|
}
|
|
1977
|
+
this.pendingInterruptAbort = true;
|
|
2513
1978
|
try {
|
|
2514
|
-
this.logger.trace("interruptActiveTurn: calling query.interrupt()...");
|
|
2515
1979
|
await this.awaitWithTimeout(queryToInterrupt.interrupt(), "interruptActiveTurn query.interrupt()");
|
|
2516
|
-
this.input?.end();
|
|
2517
|
-
this.logger.trace("interruptActiveTurn: calling query.return()...");
|
|
2518
|
-
await this.awaitWithTimeout(queryToInterrupt.return?.(), "interruptActiveTurn query.return()");
|
|
2519
|
-
this.query = null;
|
|
2520
|
-
this.input = null;
|
|
2521
|
-
this.queryRestartNeeded = false;
|
|
2522
1980
|
}
|
|
2523
1981
|
catch (error) {
|
|
2524
1982
|
this.logger.warn({ err: error }, "Failed to interrupt active turn");
|
|
2525
|
-
this.input?.end();
|
|
2526
|
-
if (this.query === queryToInterrupt) {
|
|
2527
|
-
this.query = null;
|
|
2528
|
-
this.input = null;
|
|
2529
|
-
}
|
|
2530
|
-
// Try to force-close the iterator to unblock the pump's q.next() call.
|
|
2531
|
-
this.awaitWithTimeout(queryToInterrupt.return?.(), "interruptActiveTurn force return after failure").catch(() => { });
|
|
2532
|
-
// Disown the current pump and start a fresh one immediately so
|
|
2533
|
-
// autonomous wakes are not lost while waiting for the next user turn.
|
|
2534
|
-
this.queryPumpPromise = null;
|
|
2535
|
-
this.startQueryPump();
|
|
2536
|
-
}
|
|
2537
|
-
}
|
|
2538
|
-
handleSidechainMessage(message, parentToolUseId) {
|
|
2539
|
-
const state = this.activeSidechains.get(parentToolUseId) ??
|
|
2540
|
-
{
|
|
2541
|
-
actions: [],
|
|
2542
|
-
actionKeys: [],
|
|
2543
|
-
nextActionIndex: 1,
|
|
2544
|
-
actionIndexByKey: new Map(),
|
|
2545
|
-
};
|
|
2546
|
-
this.activeSidechains.set(parentToolUseId, state);
|
|
2547
|
-
const contextUpdated = this.updateSubAgentContextFromTaskInput(state, parentToolUseId);
|
|
2548
|
-
const actionCandidates = this.extractSubAgentActionCandidates(message);
|
|
2549
|
-
let actionUpdated = false;
|
|
2550
|
-
for (const action of actionCandidates) {
|
|
2551
|
-
if (this.appendSubAgentAction(state, action)) {
|
|
2552
|
-
actionUpdated = true;
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
if (!contextUpdated && !actionUpdated) {
|
|
2556
|
-
return [];
|
|
2557
|
-
}
|
|
2558
|
-
const toolCall = mapClaudeRunningToolCall({
|
|
2559
|
-
name: "Task",
|
|
2560
|
-
callId: parentToolUseId,
|
|
2561
|
-
input: null,
|
|
2562
|
-
output: null,
|
|
2563
|
-
});
|
|
2564
|
-
if (!toolCall) {
|
|
2565
|
-
return [];
|
|
2566
|
-
}
|
|
2567
|
-
const detail = {
|
|
2568
|
-
type: "sub_agent",
|
|
2569
|
-
...(state.subAgentType ? { subAgentType: state.subAgentType } : {}),
|
|
2570
|
-
...(state.description ? { description: state.description } : {}),
|
|
2571
|
-
log: state.actions
|
|
2572
|
-
.map((action) => action.summary
|
|
2573
|
-
? `[${action.toolName}] ${action.summary}`
|
|
2574
|
-
: `[${action.toolName}]`)
|
|
2575
|
-
.join("\n"),
|
|
2576
|
-
actions: state.actions.map((action) => ({
|
|
2577
|
-
index: action.index,
|
|
2578
|
-
toolName: action.toolName,
|
|
2579
|
-
...(action.summary ? { summary: action.summary } : {}),
|
|
2580
|
-
})),
|
|
2581
|
-
};
|
|
2582
|
-
return [
|
|
2583
|
-
{
|
|
2584
|
-
type: "timeline",
|
|
2585
|
-
item: {
|
|
2586
|
-
...toolCall,
|
|
2587
|
-
detail,
|
|
2588
|
-
},
|
|
2589
|
-
provider: "claude",
|
|
2590
|
-
},
|
|
2591
|
-
];
|
|
2592
|
-
}
|
|
2593
|
-
updateSubAgentContextFromTaskInput(state, parentToolUseId) {
|
|
2594
|
-
const taskInput = this.toolUseCache.get(parentToolUseId)?.input;
|
|
2595
|
-
const nextSubAgentType = this.normalizeSubAgentText(taskInput?.subagent_type);
|
|
2596
|
-
const nextDescription = this.normalizeSubAgentText(taskInput?.description);
|
|
2597
|
-
let changed = false;
|
|
2598
|
-
if (nextSubAgentType && nextSubAgentType !== state.subAgentType) {
|
|
2599
|
-
state.subAgentType = nextSubAgentType;
|
|
2600
|
-
changed = true;
|
|
2601
|
-
}
|
|
2602
|
-
if (nextDescription && nextDescription !== state.description) {
|
|
2603
|
-
state.description = nextDescription;
|
|
2604
|
-
changed = true;
|
|
2605
|
-
}
|
|
2606
|
-
return changed;
|
|
2607
|
-
}
|
|
2608
|
-
normalizeSubAgentText(value) {
|
|
2609
|
-
const normalized = readTrimmedString(value)?.replace(/\s+/g, " ");
|
|
2610
|
-
if (!normalized) {
|
|
2611
|
-
return undefined;
|
|
2612
|
-
}
|
|
2613
|
-
if (normalized.length <= MAX_SUB_AGENT_SUMMARY_CHARS) {
|
|
2614
|
-
return normalized;
|
|
2615
1983
|
}
|
|
2616
|
-
return `${normalized.slice(0, MAX_SUB_AGENT_SUMMARY_CHARS)}...`;
|
|
2617
|
-
}
|
|
2618
|
-
extractSubAgentActionCandidates(message) {
|
|
2619
|
-
if (message.type === "assistant") {
|
|
2620
|
-
const content = message.message?.content;
|
|
2621
|
-
if (!Array.isArray(content)) {
|
|
2622
|
-
return [];
|
|
2623
|
-
}
|
|
2624
|
-
const actions = [];
|
|
2625
|
-
for (const block of content) {
|
|
2626
|
-
if (!isClaudeContentChunk(block) ||
|
|
2627
|
-
!(block.type === "tool_use" ||
|
|
2628
|
-
block.type === "mcp_tool_use" ||
|
|
2629
|
-
block.type === "server_tool_use") ||
|
|
2630
|
-
typeof block.name !== "string") {
|
|
2631
|
-
continue;
|
|
2632
|
-
}
|
|
2633
|
-
const key = readTrimmedString(block.id) ??
|
|
2634
|
-
`assistant:${block.name}:${actions.length}`;
|
|
2635
|
-
actions.push({
|
|
2636
|
-
key,
|
|
2637
|
-
toolName: block.name,
|
|
2638
|
-
input: block.input ?? null,
|
|
2639
|
-
});
|
|
2640
|
-
}
|
|
2641
|
-
return actions;
|
|
2642
|
-
}
|
|
2643
|
-
if (message.type === "stream_event") {
|
|
2644
|
-
const event = message.event;
|
|
2645
|
-
if (event.type !== "content_block_start") {
|
|
2646
|
-
return [];
|
|
2647
|
-
}
|
|
2648
|
-
const block = isClaudeContentChunk(event.content_block)
|
|
2649
|
-
? event.content_block
|
|
2650
|
-
: null;
|
|
2651
|
-
if (!block ||
|
|
2652
|
-
!(block.type === "tool_use" ||
|
|
2653
|
-
block.type === "mcp_tool_use" ||
|
|
2654
|
-
block.type === "server_tool_use") ||
|
|
2655
|
-
typeof block.name !== "string") {
|
|
2656
|
-
return [];
|
|
2657
|
-
}
|
|
2658
|
-
const key = readTrimmedString(block.id) ??
|
|
2659
|
-
`stream:${block.name}:${typeof event.index === "number" ? event.index : 0}`;
|
|
2660
|
-
return [
|
|
2661
|
-
{
|
|
2662
|
-
key,
|
|
2663
|
-
toolName: block.name,
|
|
2664
|
-
input: block.input ?? null,
|
|
2665
|
-
},
|
|
2666
|
-
];
|
|
2667
|
-
}
|
|
2668
|
-
if (message.type === "tool_progress") {
|
|
2669
|
-
const toolName = readTrimmedString(message.tool_name);
|
|
2670
|
-
if (!toolName) {
|
|
2671
|
-
return [];
|
|
2672
|
-
}
|
|
2673
|
-
const key = readTrimmedString(message.tool_use_id) ?? `progress:${toolName}`;
|
|
2674
|
-
return [{ key, toolName, input: null }];
|
|
2675
|
-
}
|
|
2676
|
-
return [];
|
|
2677
|
-
}
|
|
2678
|
-
appendSubAgentAction(state, candidate) {
|
|
2679
|
-
const normalizedToolName = readTrimmedString(candidate.toolName);
|
|
2680
|
-
if (!normalizedToolName) {
|
|
2681
|
-
return false;
|
|
2682
|
-
}
|
|
2683
|
-
const summary = this.deriveSubAgentActionSummary(normalizedToolName, candidate.input);
|
|
2684
|
-
const existingIndex = state.actionIndexByKey.get(candidate.key);
|
|
2685
|
-
if (existingIndex !== undefined) {
|
|
2686
|
-
const existing = state.actions[existingIndex];
|
|
2687
|
-
if (!existing) {
|
|
2688
|
-
return false;
|
|
2689
|
-
}
|
|
2690
|
-
const nextSummary = existing.summary ?? summary;
|
|
2691
|
-
const unchanged = existing.toolName === normalizedToolName &&
|
|
2692
|
-
existing.summary === nextSummary;
|
|
2693
|
-
if (unchanged) {
|
|
2694
|
-
return false;
|
|
2695
|
-
}
|
|
2696
|
-
state.actions[existingIndex] = {
|
|
2697
|
-
...existing,
|
|
2698
|
-
toolName: normalizedToolName,
|
|
2699
|
-
...(nextSummary ? { summary: nextSummary } : {}),
|
|
2700
|
-
};
|
|
2701
|
-
return true;
|
|
2702
|
-
}
|
|
2703
|
-
const nextEntry = {
|
|
2704
|
-
index: state.nextActionIndex,
|
|
2705
|
-
toolName: normalizedToolName,
|
|
2706
|
-
...(summary ? { summary } : {}),
|
|
2707
|
-
};
|
|
2708
|
-
state.nextActionIndex += 1;
|
|
2709
|
-
state.actions.push(nextEntry);
|
|
2710
|
-
state.actionKeys.push(candidate.key);
|
|
2711
|
-
this.trimSubAgentTail(state);
|
|
2712
|
-
this.rebuildSubAgentActionIndex(state);
|
|
2713
|
-
return true;
|
|
2714
|
-
}
|
|
2715
|
-
trimSubAgentTail(state) {
|
|
2716
|
-
while (state.actions.length > MAX_SUB_AGENT_LOG_ENTRIES) {
|
|
2717
|
-
state.actions.shift();
|
|
2718
|
-
state.actionKeys.shift();
|
|
2719
|
-
}
|
|
2720
|
-
}
|
|
2721
|
-
rebuildSubAgentActionIndex(state) {
|
|
2722
|
-
state.actionIndexByKey.clear();
|
|
2723
|
-
for (let index = 0; index < state.actionKeys.length; index += 1) {
|
|
2724
|
-
const key = state.actionKeys[index];
|
|
2725
|
-
if (key) {
|
|
2726
|
-
state.actionIndexByKey.set(key, index);
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
deriveSubAgentActionSummary(toolName, input) {
|
|
2731
|
-
const runningToolCall = mapClaudeRunningToolCall({
|
|
2732
|
-
name: toolName,
|
|
2733
|
-
callId: `sub-agent-summary-${toolName}`,
|
|
2734
|
-
input,
|
|
2735
|
-
output: null,
|
|
2736
|
-
});
|
|
2737
|
-
if (!runningToolCall) {
|
|
2738
|
-
return undefined;
|
|
2739
|
-
}
|
|
2740
|
-
const display = buildToolCallDisplayModel({
|
|
2741
|
-
name: runningToolCall.name,
|
|
2742
|
-
status: runningToolCall.status,
|
|
2743
|
-
error: runningToolCall.error,
|
|
2744
|
-
detail: runningToolCall.detail,
|
|
2745
|
-
metadata: runningToolCall.metadata,
|
|
2746
|
-
});
|
|
2747
|
-
return this.normalizeSubAgentText(display.summary);
|
|
2748
1984
|
}
|
|
2749
1985
|
translateMessageToEvents(message, options) {
|
|
2750
1986
|
const parentToolUseId = "parent_tool_use_id" in message
|
|
2751
1987
|
? message.parent_tool_use_id
|
|
2752
1988
|
: null;
|
|
2753
1989
|
if (parentToolUseId) {
|
|
2754
|
-
return this.
|
|
1990
|
+
return this.sidechainTracker.handleMessage(message, parentToolUseId);
|
|
2755
1991
|
}
|
|
2756
1992
|
const events = [];
|
|
2757
1993
|
const fallbackThreadSessionId = this.captureSessionIdFromMessage(message);
|
|
@@ -2817,9 +2053,7 @@ class ClaudeAgentSession {
|
|
|
2817
2053
|
this.compacting = false;
|
|
2818
2054
|
break;
|
|
2819
2055
|
}
|
|
2820
|
-
const messageId = typeof message.uuid === "string" && message.uuid.length > 0
|
|
2821
|
-
? message.uuid
|
|
2822
|
-
: undefined;
|
|
2056
|
+
const messageId = typeof message.uuid === "string" && message.uuid.length > 0 ? message.uuid : undefined;
|
|
2823
2057
|
this.rememberUserMessageId(messageId);
|
|
2824
2058
|
const content = message.message?.content;
|
|
2825
2059
|
const taskNotificationItem = mapTaskNotificationUserContentToToolCall({
|
|
@@ -2835,19 +2069,22 @@ class ClaudeAgentSession {
|
|
|
2835
2069
|
break;
|
|
2836
2070
|
}
|
|
2837
2071
|
if (typeof content === "string" && content.length > 0) {
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2072
|
+
if (!isClaudeTranscriptNoiseText(content)) {
|
|
2073
|
+
events.push({
|
|
2074
|
+
type: "timeline",
|
|
2075
|
+
item: {
|
|
2076
|
+
type: "user_message",
|
|
2077
|
+
text: content,
|
|
2078
|
+
...(messageId ? { messageId } : {}),
|
|
2079
|
+
},
|
|
2080
|
+
provider: "claude",
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2848
2083
|
}
|
|
2849
2084
|
else if (Array.isArray(content)) {
|
|
2850
|
-
const timelineItems = this.mapBlocksToTimeline(content
|
|
2085
|
+
const timelineItems = this.mapBlocksToTimeline(content, {
|
|
2086
|
+
textMessageType: "user_message",
|
|
2087
|
+
});
|
|
2851
2088
|
for (const item of timelineItems) {
|
|
2852
2089
|
if (item.type === "user_message" && messageId && !item.messageId) {
|
|
2853
2090
|
events.push({
|
|
@@ -2883,9 +2120,6 @@ class ClaudeAgentSession {
|
|
|
2883
2120
|
break;
|
|
2884
2121
|
}
|
|
2885
2122
|
case "result": {
|
|
2886
|
-
if (options?.suppressTerminalEvents) {
|
|
2887
|
-
break;
|
|
2888
|
-
}
|
|
2889
2123
|
const usage = this.convertUsage(message);
|
|
2890
2124
|
if (message.subtype === "success") {
|
|
2891
2125
|
events.push({ type: "turn_completed", provider: "claude", usage });
|
|
@@ -2947,18 +2181,14 @@ class ClaudeAgentSession {
|
|
|
2947
2181
|
const existingSessionId = this.claudeSessionId;
|
|
2948
2182
|
let threadStartedSessionId = null;
|
|
2949
2183
|
if (existingSessionId === null) {
|
|
2950
|
-
// First time setting session ID (empty → filled) - this is expected
|
|
2951
2184
|
this.claudeSessionId = newSessionId;
|
|
2952
2185
|
threadStartedSessionId = newSessionId;
|
|
2953
2186
|
this.logger.debug({ sessionId: newSessionId }, "Claude session ID set for the first time");
|
|
2954
2187
|
}
|
|
2955
2188
|
else if (existingSessionId === newSessionId) {
|
|
2956
|
-
// Same session ID - no-op, but log for visibility
|
|
2957
2189
|
this.logger.debug({ sessionId: newSessionId }, "Claude session ID unchanged (same value)");
|
|
2958
2190
|
}
|
|
2959
2191
|
else {
|
|
2960
|
-
// CRITICAL: Session ID is being overwritten with a different value
|
|
2961
|
-
// This should NEVER happen and indicates a serious bug
|
|
2962
2192
|
throw new Error(`CRITICAL: Claude session ID overwrite detected! ` +
|
|
2963
2193
|
`Existing: ${existingSessionId}, New: ${newSessionId}. ` +
|
|
2964
2194
|
`This indicates a session identity corruption bug.`);
|
|
@@ -2966,7 +2196,6 @@ class ClaudeAgentSession {
|
|
|
2966
2196
|
this.availableModes = DEFAULT_MODES;
|
|
2967
2197
|
this.currentMode = message.permissionMode;
|
|
2968
2198
|
this.persistence = null;
|
|
2969
|
-
// Capture actual model from SDK init message (not just the configured model)
|
|
2970
2199
|
if (message.model) {
|
|
2971
2200
|
const normalizedModel = normalizeClaudeRuntimeModelId({
|
|
2972
2201
|
runtimeModelId: message.model,
|
|
@@ -2977,7 +2206,6 @@ class ClaudeAgentSession {
|
|
|
2977
2206
|
});
|
|
2978
2207
|
this.logger.debug({ model: message.model, normalizedModel }, "Captured model from SDK init");
|
|
2979
2208
|
this.lastOptionsModel = normalizedModel;
|
|
2980
|
-
// Invalidate cached runtime info so it picks up the new model
|
|
2981
2209
|
this.cachedRuntimeInfo = null;
|
|
2982
2210
|
}
|
|
2983
2211
|
return threadStartedSessionId;
|
|
@@ -3030,7 +2258,7 @@ class ClaudeAgentSession {
|
|
|
3030
2258
|
}
|
|
3031
2259
|
}
|
|
3032
2260
|
this.toolUseCache.clear();
|
|
3033
|
-
this.
|
|
2261
|
+
this.sidechainTracker.clear();
|
|
3034
2262
|
}
|
|
3035
2263
|
pushToolCall(item, target) {
|
|
3036
2264
|
if (!item) {
|
|
@@ -3045,15 +2273,8 @@ class ClaudeAgentSession {
|
|
|
3045
2273
|
pushEvent(event) {
|
|
3046
2274
|
const foregroundTurn = this.activeForegroundTurn;
|
|
3047
2275
|
if (foregroundTurn) {
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
run.owner === "foreground" &&
|
|
3051
|
-
run.queue === foregroundTurn.queue &&
|
|
3052
|
-
this.runTracker.isRunActive(run)) {
|
|
3053
|
-
foregroundTurn.queue.push(event);
|
|
3054
|
-
return;
|
|
3055
|
-
}
|
|
3056
|
-
this.activeForegroundTurn = null;
|
|
2276
|
+
foregroundTurn.queue.push(event);
|
|
2277
|
+
return;
|
|
3057
2278
|
}
|
|
3058
2279
|
this.liveEventQueue.push(event);
|
|
3059
2280
|
}
|
|
@@ -3071,47 +2292,125 @@ class ClaudeAgentSession {
|
|
|
3071
2292
|
this.pendingPermissions.delete(id);
|
|
3072
2293
|
}
|
|
3073
2294
|
}
|
|
3074
|
-
|
|
3075
|
-
return new Promise((resolve) => setTimeout(resolve, 250));
|
|
3076
|
-
}
|
|
3077
|
-
loadPersistedHistory(sessionId) {
|
|
2295
|
+
loadPersistedHistory(sessionId, options) {
|
|
3078
2296
|
try {
|
|
3079
2297
|
const historyPath = this.resolveHistoryPath(sessionId);
|
|
3080
2298
|
if (!historyPath || !fs.existsSync(historyPath)) {
|
|
3081
2299
|
return;
|
|
3082
2300
|
}
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
if (!trimmed)
|
|
3088
|
-
continue;
|
|
3089
|
-
try {
|
|
3090
|
-
const entry = JSON.parse(trimmed);
|
|
3091
|
-
if (entry.isSidechain) {
|
|
3092
|
-
continue;
|
|
3093
|
-
}
|
|
3094
|
-
if (entry.type === "user" && typeof entry.uuid === "string") {
|
|
3095
|
-
this.rememberUserMessageId(entry.uuid);
|
|
3096
|
-
}
|
|
3097
|
-
const items = this.convertHistoryEntry(entry);
|
|
3098
|
-
if (items.length > 0) {
|
|
3099
|
-
timeline.push(...items);
|
|
3100
|
-
}
|
|
3101
|
-
}
|
|
3102
|
-
catch (error) {
|
|
3103
|
-
// ignore malformed history line
|
|
3104
|
-
}
|
|
2301
|
+
if (this.historyOffsetSessionId !== sessionId) {
|
|
2302
|
+
this.historyOffsetSessionId = sessionId;
|
|
2303
|
+
this.historyReadOffsetBytes = 0;
|
|
2304
|
+
this.historyLineFragment = "";
|
|
3105
2305
|
}
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
this.
|
|
2306
|
+
const content = fs.readFileSync(historyPath);
|
|
2307
|
+
if (content.byteLength < this.historyReadOffsetBytes) {
|
|
2308
|
+
this.historyReadOffsetBytes = 0;
|
|
2309
|
+
this.historyLineFragment = "";
|
|
2310
|
+
}
|
|
2311
|
+
if (content.byteLength === this.historyReadOffsetBytes) {
|
|
2312
|
+
return;
|
|
3109
2313
|
}
|
|
2314
|
+
const unreadChunk = content.subarray(this.historyReadOffsetBytes).toString("utf8");
|
|
2315
|
+
this.historyReadOffsetBytes = content.byteLength;
|
|
2316
|
+
this.ingestPersistedHistoryChunk(unreadChunk, {
|
|
2317
|
+
dispatchLive: options?.dispatchLive ?? false,
|
|
2318
|
+
});
|
|
3110
2319
|
}
|
|
3111
2320
|
catch (error) {
|
|
3112
2321
|
// ignore history load failures
|
|
3113
2322
|
}
|
|
3114
2323
|
}
|
|
2324
|
+
ingestPersistedHistoryChunk(chunk, options) {
|
|
2325
|
+
if (!chunk) {
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
const combined = `${this.historyLineFragment}${chunk}`;
|
|
2329
|
+
this.historyLineFragment = "";
|
|
2330
|
+
const lines = combined.split(/\r?\n/);
|
|
2331
|
+
const trailing = lines.pop() ?? "";
|
|
2332
|
+
const timeline = [];
|
|
2333
|
+
for (const line of lines) {
|
|
2334
|
+
this.ingestPersistedHistoryLine(line, {
|
|
2335
|
+
dispatchLive: options.dispatchLive,
|
|
2336
|
+
timeline,
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
if (trailing.trim().length > 0) {
|
|
2340
|
+
const handled = this.ingestPersistedHistoryLine(trailing, {
|
|
2341
|
+
dispatchLive: options.dispatchLive,
|
|
2342
|
+
timeline,
|
|
2343
|
+
});
|
|
2344
|
+
if (!handled) {
|
|
2345
|
+
this.historyLineFragment = trailing;
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
if (!options.dispatchLive && timeline.length > 0) {
|
|
2349
|
+
this.persistedHistory = [...this.persistedHistory, ...timeline];
|
|
2350
|
+
this.historyPending = true;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
ingestPersistedHistoryLine(line, options) {
|
|
2354
|
+
const trimmed = line.trim();
|
|
2355
|
+
if (!trimmed) {
|
|
2356
|
+
return true;
|
|
2357
|
+
}
|
|
2358
|
+
let entry;
|
|
2359
|
+
try {
|
|
2360
|
+
entry = JSON.parse(trimmed);
|
|
2361
|
+
}
|
|
2362
|
+
catch {
|
|
2363
|
+
return false;
|
|
2364
|
+
}
|
|
2365
|
+
if (entry.isSidechain) {
|
|
2366
|
+
return true;
|
|
2367
|
+
}
|
|
2368
|
+
if (entry.type === "user" && typeof entry.uuid === "string") {
|
|
2369
|
+
this.rememberUserMessageId(entry.uuid);
|
|
2370
|
+
}
|
|
2371
|
+
if (options.dispatchLive) {
|
|
2372
|
+
this.dispatchPersistedHistoryEntry(entry);
|
|
2373
|
+
return true;
|
|
2374
|
+
}
|
|
2375
|
+
const items = this.convertHistoryEntry(entry);
|
|
2376
|
+
if (items.length > 0) {
|
|
2377
|
+
options.timeline.push(...items);
|
|
2378
|
+
}
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
dispatchPersistedHistoryEntry(entry) {
|
|
2382
|
+
const liveMessage = this.normalizePersistedHistoryEntryToLiveMessage(entry);
|
|
2383
|
+
if (liveMessage) {
|
|
2384
|
+
this.routeSdkMessageFromPump(liveMessage);
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
const items = this.convertHistoryEntry(entry);
|
|
2388
|
+
for (const item of items) {
|
|
2389
|
+
this.pushEvent({
|
|
2390
|
+
type: "timeline",
|
|
2391
|
+
item,
|
|
2392
|
+
provider: "claude",
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
normalizePersistedHistoryEntryToLiveMessage(entry) {
|
|
2397
|
+
const taskNotificationMessage = coerceTaskNotificationHistoryRecordToSystemMessage(entry);
|
|
2398
|
+
if (taskNotificationMessage) {
|
|
2399
|
+
return taskNotificationMessage;
|
|
2400
|
+
}
|
|
2401
|
+
const type = readTrimmedString(entry.type);
|
|
2402
|
+
switch (type) {
|
|
2403
|
+
case "assistant":
|
|
2404
|
+
case "result":
|
|
2405
|
+
case "stream_event":
|
|
2406
|
+
case "system":
|
|
2407
|
+
case "tool_progress":
|
|
2408
|
+
case "user":
|
|
2409
|
+
return entry;
|
|
2410
|
+
default:
|
|
2411
|
+
return null;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
3115
2414
|
resolveHistoryPath(sessionId) {
|
|
3116
2415
|
const cwd = this.config.cwd;
|
|
3117
2416
|
if (!cwd)
|
|
@@ -3125,25 +2424,50 @@ class ClaudeAgentSession {
|
|
|
3125
2424
|
convertHistoryEntry(entry) {
|
|
3126
2425
|
return convertClaudeHistoryEntry(entry, (content) => this.mapBlocksToTimeline(content));
|
|
3127
2426
|
}
|
|
2427
|
+
// Maps Claude content blocks into AgentTimelineItems.
|
|
2428
|
+
//
|
|
2429
|
+
// textMessageType controls what type text blocks emit:
|
|
2430
|
+
// - "assistant_message" (default): one item per text block (streaming granularity)
|
|
2431
|
+
// - "user_message": coalesces all text blocks into a single user_message
|
|
2432
|
+
// (matches extractUserMessageText semantics: trim each block, join with "\n\n")
|
|
2433
|
+
//
|
|
2434
|
+
// suppressAssistantText only applies when textMessageType is "assistant_message" — user text
|
|
2435
|
+
// must never be suppressed since the TimelineAssembler only handles assistant text.
|
|
2436
|
+
//
|
|
2437
|
+
// NOTE: convertClaudeHistoryEntry uses extractUserMessageText directly instead of this function
|
|
2438
|
+
// for user entries. Both paths must produce equivalent user_message items.
|
|
3128
2439
|
mapBlocksToTimeline(content, options) {
|
|
3129
|
-
const
|
|
2440
|
+
const textMessageType = options?.textMessageType ?? "assistant_message";
|
|
2441
|
+
const suppressText = textMessageType === "assistant_message" && (options?.suppressAssistantText ?? false);
|
|
3130
2442
|
const suppressReasoning = options?.suppressReasoning ?? false;
|
|
3131
2443
|
if (typeof content === "string") {
|
|
3132
|
-
if (!content ||
|
|
2444
|
+
if (!content ||
|
|
2445
|
+
content === INTERRUPT_TOOL_USE_PLACEHOLDER ||
|
|
2446
|
+
isClaudeTranscriptNoiseText(content)) {
|
|
3133
2447
|
return [];
|
|
3134
2448
|
}
|
|
3135
|
-
if (
|
|
2449
|
+
if (suppressText) {
|
|
3136
2450
|
return [];
|
|
3137
2451
|
}
|
|
3138
|
-
return [{ type:
|
|
2452
|
+
return [{ type: textMessageType, text: content }];
|
|
3139
2453
|
}
|
|
3140
2454
|
const items = [];
|
|
2455
|
+
// User SDK entries can arrive as multiple text blocks, but Paseo treats them as one message.
|
|
2456
|
+
const userTextParts = [];
|
|
3141
2457
|
for (const block of content) {
|
|
3142
2458
|
switch (block.type) {
|
|
3143
2459
|
case "text":
|
|
3144
2460
|
case "text_delta":
|
|
3145
|
-
if (block.text &&
|
|
3146
|
-
|
|
2461
|
+
if (block.text &&
|
|
2462
|
+
block.text !== INTERRUPT_TOOL_USE_PLACEHOLDER &&
|
|
2463
|
+
!isClaudeTranscriptNoiseText(block.text)) {
|
|
2464
|
+
if (textMessageType === "user_message") {
|
|
2465
|
+
const trimmed = block.text.trim();
|
|
2466
|
+
if (trimmed) {
|
|
2467
|
+
userTextParts.push(trimmed);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
else if (!suppressText) {
|
|
3147
2471
|
items.push({ type: "assistant_message", text: block.text });
|
|
3148
2472
|
}
|
|
3149
2473
|
}
|
|
@@ -3176,6 +2500,12 @@ class ClaudeAgentSession {
|
|
|
3176
2500
|
break;
|
|
3177
2501
|
}
|
|
3178
2502
|
}
|
|
2503
|
+
if (textMessageType === "user_message" && userTextParts.length > 0) {
|
|
2504
|
+
items.unshift({
|
|
2505
|
+
type: "user_message",
|
|
2506
|
+
text: userTextParts.join("\n\n"),
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
3179
2509
|
return items;
|
|
3180
2510
|
}
|
|
3181
2511
|
handleToolUseStart(block, items) {
|
|
@@ -3200,7 +2530,7 @@ class ClaudeAgentSession {
|
|
|
3200
2530
|
const toolName = entry?.name ?? block.tool_name ?? "tool";
|
|
3201
2531
|
const callId = typeof block.tool_use_id === "string" && block.tool_use_id.length > 0
|
|
3202
2532
|
? block.tool_use_id
|
|
3203
|
-
: entry?.id ?? null;
|
|
2533
|
+
: (entry?.id ?? null);
|
|
3204
2534
|
// Extract output from block.content (SDK always returns content in string form)
|
|
3205
2535
|
const output = this.buildToolOutput(block, entry);
|
|
3206
2536
|
if (block.is_error) {
|
|
@@ -3222,7 +2552,7 @@ class ClaudeAgentSession {
|
|
|
3222
2552
|
}
|
|
3223
2553
|
if (typeof block.tool_use_id === "string") {
|
|
3224
2554
|
this.toolUseCache.delete(block.tool_use_id);
|
|
3225
|
-
this.
|
|
2555
|
+
this.sidechainTracker.delete(block.tool_use_id);
|
|
3226
2556
|
}
|
|
3227
2557
|
}
|
|
3228
2558
|
buildToolOutput(block, entry) {
|
|
@@ -3295,12 +2625,24 @@ class ClaudeAgentSession {
|
|
|
3295
2625
|
normalizedTool === "apply_diff") {
|
|
3296
2626
|
if (input && typeof input.file_path === "string") {
|
|
3297
2627
|
// Support both old_str/new_str and old_string/new_string parameter names
|
|
3298
|
-
const oldContent = typeof input.old_str === "string"
|
|
3299
|
-
|
|
2628
|
+
const oldContent = typeof input.old_str === "string"
|
|
2629
|
+
? input.old_str
|
|
2630
|
+
: typeof input.old_string === "string"
|
|
2631
|
+
? input.old_string
|
|
2632
|
+
: undefined;
|
|
2633
|
+
const newContent = typeof input.new_str === "string"
|
|
2634
|
+
? input.new_str
|
|
2635
|
+
: typeof input.new_string === "string"
|
|
2636
|
+
? input.new_string
|
|
2637
|
+
: undefined;
|
|
3300
2638
|
return {
|
|
3301
2639
|
type: "file_edit",
|
|
3302
2640
|
filePath: input.file_path,
|
|
3303
|
-
diff: typeof input.patch === "string"
|
|
2641
|
+
diff: typeof input.patch === "string"
|
|
2642
|
+
? input.patch
|
|
2643
|
+
: typeof input.diff === "string"
|
|
2644
|
+
? input.diff
|
|
2645
|
+
: undefined,
|
|
3304
2646
|
oldContent,
|
|
3305
2647
|
newContent,
|
|
3306
2648
|
};
|
|
@@ -3323,7 +2665,9 @@ class ClaudeAgentSession {
|
|
|
3323
2665
|
mapPartialEvent(event, options) {
|
|
3324
2666
|
if (event.type === "content_block_start") {
|
|
3325
2667
|
const block = isClaudeContentChunk(event.content_block) ? event.content_block : null;
|
|
3326
|
-
if (block?.type === "tool_use" &&
|
|
2668
|
+
if (block?.type === "tool_use" &&
|
|
2669
|
+
typeof event.index === "number" &&
|
|
2670
|
+
typeof block.id === "string") {
|
|
3327
2671
|
this.toolUseIndexToId.set(event.index, block.id);
|
|
3328
2672
|
this.toolUseInputBuffers.delete(block.id);
|
|
3329
2673
|
}
|
|
@@ -3388,7 +2732,9 @@ class ClaudeAgentSession {
|
|
|
3388
2732
|
else if (!existing.server) {
|
|
3389
2733
|
existing.server = existing.name;
|
|
3390
2734
|
}
|
|
3391
|
-
if (block.type === "tool_use" ||
|
|
2735
|
+
if (block.type === "tool_use" ||
|
|
2736
|
+
block.type === "mcp_tool_use" ||
|
|
2737
|
+
block.type === "server_tool_use") {
|
|
3392
2738
|
const input = this.normalizeToolInput(block.input);
|
|
3393
2739
|
if (input) {
|
|
3394
2740
|
this.applyToolInput(existing, input);
|
|
@@ -3407,16 +2753,19 @@ class ClaudeAgentSession {
|
|
|
3407
2753
|
}
|
|
3408
2754
|
const buffer = (this.toolUseInputBuffers.get(toolId) ?? "") + partialJson;
|
|
3409
2755
|
this.toolUseInputBuffers.set(toolId, buffer);
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
2756
|
+
const entry = this.toolUseCache.get(toolId);
|
|
2757
|
+
const parsed = parsePartialJsonObject(buffer);
|
|
2758
|
+
if (!entry || !parsed) {
|
|
2759
|
+
return;
|
|
3413
2760
|
}
|
|
3414
|
-
|
|
2761
|
+
const normalized = this.normalizeToolInput(parsed.value);
|
|
2762
|
+
if (!normalized) {
|
|
3415
2763
|
return;
|
|
3416
2764
|
}
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
2765
|
+
if (!parsed.complete && Object.keys(normalized).length === 0) {
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
if (this.areToolInputsEqual(entry.input ?? undefined, normalized)) {
|
|
3420
2769
|
return;
|
|
3421
2770
|
}
|
|
3422
2771
|
this.applyToolInput(entry, normalized);
|
|
@@ -3434,6 +2783,17 @@ class ClaudeAgentSession {
|
|
|
3434
2783
|
}
|
|
3435
2784
|
return input;
|
|
3436
2785
|
}
|
|
2786
|
+
areToolInputsEqual(left, right) {
|
|
2787
|
+
if (!left) {
|
|
2788
|
+
return false;
|
|
2789
|
+
}
|
|
2790
|
+
const leftKeys = Object.keys(left);
|
|
2791
|
+
const rightKeys = Object.keys(right);
|
|
2792
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
2793
|
+
return false;
|
|
2794
|
+
}
|
|
2795
|
+
return rightKeys.every((key) => left[key] === right[key]);
|
|
2796
|
+
}
|
|
3437
2797
|
applyToolInput(entry, input) {
|
|
3438
2798
|
entry.input = input;
|
|
3439
2799
|
if (this.isCommandTool(entry.name, input)) {
|
|
@@ -3450,7 +2810,10 @@ class ClaudeAgentSession {
|
|
|
3450
2810
|
}
|
|
3451
2811
|
isCommandTool(name, input) {
|
|
3452
2812
|
const normalized = name.toLowerCase();
|
|
3453
|
-
if (normalized.includes("bash") ||
|
|
2813
|
+
if (normalized.includes("bash") ||
|
|
2814
|
+
normalized.includes("shell") ||
|
|
2815
|
+
normalized.includes("terminal") ||
|
|
2816
|
+
normalized.includes("command")) {
|
|
3454
2817
|
return true;
|
|
3455
2818
|
}
|
|
3456
2819
|
if (typeof input.command === "string" || Array.isArray(input.command)) {
|
|
@@ -3494,7 +2857,10 @@ class ClaudeAgentSession {
|
|
|
3494
2857
|
const files = [];
|
|
3495
2858
|
for (const value of input.files) {
|
|
3496
2859
|
if (typeof value === "string" && value.length > 0) {
|
|
3497
|
-
files.push({
|
|
2860
|
+
files.push({
|
|
2861
|
+
path: this.relativizePath(value) ?? value,
|
|
2862
|
+
kind: this.detectFileKind(value),
|
|
2863
|
+
});
|
|
3498
2864
|
}
|
|
3499
2865
|
}
|
|
3500
2866
|
if (files.length > 0) {
|
|
@@ -3557,11 +2923,7 @@ function hasToolLikeBlock(block) {
|
|
|
3557
2923
|
return type.includes("tool");
|
|
3558
2924
|
}
|
|
3559
2925
|
function readCompactionMetadata(source) {
|
|
3560
|
-
const candidates = [
|
|
3561
|
-
source.compact_metadata,
|
|
3562
|
-
source.compactMetadata,
|
|
3563
|
-
source.compactionMetadata,
|
|
3564
|
-
];
|
|
2926
|
+
const candidates = [source.compact_metadata, source.compactMetadata, source.compactionMetadata];
|
|
3565
2927
|
for (const candidate of candidates) {
|
|
3566
2928
|
if (!candidate || typeof candidate !== "object") {
|
|
3567
2929
|
continue;
|
|
@@ -3587,18 +2949,18 @@ function normalizeHistoryBlocks(content) {
|
|
|
3587
2949
|
export function convertClaudeHistoryEntry(entry, mapBlocks) {
|
|
3588
2950
|
if (entry.type === "system" && entry.subtype === "compact_boundary") {
|
|
3589
2951
|
const compactMetadata = readCompactionMetadata(entry);
|
|
3590
|
-
return [
|
|
2952
|
+
return [
|
|
2953
|
+
{
|
|
3591
2954
|
type: "compaction",
|
|
3592
2955
|
status: "completed",
|
|
3593
2956
|
trigger: compactMetadata?.trigger === "manual" ? "manual" : "auto",
|
|
3594
2957
|
preTokens: compactMetadata?.preTokens,
|
|
3595
|
-
}
|
|
2958
|
+
},
|
|
2959
|
+
];
|
|
3596
2960
|
}
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
return [taskNotificationItem];
|
|
3601
|
-
}
|
|
2961
|
+
const taskNotificationItem = mapTaskNotificationSystemRecordToToolCall(entry);
|
|
2962
|
+
if (taskNotificationItem) {
|
|
2963
|
+
return [taskNotificationItem];
|
|
3602
2964
|
}
|
|
3603
2965
|
if (entry.isCompactSummary) {
|
|
3604
2966
|
return [];
|
|
@@ -3611,10 +2973,12 @@ export function convertClaudeHistoryEntry(entry, mapBlocks) {
|
|
|
3611
2973
|
return [];
|
|
3612
2974
|
}
|
|
3613
2975
|
const content = message.content;
|
|
2976
|
+
if ((entry.type === "user" || entry.type === "assistant") &&
|
|
2977
|
+
isClaudeTranscriptNoiseContent(content)) {
|
|
2978
|
+
return [];
|
|
2979
|
+
}
|
|
3614
2980
|
const normalizedBlocks = normalizeHistoryBlocks(content);
|
|
3615
|
-
const contentValue = typeof content === "string"
|
|
3616
|
-
? content
|
|
3617
|
-
: normalizedBlocks;
|
|
2981
|
+
const contentValue = typeof content === "string" ? content : normalizedBlocks;
|
|
3618
2982
|
const hasToolBlock = normalizedBlocks?.some((block) => hasToolLikeBlock(block)) ?? false;
|
|
3619
2983
|
const userMessageId = entry.type === "user" && typeof entry.uuid === "string" && entry.uuid.length > 0
|
|
3620
2984
|
? entry.uuid
|
|
@@ -3747,9 +3111,7 @@ async function collectRecentClaudeSessions(root, limit) {
|
|
|
3747
3111
|
}
|
|
3748
3112
|
}
|
|
3749
3113
|
}
|
|
3750
|
-
return candidates
|
|
3751
|
-
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())
|
|
3752
|
-
.slice(0, limit);
|
|
3114
|
+
return candidates.sort((a, b) => b.mtime.getTime() - a.mtime.getTime()).slice(0, limit);
|
|
3753
3115
|
}
|
|
3754
3116
|
async function parseClaudeSessionDescriptor(filePath, mtime) {
|
|
3755
3117
|
let content;
|
|
@@ -3832,15 +3194,20 @@ function extractClaudeUserText(message) {
|
|
|
3832
3194
|
return null;
|
|
3833
3195
|
}
|
|
3834
3196
|
if (typeof message.content === "string") {
|
|
3835
|
-
|
|
3197
|
+
const normalized = message.content.trim();
|
|
3198
|
+
return normalized && !isClaudeTranscriptNoiseText(normalized) ? normalized : null;
|
|
3836
3199
|
}
|
|
3837
3200
|
if (typeof message.text === "string") {
|
|
3838
|
-
|
|
3201
|
+
const normalized = message.text.trim();
|
|
3202
|
+
return normalized && !isClaudeTranscriptNoiseText(normalized) ? normalized : null;
|
|
3839
3203
|
}
|
|
3840
3204
|
if (Array.isArray(message.content)) {
|
|
3841
3205
|
for (const block of message.content) {
|
|
3842
3206
|
if (block && typeof block.text === "string") {
|
|
3843
|
-
|
|
3207
|
+
const normalized = block.text.trim();
|
|
3208
|
+
if (normalized && !isClaudeTranscriptNoiseText(normalized)) {
|
|
3209
|
+
return normalized;
|
|
3210
|
+
}
|
|
3844
3211
|
}
|
|
3845
3212
|
}
|
|
3846
3213
|
}
|