@vellumai/assistant 0.4.26 → 0.4.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -2
- package/AGENTS.md +5 -0
- package/ARCHITECTURE.md +169 -69
- package/Dockerfile +1 -1
- package/README.md +111 -112
- package/bun.lock +0 -3
- package/docs/architecture/integrations.md +0 -1
- package/docs/architecture/memory.md +100 -63
- package/docs/error-handling.md +71 -0
- package/docs/runbook-trusted-contacts.md +10 -9
- package/docs/trusted-contact-access.md +48 -46
- package/package.json +3 -3
- package/scripts/compare-benchmarks.sh +12 -5
- package/scripts/ipc/check-swift-decoder-drift.ts +3 -0
- package/scripts/test.sh +89 -5
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +46 -0
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/account-registry.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +36 -23
- package/src/__tests__/agent-loop-thinking.test.ts +29 -13
- package/src/__tests__/agent-loop.test.ts +2 -1
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +7 -7
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +217 -0
- package/src/__tests__/call-controller.test.ts +99 -69
- package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +113 -70
- package/src/__tests__/channel-guardian.test.ts +173 -282
- package/src/__tests__/channel-readiness-service.test.ts +6 -2
- package/src/__tests__/channel-reply-delivery.test.ts +2 -2
- package/src/__tests__/channel-retry-sweep.test.ts +14 -14
- package/src/__tests__/checker.test.ts +12 -31
- package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +67 -59
- package/src/__tests__/compaction.benchmark.test.ts +6 -2
- package/src/__tests__/computer-use-tools.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +66 -7
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
- package/src/__tests__/contacts-tools.test.ts +63 -2
- package/src/__tests__/context-overflow-approval.test.ts +141 -0
- package/src/__tests__/context-overflow-policy.test.ts +171 -0
- package/src/__tests__/context-overflow-reducer.test.ts +533 -0
- package/src/__tests__/context-window-manager.test.ts +97 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
- package/src/__tests__/conversation-routes.test.ts +4 -7
- package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
- package/src/__tests__/credential-security-e2e.test.ts +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/credential-vault-unit.test.ts +1 -1
- package/src/__tests__/credential-vault.test.ts +11 -8
- package/src/__tests__/daemon-lifecycle.test.ts +2 -2
- package/src/__tests__/daemon-server-session-init.test.ts +6 -6
- package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
- package/src/__tests__/encrypted-store.test.ts +10 -7
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/file-edit-tool.test.ts +1 -1
- package/src/__tests__/file-read-tool.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +1 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
- package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
- package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
- package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
- package/src/__tests__/guardian-dispatch.test.ts +79 -1
- package/src/__tests__/guardian-grant-minting.test.ts +14 -14
- package/src/__tests__/guardian-outbound-http.test.ts +1 -2
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -5
- package/src/__tests__/guardian-routing-state.test.ts +36 -52
- package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
- package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
- package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
- package/src/__tests__/handlers-telegram-config.test.ts +14 -14
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +1 -1
- package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
- package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +45 -2
- package/src/__tests__/host-file-edit-tool.test.ts +1 -1
- package/src/__tests__/host-file-read-tool.test.ts +1 -1
- package/src/__tests__/host-file-write-tool.test.ts +1 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +16 -18
- package/src/__tests__/ingress-reconcile.test.ts +2 -2
- package/src/__tests__/ingress-routes-http.test.ts +2 -1
- package/src/__tests__/integrations-cli.test.ts +256 -0
- package/src/__tests__/intent-routing.test.ts +4 -5
- package/src/__tests__/invite-redemption-service.test.ts +4 -3
- package/src/__tests__/ipc-snapshot.test.ts +28 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
- package/src/__tests__/mcp-cli.test.ts +136 -57
- package/src/__tests__/mcp-client-auth.test.ts +95 -0
- package/src/__tests__/media-generate-image.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
- package/src/__tests__/memory-regressions.test.ts +6 -6
- package/src/__tests__/messaging-send-tool.test.ts +1 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
- package/src/__tests__/migration-export-http.test.ts +540 -0
- package/src/__tests__/migration-import-commit-http.test.ts +823 -0
- package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
- package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
- package/src/__tests__/migration-transport.test.ts +904 -0
- package/src/__tests__/migration-validate-http.test.ts +698 -0
- package/src/__tests__/migration-wizard.test.ts +1289 -0
- package/src/__tests__/non-member-access-request.test.ts +17 -17
- package/src/__tests__/notification-decision-strategy.test.ts +110 -2
- package/src/__tests__/notification-deep-link.test.ts +18 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/oauth2-gateway-transport.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
- package/src/__tests__/proxy-approval-callback.test.ts +1 -1
- package/src/__tests__/qdrant-manager.test.ts +40 -11
- package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
- package/src/__tests__/recording-handler.test.ts +2 -2
- package/src/__tests__/recording-intent-handler.test.ts +3 -3
- package/src/__tests__/recording-state-machine.test.ts +2 -2
- package/src/__tests__/relay-server.test.ts +506 -227
- package/src/__tests__/reminder-store.test.ts +8 -0
- package/src/__tests__/reminder.test.ts +8 -0
- package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
- package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
- package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
- package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
- package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
- package/src/__tests__/script-proxy-policy.test.ts +2 -2
- package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
- package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/secret-scanner-executor.test.ts +2 -2
- package/src/__tests__/send-endpoint-busy.test.ts +11 -9
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +17 -2
- package/src/__tests__/session-agent-loop.test.ts +456 -35
- package/src/__tests__/session-confirmation-signals.test.ts +3 -2
- package/src/__tests__/session-conflict-gate.test.ts +20 -3
- package/src/__tests__/session-init.benchmark.test.ts +2 -2
- package/src/__tests__/session-load-history-repair.test.ts +7 -7
- package/src/__tests__/session-pre-run-repair.test.ts +17 -2
- package/src/__tests__/session-profile-injection.test.ts +20 -3
- package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
- package/src/__tests__/session-queue.test.ts +33 -18
- package/src/__tests__/session-runtime-assembly.test.ts +147 -1
- package/src/__tests__/session-runtime-workspace.test.ts +40 -0
- package/src/__tests__/session-slash-known.test.ts +21 -3
- package/src/__tests__/session-slash-queue.test.ts +17 -2
- package/src/__tests__/session-slash-unknown.test.ts +17 -2
- package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
- package/src/__tests__/session-workspace-injection.test.ts +17 -2
- package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
- package/src/__tests__/shell-credential-ref.test.ts +1 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
- package/src/__tests__/skill-load-tool.test.ts +1 -1
- package/src/__tests__/skill-script-runner-host.test.ts +1 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
- package/src/__tests__/skill-script-runner.test.ts +1 -1
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/slack-skill.test.ts +3 -2
- package/src/__tests__/subagent-tools.test.ts +3 -3
- package/src/__tests__/swarm-recursion.test.ts +1 -1
- package/src/__tests__/swarm-session-integration.test.ts +1 -1
- package/src/__tests__/swarm-tool.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-tools.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
- package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
- package/src/__tests__/tool-approval-handler.test.ts +15 -15
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +23 -182
- package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
- package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
- package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
- package/src/__tests__/trust-context-guards.test.ts +25 -29
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
- package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
- package/src/__tests__/trusted-contact-verification.test.ts +63 -77
- package/src/__tests__/turn-commit.test.ts +18 -18
- package/src/__tests__/twilio-provider.test.ts +7 -7
- package/src/__tests__/validation-results-screen.test.ts +1107 -0
- package/src/__tests__/view-image-tool.test.ts +1 -1
- package/src/__tests__/voice-invite-redemption.test.ts +3 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
- package/src/__tests__/voice-session-bridge.test.ts +24 -24
- package/src/agent/attachments.ts +3 -1
- package/src/agent/loop.ts +13 -13
- package/src/agent/message-types.ts +13 -7
- package/src/amazon/cart.ts +59 -32
- package/src/amazon/checkout.ts +25 -14
- package/src/amazon/client.ts +68 -48
- package/src/amazon/product-details.ts +3 -3
- package/src/amazon/request-extractor.ts +46 -31
- package/src/amazon/search.ts +6 -4
- package/src/amazon/session.ts +33 -24
- package/src/approvals/AGENTS.md +26 -0
- package/src/approvals/approval-primitive.ts +87 -64
- package/src/approvals/guardian-decision-primitive.ts +172 -81
- package/src/approvals/guardian-request-resolvers.ts +262 -155
- package/src/autonomy/autonomy-resolver.ts +7 -5
- package/src/autonomy/autonomy-store.ts +34 -19
- package/src/autonomy/disposition-mapper.ts +5 -5
- package/src/autonomy/index.ts +6 -6
- package/src/autonomy/types.ts +7 -3
- package/src/browser-extension-relay/client.ts +50 -19
- package/src/browser-extension-relay/protocol.ts +11 -11
- package/src/browser-extension-relay/server.ts +45 -20
- package/src/bundler/app-bundler.ts +75 -50
- package/src/bundler/bundle-scanner.ts +145 -41
- package/src/bundler/bundle-signer.ts +16 -14
- package/src/bundler/signature-verifier.ts +36 -33
- package/src/calls/call-constants.ts +10 -3
- package/src/calls/call-controller.ts +473 -214
- package/src/calls/call-conversation-messages.ts +25 -15
- package/src/calls/call-domain.ts +401 -148
- package/src/calls/call-pointer-message-composer.ts +26 -21
- package/src/calls/call-pointer-messages.ts +52 -28
- package/src/calls/call-recovery.ts +53 -37
- package/src/calls/call-state-machine.ts +37 -7
- package/src/calls/call-state.ts +35 -13
- package/src/calls/call-store.ts +165 -77
- package/src/calls/elevenlabs-client.ts +39 -20
- package/src/calls/guardian-action-sweep.ts +42 -24
- package/src/calls/guardian-dispatch.ts +79 -56
- package/src/calls/guardian-question-copy.ts +28 -23
- package/src/calls/relay-server.ts +1121 -532
- package/src/calls/speaker-identification.ts +21 -15
- package/src/calls/twilio-config.ts +34 -17
- package/src/calls/twilio-provider.ts +108 -55
- package/src/calls/twilio-rest.ts +212 -100
- package/src/calls/twilio-routes.ts +165 -92
- package/src/calls/types.ts +55 -7
- package/src/calls/voice-quality.ts +6 -4
- package/src/calls/voice-session-bridge.ts +181 -133
- package/src/channels/config.ts +17 -13
- package/src/channels/types.ts +38 -10
- package/src/cli/amazon.ts +333 -227
- package/src/cli/config-commands.ts +236 -146
- package/src/cli/core-commands.ts +403 -329
- package/src/cli/email-guardrails.ts +38 -19
- package/src/cli/email.ts +207 -153
- package/src/cli/influencer.ts +58 -56
- package/src/cli/integrations.ts +362 -0
- package/src/cli/ipc-client.ts +24 -19
- package/src/cli/map.ts +176 -129
- package/src/cli/mcp.ts +260 -152
- package/src/cli/sequence.ts +165 -107
- package/src/cli/twitter.ts +302 -218
- package/src/cli.ts +418 -279
- package/src/commands/cc-command-registry.ts +52 -27
- package/src/config/agent-schema.ts +217 -134
- package/src/config/assistant-feature-flags.ts +23 -18
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
- package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
- package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
- package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
- package/src/config/bundled-skills/contacts/SKILL.md +446 -15
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +99 -20
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +74 -17
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +89 -26
- package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
- package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
- package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
- package/src/config/bundled-skills/email-setup/SKILL.md +9 -9
- package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
- package/src/config/bundled-skills/google-calendar/types.ts +3 -3
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +46 -24
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +36 -19
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
- package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
- package/src/config/bundled-skills/media-processing/TOOLS.json +20 -2
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
- package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +177 -91
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
- package/src/config/bundled-skills/messaging/SKILL.md +7 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +7 -7
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
- package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
- package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
- package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
- package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
- package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
- package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
- package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
- package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
- package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
- package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
- package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
- package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
- package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
- package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
- package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
- package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
- package/src/config/bundled-skills/slack/TOOLS.json +33 -15
- package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
- package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
- package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
- package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
- package/src/config/bundled-skills/twitter/SKILL.md +19 -2
- package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
- package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
- package/src/config/calls-schema.ts +108 -63
- package/src/config/computer-use-prompt.ts +7 -7
- package/src/config/core-schema.ts +239 -155
- package/src/config/defaults.ts +2 -2
- package/src/config/elevenlabs-schema.ts +15 -15
- package/src/config/env-registry.ts +33 -33
- package/src/config/feature-flag-registry.json +31 -7
- package/src/config/loader.ts +118 -58
- package/src/config/mcp-schema.ts +29 -15
- package/src/config/memory-schema.ts +434 -229
- package/src/config/notifications-schema.ts +4 -4
- package/src/config/sandbox-schema.ts +2 -2
- package/src/config/schema.ts +12 -2
- package/src/config/skill-state.ts +27 -15
- package/src/config/skills-schema.ts +72 -23
- package/src/config/skills.ts +303 -143
- package/src/config/system-prompt.ts +25 -6
- package/src/config/types.ts +1 -1
- package/src/config/update-bulletin-format.ts +3 -3
- package/src/config/update-bulletin-state.ts +15 -6
- package/src/config/update-bulletin-template-path.ts +8 -4
- package/src/config/update-bulletin.ts +33 -14
- package/src/config/user-reference.ts +8 -8
- package/src/contacts/contact-events.ts +21 -0
- package/src/contacts/contact-store.ts +622 -100
- package/src/contacts/contacts-write.ts +287 -0
- package/src/contacts/index.ts +13 -4
- package/src/contacts/startup-migration.ts +21 -0
- package/src/contacts/types.ts +47 -2
- package/src/context/token-estimator.ts +54 -31
- package/src/context/tool-result-truncation.ts +41 -7
- package/src/context/window-manager.ts +225 -120
- package/src/daemon/approval-generators.ts +83 -55
- package/src/daemon/approved-devices-store.ts +33 -20
- package/src/daemon/assistant-attachments.ts +134 -98
- package/src/daemon/auth-manager.ts +17 -15
- package/src/daemon/classifier.ts +117 -46
- package/src/daemon/computer-use-session.ts +316 -187
- package/src/daemon/config-watcher.ts +91 -44
- package/src/daemon/connection-policy.ts +18 -10
- package/src/daemon/context-overflow-approval.ts +48 -0
- package/src/daemon/context-overflow-policy.ts +50 -0
- package/src/daemon/context-overflow-reducer.ts +300 -0
- package/src/daemon/daemon-control.ts +79 -51
- package/src/daemon/date-context.ts +119 -69
- package/src/daemon/dictation-profile-store.ts +94 -48
- package/src/daemon/dictation-text-processing.ts +33 -12
- package/src/daemon/doordash-steps.ts +92 -49
- package/src/daemon/guardian-action-generators.ts +62 -46
- package/src/daemon/guardian-verification-intent.ts +31 -18
- package/src/daemon/handlers/apps.ts +257 -111
- package/src/daemon/handlers/avatar.ts +20 -15
- package/src/daemon/handlers/computer-use.ts +82 -39
- package/src/daemon/handlers/config-channels.ts +146 -69
- package/src/daemon/handlers/config-heartbeat.ts +114 -59
- package/src/daemon/handlers/config-inbox.ts +277 -106
- package/src/daemon/handlers/config-ingress.ts +127 -55
- package/src/daemon/handlers/config-integrations.ts +145 -88
- package/src/daemon/handlers/config-model.ts +58 -22
- package/src/daemon/handlers/config-platform.ts +40 -16
- package/src/daemon/handlers/config-scheduling.ts +109 -48
- package/src/daemon/handlers/config-slack-channel.ts +67 -35
- package/src/daemon/handlers/config-slack.ts +21 -20
- package/src/daemon/handlers/config-telegram.ts +100 -70
- package/src/daemon/handlers/config-tools.ts +103 -55
- package/src/daemon/handlers/config-trust.ts +50 -20
- package/src/daemon/handlers/config.ts +72 -24
- package/src/daemon/handlers/contacts.ts +163 -0
- package/src/daemon/handlers/diagnostics.ts +90 -48
- package/src/daemon/handlers/documents.ts +74 -46
- package/src/daemon/handlers/guardian-actions.ts +118 -71
- package/src/daemon/handlers/home-base.ts +19 -16
- package/src/daemon/handlers/identity.ts +65 -45
- package/src/daemon/handlers/index.ts +78 -54
- package/src/daemon/handlers/misc.ts +664 -234
- package/src/daemon/handlers/navigate-settings.ts +14 -11
- package/src/daemon/handlers/oauth-connect.ts +48 -35
- package/src/daemon/handlers/open-bundle-handler.ts +31 -24
- package/src/daemon/handlers/pairing.ts +51 -25
- package/src/daemon/handlers/publish.ts +55 -33
- package/src/daemon/handlers/recording.ts +378 -162
- package/src/daemon/handlers/sessions.ts +923 -423
- package/src/daemon/handlers/shared.ts +202 -117
- package/src/daemon/handlers/signing.ts +25 -6
- package/src/daemon/handlers/subagents.ts +117 -56
- package/src/daemon/handlers/twitter-auth.ts +70 -49
- package/src/daemon/handlers/work-items.ts +264 -112
- package/src/daemon/handlers/workspace-files.ts +27 -20
- package/src/daemon/handlers.ts +2 -2
- package/src/daemon/history-repair.ts +16 -15
- package/src/daemon/identity-helpers.ts +4 -4
- package/src/daemon/install-cli-launchers.ts +33 -22
- package/src/daemon/ipc-blob-store.ts +38 -24
- package/src/daemon/ipc-contract/apps.ts +61 -49
- package/src/daemon/ipc-contract/computer-use.ts +47 -37
- package/src/daemon/ipc-contract/contacts.ts +69 -0
- package/src/daemon/ipc-contract/diagnostics.ts +14 -14
- package/src/daemon/ipc-contract/documents.ts +8 -8
- package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
- package/src/daemon/ipc-contract/inbox.ts +16 -16
- package/src/daemon/ipc-contract/integrations.ts +57 -44
- package/src/daemon/ipc-contract/memory.ts +3 -5
- package/src/daemon/ipc-contract/messages.ts +95 -69
- package/src/daemon/ipc-contract/notifications.ts +10 -6
- package/src/daemon/ipc-contract/pairing.ts +8 -8
- package/src/daemon/ipc-contract/schedules.ts +20 -20
- package/src/daemon/ipc-contract/sessions.ts +88 -57
- package/src/daemon/ipc-contract/settings.ts +12 -7
- package/src/daemon/ipc-contract/shared.ts +9 -7
- package/src/daemon/ipc-contract/skills.ts +46 -26
- package/src/daemon/ipc-contract/subagents.ts +9 -9
- package/src/daemon/ipc-contract/trust.ts +11 -11
- package/src/daemon/ipc-contract/work-items.ts +33 -28
- package/src/daemon/ipc-contract/workspace.ts +28 -21
- package/src/daemon/ipc-contract-inventory.json +8 -0
- package/src/daemon/ipc-contract-inventory.ts +29 -26
- package/src/daemon/ipc-contract.ts +111 -44
- package/src/daemon/ipc-handler.ts +27 -19
- package/src/daemon/ipc-protocol.ts +22 -12
- package/src/daemon/ipc-validate.ts +91 -46
- package/src/daemon/lifecycle.ts +25 -1
- package/src/daemon/main.ts +10 -8
- package/src/daemon/media-visibility-policy.ts +3 -1
- package/src/daemon/pairing-store.ts +72 -40
- package/src/daemon/providers-setup.ts +35 -25
- package/src/daemon/recording-executor.ts +37 -30
- package/src/daemon/recording-intent-fallback.ts +58 -28
- package/src/daemon/recording-intent.ts +71 -61
- package/src/daemon/ride-shotgun-handler.ts +201 -121
- package/src/daemon/seed-files.ts +28 -17
- package/src/daemon/server.ts +23 -14
- package/src/daemon/session-agent-loop-handlers.ts +261 -135
- package/src/daemon/session-agent-loop.ts +795 -253
- package/src/daemon/session-attachments.ts +104 -39
- package/src/daemon/session-conflict-gate.ts +72 -28
- package/src/daemon/session-dynamic-profile.ts +36 -22
- package/src/daemon/session-error.ts +50 -45
- package/src/daemon/session-evictor.ts +17 -10
- package/src/daemon/session-history.ts +201 -89
- package/src/daemon/session-lifecycle.ts +79 -42
- package/src/daemon/session-media-retry.ts +89 -41
- package/src/daemon/session-memory.ts +77 -55
- package/src/daemon/session-messaging.ts +261 -111
- package/src/daemon/session-notifiers.ts +57 -45
- package/src/daemon/session-process.ts +370 -154
- package/src/daemon/session-queue-manager.ts +30 -13
- package/src/daemon/session-runtime-assembly.ts +61 -15
- package/src/daemon/session-skill-tools.ts +84 -36
- package/src/daemon/session-slash.ts +178 -113
- package/src/daemon/session-surfaces.ts +498 -211
- package/src/daemon/session-tool-setup.ts +22 -17
- package/src/daemon/session-usage.ts +26 -13
- package/src/daemon/session-workspace.ts +7 -4
- package/src/daemon/session.ts +18 -19
- package/src/daemon/shutdown-handlers.ts +36 -33
- package/src/daemon/tls-certs.ts +90 -57
- package/src/daemon/tool-side-effects.ts +97 -65
- package/src/daemon/trace-emitter.ts +8 -7
- package/src/daemon/video-thumbnail.ts +55 -25
- package/src/daemon/watch-handler.ts +164 -86
- package/src/email/provider.ts +1 -1
- package/src/email/providers/agentmail.ts +87 -45
- package/src/email/providers/index.ts +19 -14
- package/src/email/service.ts +52 -24
- package/src/email/types.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/events/bus.ts +30 -10
- package/src/events/domain-events.ts +19 -13
- package/src/events/index.ts +6 -6
- package/src/events/tool-audit-listener.ts +34 -20
- package/src/events/tool-domain-event-publisher.ts +22 -20
- package/src/events/tool-metrics-listener.ts +26 -21
- package/src/events/tool-notification-listener.ts +5 -5
- package/src/events/tool-profiling-listener.ts +33 -23
- package/src/events/tool-trace-listener.ts +70 -46
- package/src/export/formatter.ts +38 -32
- package/src/followups/followup-store.ts +43 -36
- package/src/followups/index.ts +2 -2
- package/src/followups/types.ts +1 -1
- package/src/gallery/default-gallery.ts +37 -34
- package/src/gallery/gallery-manifest.ts +9 -9
- package/src/heartbeat/heartbeat-service.ts +59 -37
- package/src/home-base/app-link-store.ts +14 -12
- package/src/home-base/bootstrap.ts +14 -8
- package/src/home-base/prebuilt/seed.ts +35 -26
- package/src/home-base/prebuilt-home-base-updater.ts +14 -8
- package/src/hooks/cli.ts +56 -43
- package/src/hooks/config.ts +27 -14
- package/src/hooks/discovery.ts +53 -33
- package/src/hooks/manager.ts +50 -26
- package/src/hooks/runner.ts +35 -29
- package/src/hooks/templates.ts +38 -15
- package/src/hooks/types.ts +13 -13
- package/src/inbound/platform-callback-registration.ts +21 -15
- package/src/inbound/public-ingress-urls.ts +9 -6
- package/src/index.ts +20 -19
- package/src/influencer/client.ts +269 -108
- package/src/instrument.ts +3 -1
- package/src/logfire.ts +64 -39
- package/src/mcp/client.ts +107 -55
- package/src/mcp/manager.ts +45 -18
- package/src/mcp/mcp-oauth-provider.ts +114 -62
- package/src/media/gemini-image-service.ts +28 -21
- package/src/memory/account-store.ts +16 -9
- package/src/memory/admin.ts +87 -57
- package/src/memory/app-git-service.ts +77 -47
- package/src/memory/app-store.ts +151 -77
- package/src/memory/attachments-store.ts +123 -53
- package/src/memory/canonical-guardian-store.ts +190 -48
- package/src/memory/channel-delivery-store.ts +5 -5
- package/src/memory/channel-guardian-store.ts +31 -16
- package/src/memory/checkpoints.ts +14 -7
- package/src/memory/clarification-resolver.ts +219 -104
- package/src/memory/conflict-intent.ts +74 -23
- package/src/memory/conflict-policy.ts +20 -7
- package/src/memory/conflict-store.ts +144 -94
- package/src/memory/contradiction-checker.ts +257 -132
- package/src/memory/conversation-attention-store.ts +72 -32
- package/src/memory/conversation-bootstrap.ts +28 -0
- package/src/memory/conversation-crud.ts +12 -5
- package/src/memory/conversation-display-order-migration.ts +7 -7
- package/src/memory/conversation-key-store.ts +18 -13
- package/src/memory/conversation-queries.ts +130 -52
- package/src/memory/conversation-store.ts +43 -26
- package/src/memory/conversation-title-service.ts +89 -66
- package/src/memory/db-init.ts +90 -2
- package/src/memory/db.ts +10 -3
- package/src/memory/delivery-channels.ts +12 -6
- package/src/memory/delivery-crud.ts +26 -12
- package/src/memory/delivery-status.ts +19 -16
- package/src/memory/embedding-backend.ts +205 -77
- package/src/memory/embedding-gemini.ts +23 -10
- package/src/memory/embedding-local.ts +89 -44
- package/src/memory/embedding-ollama.ts +25 -13
- package/src/memory/embedding-openai.ts +20 -11
- package/src/memory/embedding-runtime-manager.ts +163 -90
- package/src/memory/entity-extractor.ts +185 -123
- package/src/memory/external-conversation-store.ts +30 -12
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/fts-reconciler.ts +57 -28
- package/src/memory/guardian-action-store.ts +162 -100
- package/src/memory/guardian-approvals.ts +63 -129
- package/src/memory/guardian-rate-limits.ts +20 -9
- package/src/memory/guardian-verification.ts +82 -35
- package/src/memory/indexer.ts +96 -55
- package/src/memory/ingress-invite-store.ts +28 -169
- package/src/memory/items-extractor.ts +313 -157
- package/src/memory/job-handlers/backfill.ts +116 -63
- package/src/memory/job-handlers/cleanup.ts +64 -41
- package/src/memory/job-handlers/conflict.ts +90 -49
- package/src/memory/job-handlers/embedding.ts +32 -17
- package/src/memory/job-handlers/extraction.ts +58 -33
- package/src/memory/job-handlers/index-maintenance.ts +31 -17
- package/src/memory/job-handlers/media-processing.ts +65 -24
- package/src/memory/job-handlers/summarization.ts +186 -128
- package/src/memory/job-utils.ts +100 -57
- package/src/memory/jobs-store.ts +235 -142
- package/src/memory/jobs-worker.ts +167 -83
- package/src/memory/llm-request-log-store.ts +13 -11
- package/src/memory/llm-usage-store.ts +35 -26
- package/src/memory/media-store.ts +151 -44
- package/src/memory/message-content.ts +28 -18
- package/src/memory/migrations/001-job-deferrals.ts +11 -5
- package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
- package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
- package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
- package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
- package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
- package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
- package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
- package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
- package/src/memory/migrations/022-add-origin-interface.ts +4 -2
- package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
- package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
- package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
- package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
- package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
- package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
- package/src/memory/migrations/028-call-session-mode.ts +13 -3
- package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
- package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
- package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
- package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
- package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
- package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
- package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
- package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
- package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
- package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
- package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
- package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
- package/src/memory/migrations/038-actor-token-records.ts +5 -9
- package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
- package/src/memory/migrations/103-complex-migrations.ts +9 -9
- package/src/memory/migrations/104-core-indexes.ts +188 -64
- package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
- package/src/memory/migrations/106-call-sessions.ts +58 -16
- package/src/memory/migrations/107-followups.ts +16 -6
- package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
- package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
- package/src/memory/migrations/110-channel-guardian.ts +48 -10
- package/src/memory/migrations/111-media-assets.ts +52 -18
- package/src/memory/migrations/112-assistant-inbox.ts +32 -12
- package/src/memory/migrations/113-late-migrations.ts +12 -12
- package/src/memory/migrations/114-notifications.ts +28 -12
- package/src/memory/migrations/115-sequences.ts +10 -4
- package/src/memory/migrations/116-messages-fts.ts +1 -1
- package/src/memory/migrations/117-conversation-attention.ts +16 -6
- package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
- package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
- package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
- package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
- package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
- package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
- package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
- package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
- package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
- package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
- package/src/memory/migrations/index.ts +82 -73
- package/src/memory/migrations/registry.ts +53 -37
- package/src/memory/migrations/validate-migration-state.ts +73 -46
- package/src/memory/profile-compiler.ts +58 -24
- package/src/memory/published-pages-store.ts +12 -16
- package/src/memory/qdrant-circuit-breaker.ts +28 -20
- package/src/memory/qdrant-client.ts +99 -63
- package/src/memory/qdrant-manager.ts +89 -57
- package/src/memory/query-builder.ts +9 -7
- package/src/memory/raw-query.ts +63 -14
- package/src/memory/recall-cache.ts +15 -8
- package/src/memory/retrieval-budget.ts +0 -1
- package/src/memory/retriever.ts +385 -192
- package/src/memory/schema-migration.ts +1 -1
- package/src/memory/schema.ts +44 -56
- package/src/memory/scoped-approval-grants.ts +99 -45
- package/src/memory/search/entity.ts +102 -40
- package/src/memory/search/formatting.ts +70 -52
- package/src/memory/search/lexical.ts +82 -43
- package/src/memory/search/ranking.ts +103 -39
- package/src/memory/search/semantic.ts +59 -35
- package/src/memory/search/types.ts +8 -8
- package/src/memory/segmenter.ts +20 -12
- package/src/memory/shared-app-links-store.ts +21 -16
- package/src/memory/task-memory-cleanup.ts +18 -8
- package/src/memory/tool-usage-store.ts +27 -19
- package/src/memory/validation.ts +4 -2
- package/src/messaging/activity-analyzer.ts +7 -7
- package/src/messaging/draft-store.ts +13 -10
- package/src/messaging/email-classifier.ts +73 -37
- package/src/messaging/index.ts +3 -3
- package/src/messaging/outreach-classifier.ts +76 -38
- package/src/messaging/provider-types.ts +2 -4
- package/src/messaging/provider.ts +37 -8
- package/src/messaging/providers/gmail/adapter.ts +183 -66
- package/src/messaging/providers/gmail/client.ts +3 -1
- package/src/messaging/providers/gmail/mime-builder.ts +21 -19
- package/src/messaging/providers/gmail/people-client.ts +22 -9
- package/src/messaging/providers/gmail/types.ts +6 -6
- package/src/messaging/providers/slack/adapter.ts +93 -43
- package/src/messaging/providers/slack/client.ts +100 -41
- package/src/messaging/providers/slack/types.ts +6 -0
- package/src/messaging/providers/sms/adapter.ts +76 -40
- package/src/messaging/providers/sms/client.ts +4 -4
- package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
- package/src/messaging/providers/telegram-bot/client.ts +7 -7
- package/src/messaging/providers/whatsapp/adapter.ts +58 -31
- package/src/messaging/providers/whatsapp/client.ts +4 -4
- package/src/messaging/registry.ts +9 -5
- package/src/messaging/style-analyzer.ts +69 -39
- package/src/messaging/thread-summarizer.ts +101 -53
- package/src/messaging/triage-engine.ts +111 -82
- package/src/messaging/types.ts +10 -10
- package/src/migrations/config-merge.ts +18 -10
- package/src/migrations/data-layout.ts +35 -22
- package/src/migrations/data-merge.ts +17 -7
- package/src/migrations/hooks-merge.ts +43 -16
- package/src/migrations/index.ts +6 -6
- package/src/migrations/log.ts +9 -5
- package/src/migrations/skills-merge.ts +17 -7
- package/src/migrations/workspace-layout.ts +39 -25
- package/src/notifications/AGENTS.md +5 -0
- package/src/notifications/adapters/macos.ts +21 -14
- package/src/notifications/adapters/sms.ts +28 -15
- package/src/notifications/adapters/telegram.ts +24 -15
- package/src/notifications/broadcaster.ts +108 -52
- package/src/notifications/conversation-pairing.ts +64 -29
- package/src/notifications/copy-composer.ts +165 -95
- package/src/notifications/decision-engine.ts +353 -147
- package/src/notifications/decisions-store.ts +26 -10
- package/src/notifications/deliveries-store.ts +23 -13
- package/src/notifications/destination-resolver.ts +42 -24
- package/src/notifications/deterministic-checks.ts +78 -27
- package/src/notifications/emit-signal.ts +83 -45
- package/src/notifications/events-store.ts +13 -7
- package/src/notifications/guardian-question-mode.ts +125 -75
- package/src/notifications/preference-extractor.ts +85 -53
- package/src/notifications/preference-summary.ts +31 -18
- package/src/notifications/preferences-store.ts +29 -18
- package/src/notifications/runtime-dispatch.ts +22 -12
- package/src/notifications/signal.ts +4 -4
- package/src/notifications/thread-candidates.ts +59 -23
- package/src/notifications/thread-seed-composer.ts +45 -27
- package/src/notifications/types.ts +19 -10
- package/src/oauth/connect-orchestrator.ts +105 -54
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/provider-profiles.ts +80 -59
- package/src/oauth/scope-policy.ts +5 -2
- package/src/oauth/token-persistence.ts +58 -24
- package/src/outbound-proxy/certs.ts +284 -0
- package/src/outbound-proxy/config.ts +94 -0
- package/src/outbound-proxy/connect-tunnel.ts +84 -0
- package/src/outbound-proxy/health.ts +62 -0
- package/src/outbound-proxy/host-pattern-match.ts +67 -0
- package/src/outbound-proxy/http-forwarder.ts +162 -0
- package/src/outbound-proxy/index.ts +80 -0
- package/src/outbound-proxy/logging.ts +193 -0
- package/src/outbound-proxy/mitm-handler.ts +292 -0
- package/src/outbound-proxy/policy.ts +172 -0
- package/src/outbound-proxy/router.ts +64 -0
- package/src/outbound-proxy/server.ts +145 -0
- package/src/outbound-proxy/types.ts +150 -0
- package/src/permissions/checker.ts +481 -189
- package/src/permissions/defaults.ts +135 -108
- package/src/permissions/prompter.ts +53 -27
- package/src/permissions/secret-prompter.ts +21 -15
- package/src/permissions/shell-identity.ts +47 -16
- package/src/permissions/trust-store.ts +185 -73
- package/src/permissions/types.ts +22 -12
- package/src/permissions/workspace-policy.ts +47 -38
- package/src/playbooks/index.ts +10 -2
- package/src/playbooks/playbook-compiler.ts +30 -24
- package/src/playbooks/types.ts +11 -8
- package/src/providers/anthropic/client.ts +325 -168
- package/src/providers/failover.ts +57 -22
- package/src/providers/fireworks/client.ts +9 -5
- package/src/providers/gemini/client.ts +61 -39
- package/src/providers/model-intents.ts +40 -33
- package/src/providers/ollama/client.ts +7 -7
- package/src/providers/openai/client.ts +106 -68
- package/src/providers/openrouter/client.ts +9 -5
- package/src/providers/provider-send-message.ts +59 -27
- package/src/providers/ratelimit.ts +25 -8
- package/src/providers/registry.ts +86 -38
- package/src/providers/retry.ts +84 -36
- package/src/providers/stream-timeout.ts +5 -3
- package/src/providers/types.ts +7 -6
- package/src/runtime/AGENTS.md +42 -0
- package/src/runtime/access-request-helper.ts +118 -68
- package/src/runtime/actor-refresh-token-store.ts +21 -16
- package/src/runtime/actor-token-store.ts +25 -18
- package/src/runtime/actor-trust-resolver.ts +183 -80
- package/src/runtime/approval-conversation-turn.ts +39 -26
- package/src/runtime/approval-message-composer.ts +116 -84
- package/src/runtime/assistant-event-hub.ts +25 -6
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/assistant-scope.ts +1 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
- package/src/runtime/auth/context.ts +8 -7
- package/src/runtime/auth/credential-service.ts +60 -38
- package/src/runtime/auth/external-assistant-id.ts +16 -8
- package/src/runtime/auth/index.ts +23 -16
- package/src/runtime/auth/route-policy.ts +170 -104
- package/src/runtime/auth/scopes.ts +22 -29
- package/src/runtime/auth/subject.ts +19 -13
- package/src/runtime/auth/token-service.ts +3 -3
- package/src/runtime/auth/types.ts +23 -23
- package/src/runtime/channel-approval-parser.ts +37 -14
- package/src/runtime/channel-approval-types.ts +12 -4
- package/src/runtime/channel-approvals.ts +41 -23
- package/src/runtime/channel-guardian-service.ts +144 -103
- package/src/runtime/channel-invite-transport.ts +4 -2
- package/src/runtime/channel-invite-transports/telegram.ts +16 -10
- package/src/runtime/channel-invite-transports/voice.ts +7 -7
- package/src/runtime/channel-readiness-service.ts +139 -90
- package/src/runtime/channel-readiness-types.ts +4 -2
- package/src/runtime/channel-reply-delivery.ts +21 -11
- package/src/runtime/channel-retry-sweep.ts +111 -62
- package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
- package/src/runtime/gateway-client.ts +86 -53
- package/src/runtime/guardian-action-conversation-turn.ts +34 -18
- package/src/runtime/guardian-action-followup-executor.ts +115 -45
- package/src/runtime/guardian-action-grant-minter.ts +40 -24
- package/src/runtime/guardian-action-message-composer.ts +105 -84
- package/src/runtime/guardian-decision-types.ts +28 -13
- package/src/runtime/guardian-outbound-actions.ts +9 -0
- package/src/runtime/guardian-reply-router.ts +274 -145
- package/src/runtime/guardian-vellum-migration.ts +38 -24
- package/src/runtime/guardian-verification-templates.ts +8 -11
- package/src/runtime/http-router.ts +175 -0
- package/src/runtime/http-server.ts +931 -669
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/ingress-service.ts +182 -89
- package/src/runtime/invite-redemption-service.ts +211 -134
- package/src/runtime/invite-redemption-templates.ts +18 -11
- package/src/runtime/local-actor-identity.ts +73 -55
- package/src/runtime/middleware/auth.ts +25 -14
- package/src/runtime/middleware/error-handler.ts +15 -11
- package/src/runtime/middleware/rate-limiter.ts +23 -17
- package/src/runtime/middleware/request-logger.ts +4 -4
- package/src/runtime/middleware/twilio-validation.ts +29 -20
- package/src/runtime/migrations/migration-transport.ts +575 -0
- package/src/runtime/migrations/migration-wizard.ts +715 -0
- package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
- package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
- package/src/runtime/migrations/validation-results-screen.ts +467 -0
- package/src/runtime/migrations/vbundle-builder.ts +295 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
- package/src/runtime/migrations/vbundle-importer.ts +339 -0
- package/src/runtime/migrations/vbundle-validator.ts +356 -0
- package/src/runtime/pending-interactions.ts +16 -7
- package/src/runtime/routes/access-request-decision.ts +73 -52
- package/src/runtime/routes/app-routes.ts +56 -38
- package/src/runtime/routes/approval-routes.ts +165 -74
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
- package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
- package/src/runtime/routes/attachment-routes.ts +59 -48
- package/src/runtime/routes/brain-graph-routes.ts +85 -69
- package/src/runtime/routes/call-routes.ts +79 -38
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
- package/src/runtime/routes/channel-delivery-routes.ts +19 -14
- package/src/runtime/routes/channel-guardian-routes.ts +3 -3
- package/src/runtime/routes/channel-inbound-routes.ts +2 -2
- package/src/runtime/routes/channel-readiness-routes.ts +12 -6
- package/src/runtime/routes/channel-route-shared.ts +33 -25
- package/src/runtime/routes/channel-routes.ts +4 -6
- package/src/runtime/routes/contact-routes.ts +205 -16
- package/src/runtime/routes/conversation-attention-routes.ts +57 -28
- package/src/runtime/routes/conversation-routes.ts +321 -174
- package/src/runtime/routes/debug-routes.ts +14 -10
- package/src/runtime/routes/events-routes.ts +90 -57
- package/src/runtime/routes/global-search-routes.ts +266 -0
- package/src/runtime/routes/guardian-action-routes.ts +147 -56
- package/src/runtime/routes/guardian-approval-interception.ts +255 -880
- package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
- package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
- package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
- package/src/runtime/routes/identity-routes.ts +71 -42
- package/src/runtime/routes/inbound-conversation.ts +17 -11
- package/src/runtime/routes/inbound-message-handler.ts +278 -1460
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +658 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +492 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
- package/src/runtime/routes/ingress-routes.ts +34 -23
- package/src/runtime/routes/integration-routes.ts +60 -21
- package/src/runtime/routes/migration-routes.ts +434 -0
- package/src/runtime/routes/pairing-routes.ts +157 -79
- package/src/runtime/routes/secret-routes.ts +6 -2
- package/src/runtime/routes/twilio-routes.ts +443 -249
- package/src/runtime/tool-grant-request-helper.ts +36 -27
- package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
- package/src/schedule/integration-status.ts +44 -9
- package/src/schedule/recurrence-engine.ts +47 -24
- package/src/schedule/recurrence-types.ts +12 -7
- package/src/schedule/schedule-store.ts +166 -83
- package/src/schedule/scheduler.ts +26 -22
- package/src/security/encrypted-store.ts +68 -38
- package/src/security/keychain.ts +183 -120
- package/src/security/oauth-callback-registry.ts +3 -3
- package/src/security/oauth2.ts +226 -138
- package/src/security/redaction.ts +24 -24
- package/src/security/secret-allowlist.ts +46 -21
- package/src/security/secret-ingress.ts +15 -7
- package/src/security/secret-scanner.ts +193 -104
- package/src/security/secure-keys.ts +9 -3
- package/src/security/token-manager.ts +99 -40
- package/src/security/tool-approval-digest.ts +3 -3
- package/src/sequence/analytics.ts +52 -27
- package/src/sequence/engine.ts +135 -72
- package/src/sequence/guardrails.ts +32 -20
- package/src/sequence/importer.ts +75 -37
- package/src/sequence/reply-matcher.ts +36 -18
- package/src/sequence/store.ts +137 -75
- package/src/sequence/types.ts +30 -16
- package/src/services/published-app-updater.ts +26 -16
- package/src/services/vercel-deploy.ts +19 -15
- package/src/skills/active-skill-tools.ts +3 -3
- package/src/skills/clawhub.ts +178 -90
- package/src/skills/include-graph.ts +24 -17
- package/src/skills/managed-store.ts +89 -42
- package/src/skills/path-classifier.ts +10 -10
- package/src/skills/remote-skill-policy.ts +31 -22
- package/src/skills/slash-commands.ts +36 -30
- package/src/skills/tool-manifest.ts +60 -31
- package/src/skills/version-hash.ts +25 -15
- package/src/slack/slack-webhook.ts +19 -15
- package/src/subagent/index.ts +4 -8
- package/src/subagent/manager.ts +119 -69
- package/src/subagent/types.ts +9 -12
- package/src/swarm/backend-claude-code.ts +124 -45
- package/src/swarm/checkpoint.ts +36 -16
- package/src/swarm/graph-utils.ts +1 -3
- package/src/swarm/index.ts +38 -19
- package/src/swarm/limits.ts +13 -4
- package/src/swarm/orchestrator.ts +108 -57
- package/src/swarm/plan-validator.ts +23 -17
- package/src/swarm/router-planner.ts +51 -22
- package/src/swarm/router-prompts.ts +4 -1
- package/src/swarm/synthesizer.ts +26 -18
- package/src/swarm/types.ts +14 -4
- package/src/swarm/worker-backend.ts +36 -26
- package/src/swarm/worker-prompts.ts +13 -9
- package/src/swarm/worker-runner.ts +40 -34
- package/src/tasks/candidate-store.ts +14 -6
- package/src/tasks/ephemeral-permissions.ts +9 -5
- package/src/tasks/task-compiler.ts +41 -38
- package/src/tasks/task-runner.ts +54 -26
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/task-store.ts +20 -7
- package/src/tasks/tool-sanitizer.ts +3 -3
- package/src/tools/apps/definitions.ts +23 -15
- package/src/tools/apps/executors.ts +118 -37
- package/src/tools/apps/open-proxy.ts +5 -5
- package/src/tools/apps/registry.ts +2 -2
- package/src/tools/assets/materialize.ts +59 -41
- package/src/tools/assets/search.ts +86 -48
- package/src/tools/browser/api-map.ts +52 -36
- package/src/tools/browser/auth-cache.ts +21 -18
- package/src/tools/browser/auth-detector.ts +43 -28
- package/src/tools/browser/auto-navigate.ts +149 -68
- package/src/tools/browser/browser-execution.ts +9 -3
- package/src/tools/browser/headless-browser.ts +287 -150
- package/src/tools/browser/jit-auth.ts +37 -21
- package/src/tools/browser/network-recorder.ts +138 -56
- package/src/tools/browser/recording-store.ts +22 -15
- package/src/tools/browser/runtime-check.ts +8 -5
- package/src/tools/browser/x-auto-navigate.ts +88 -47
- package/src/tools/calls/call-end.ts +9 -6
- package/src/tools/calls/call-start.ts +30 -20
- package/src/tools/calls/call-status.ts +8 -5
- package/src/tools/claude-code/claude-code.ts +301 -165
- package/src/tools/computer-use/definitions.ts +159 -130
- package/src/tools/computer-use/registry.ts +2 -2
- package/src/tools/computer-use/request-computer-control.ts +21 -13
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/credentials/account-registry.ts +52 -35
- package/src/tools/credentials/broker-types.ts +1 -1
- package/src/tools/credentials/broker.ts +97 -55
- package/src/tools/credentials/domain-policy.ts +5 -2
- package/src/tools/credentials/host-pattern-match.ts +15 -8
- package/src/tools/credentials/metadata-store.ts +93 -43
- package/src/tools/credentials/policy-types.ts +5 -2
- package/src/tools/credentials/policy-validate.ts +21 -14
- package/src/tools/credentials/post-connect-hooks.ts +18 -7
- package/src/tools/credentials/resolve.ts +11 -10
- package/src/tools/credentials/selection.ts +30 -25
- package/src/tools/credentials/tool-policy.ts +5 -2
- package/src/tools/credentials/vault.ts +452 -183
- package/src/tools/document/document-tool.ts +23 -17
- package/src/tools/document/editor-template.ts +12 -7
- package/src/tools/execution-target.ts +13 -10
- package/src/tools/execution-timeout.ts +6 -5
- package/src/tools/executor.ts +141 -74
- package/src/tools/filesystem/edit.ts +82 -45
- package/src/tools/filesystem/fuzzy-match.ts +70 -32
- package/src/tools/filesystem/read.ts +46 -28
- package/src/tools/filesystem/view-image.ts +86 -42
- package/src/tools/filesystem/write.ts +53 -32
- package/src/tools/followups/followup_create.ts +43 -17
- package/src/tools/followups/followup_list.ts +28 -13
- package/src/tools/followups/followup_resolve.ts +9 -6
- package/src/tools/guardian-control-plane-policy.ts +15 -14
- package/src/tools/host-filesystem/edit.ts +77 -42
- package/src/tools/host-filesystem/read.ts +52 -33
- package/src/tools/host-filesystem/write.ts +50 -29
- package/src/tools/host-terminal/host-shell.ts +97 -61
- package/src/tools/mcp/mcp-tool-factory.ts +21 -14
- package/src/tools/memory/definitions.ts +60 -28
- package/src/tools/memory/handlers.ts +149 -77
- package/src/tools/memory/register.ts +39 -16
- package/src/tools/network/__tests__/web-search.test.ts +236 -177
- package/src/tools/network/domain-normalize.ts +13 -9
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
- package/src/tools/network/script-proxy/index.ts +1 -17
- package/src/tools/network/script-proxy/session-manager.ts +151 -84
- package/src/tools/network/url-safety.ts +56 -34
- package/src/tools/network/web-fetch.ts +273 -155
- package/src/tools/network/web-search.ts +166 -81
- package/src/tools/permission-checker.ts +6 -25
- package/src/tools/policy-context.ts +8 -5
- package/src/tools/registry.ts +73 -46
- package/src/tools/reminder/reminder-store.ts +65 -44
- package/src/tools/reminder/reminder.ts +76 -35
- package/src/tools/schedule/create.ts +44 -21
- package/src/tools/schedule/delete.ts +8 -5
- package/src/tools/schedule/list.ts +39 -19
- package/src/tools/schedule/update.ts +49 -26
- package/src/tools/secret-detection-handler.ts +130 -49
- package/src/tools/sensitive-output-placeholders.ts +15 -8
- package/src/tools/shared/filesystem/edit-engine.ts +45 -14
- package/src/tools/shared/filesystem/errors.ts +18 -18
- package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
- package/src/tools/shared/filesystem/format-diff.ts +21 -11
- package/src/tools/shared/filesystem/path-policy.ts +17 -13
- package/src/tools/shared/filesystem/size-guard.ts +8 -4
- package/src/tools/shared/filesystem/types.ts +2 -2
- package/src/tools/shared/shell-output.ts +4 -3
- package/src/tools/side-effects.ts +36 -28
- package/src/tools/skills/delete-managed.ts +30 -17
- package/src/tools/skills/load.ts +88 -46
- package/src/tools/skills/sandbox-runner.ts +62 -46
- package/src/tools/skills/scaffold-managed.ts +98 -48
- package/src/tools/skills/script-contract.ts +5 -2
- package/src/tools/skills/skill-script-runner.ts +29 -13
- package/src/tools/skills/skill-tool-factory.ts +20 -10
- package/src/tools/subagent/abort.ts +10 -4
- package/src/tools/subagent/message.ts +14 -8
- package/src/tools/subagent/read.ts +20 -11
- package/src/tools/subagent/spawn.ts +14 -6
- package/src/tools/subagent/status.ts +7 -4
- package/src/tools/swarm/delegate.ts +75 -49
- package/src/tools/system/avatar-generator.ts +46 -33
- package/src/tools/system/navigate-settings.ts +29 -19
- package/src/tools/system/open-system-settings.ts +30 -20
- package/src/tools/system/request-permission.ts +59 -44
- package/src/tools/system/version.ts +27 -16
- package/src/tools/system/voice-config.ts +116 -53
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +61 -22
- package/src/tools/tasks/task-list.ts +23 -11
- package/src/tools/tasks/task-run.ts +41 -16
- package/src/tools/tasks/task-save.ts +27 -10
- package/src/tools/tasks/work-item-enqueue.ts +114 -48
- package/src/tools/tasks/work-item-list.ts +20 -10
- package/src/tools/tasks/work-item-remove.ts +49 -15
- package/src/tools/tasks/work-item-run.ts +34 -13
- package/src/tools/tasks/work-item-update.ts +84 -31
- package/src/tools/terminal/backends/native.ts +64 -35
- package/src/tools/terminal/backends/types.ts +6 -2
- package/src/tools/terminal/parser.ts +200 -125
- package/src/tools/terminal/safe-env.ts +27 -21
- package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
- package/src/tools/terminal/sandbox.ts +10 -6
- package/src/tools/terminal/shell.ts +124 -68
- package/src/tools/tool-approval-handler.ts +193 -138
- package/src/tools/types.ts +43 -23
- package/src/tools/ui-surface/definitions.ts +124 -89
- package/src/tools/ui-surface/registry.ts +2 -2
- package/src/tools/watch/screen-watch.ts +50 -32
- package/src/tools/watch/watch-state.ts +41 -15
- package/src/tools/watcher/create.ts +37 -15
- package/src/tools/watcher/delete.ts +9 -6
- package/src/tools/watcher/digest.ts +10 -6
- package/src/tools/watcher/list.ts +37 -14
- package/src/tools/watcher/update.ts +33 -18
- package/src/tools/weather/service.ts +331 -174
- package/src/twitter/client.ts +261 -138
- package/src/twitter/oauth-client.ts +17 -13
- package/src/twitter/router.ts +51 -23
- package/src/twitter/session.ts +27 -18
- package/src/types/qrcode.d.ts +6 -3
- package/src/usage/actors.ts +16 -16
- package/src/usage/types.ts +3 -3
- package/src/util/bundled-asset.ts +10 -6
- package/src/util/canonicalize-identity.ts +11 -4
- package/src/util/clipboard.ts +7 -7
- package/src/util/content-id.ts +3 -3
- package/src/util/debounce.ts +3 -2
- package/src/util/diff.ts +55 -33
- package/src/util/errors.ts +26 -26
- package/src/util/fs.ts +8 -2
- package/src/util/log-redact.ts +12 -12
- package/src/util/logger.ts +112 -51
- package/src/util/network-info.ts +13 -5
- package/src/util/object.ts +4 -2
- package/src/util/phone.ts +4 -4
- package/src/util/platform.ts +80 -58
- package/src/util/pricing.ts +49 -31
- package/src/util/retry.ts +18 -7
- package/src/util/row-mapper.ts +7 -4
- package/src/util/silently.ts +7 -4
- package/src/util/spawn.ts +48 -0
- package/src/util/spinner.ts +9 -7
- package/src/util/time.ts +16 -3
- package/src/util/truncate.ts +1 -1
- package/src/util/voice-code.ts +6 -4
- package/src/util/xml.ts +5 -1
- package/src/version.ts +12 -8
- package/src/watcher/engine.ts +71 -44
- package/src/watcher/provider-registry.ts +1 -1
- package/src/watcher/providers/github.ts +40 -23
- package/src/watcher/providers/gmail.ts +59 -38
- package/src/watcher/providers/google-calendar.ts +62 -48
- package/src/watcher/providers/linear.ts +219 -150
- package/src/watcher/providers/slack.ts +93 -27
- package/src/watcher/watcher-store.ts +75 -55
- package/src/work-items/work-item-runner.ts +62 -29
- package/src/work-items/work-item-store.ts +137 -47
- package/src/workspace/commit-message-enrichment-service.ts +65 -25
- package/src/workspace/commit-message-provider.ts +14 -12
- package/src/workspace/git-service.ts +355 -239
- package/src/workspace/heartbeat-service.ts +74 -37
- package/src/workspace/provider-commit-message-generator.ts +95 -70
- package/src/workspace/top-level-renderer.ts +10 -8
- package/src/workspace/top-level-scanner.ts +9 -3
- package/src/workspace/turn-commit.ts +63 -36
- package/src/__tests__/ingress-member-store.test.ts +0 -294
- package/src/__tests__/script-proxy-router.test.ts +0 -215
- package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
- package/src/memory/guardian-bindings.ts +0 -158
- package/src/memory/ingress-member-store.ts +0 -352
- package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
- package/src/tools/network/script-proxy/certs.ts +0 -7
- package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
- package/src/tools/network/script-proxy/logging.ts +0 -12
- package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
- package/src/tools/network/script-proxy/policy.ts +0 -4
- package/src/tools/network/script-proxy/router.ts +0 -2
- package/src/tools/network/script-proxy/server.ts +0 -5
- package/src/tools/network/script-proxy/types.ts +0 -19
|
@@ -1,34 +1,56 @@
|
|
|
1
|
-
import * as net from
|
|
1
|
+
import * as net from "node:net";
|
|
2
2
|
|
|
3
|
-
import { v4 as uuid } from
|
|
3
|
+
import { v4 as uuid } from "uuid";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import {
|
|
6
|
+
createAssistantMessage,
|
|
7
|
+
createUserMessage,
|
|
8
|
+
} from "../../agent/message-types.js";
|
|
9
|
+
import {
|
|
10
|
+
type InterfaceId,
|
|
11
|
+
isChannelId,
|
|
12
|
+
parseChannelId,
|
|
13
|
+
parseInterfaceId,
|
|
14
|
+
} from "../../channels/types.js";
|
|
15
|
+
import { getConfig } from "../../config/loader.js";
|
|
16
|
+
import {
|
|
17
|
+
getAttachmentsForMessage,
|
|
18
|
+
getFilePathForAttachment,
|
|
19
|
+
setAttachmentThumbnail,
|
|
20
|
+
} from "../../memory/attachments-store.js";
|
|
9
21
|
import {
|
|
10
22
|
createCanonicalGuardianRequest,
|
|
11
23
|
generateCanonicalRequestCode,
|
|
12
24
|
listCanonicalGuardianRequests,
|
|
13
25
|
listPendingCanonicalGuardianRequestsByDestinationConversation,
|
|
14
26
|
resolveCanonicalGuardianRequest,
|
|
15
|
-
} from
|
|
16
|
-
import { getAttentionStateByConversationIds } from
|
|
17
|
-
import * as conversationStore from
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import * as
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import
|
|
31
|
-
import
|
|
27
|
+
} from "../../memory/canonical-guardian-store.js";
|
|
28
|
+
import { getAttentionStateByConversationIds } from "../../memory/conversation-attention-store.js";
|
|
29
|
+
import * as conversationStore from "../../memory/conversation-store.js";
|
|
30
|
+
import {
|
|
31
|
+
GENERATING_TITLE,
|
|
32
|
+
queueGenerateConversationTitle,
|
|
33
|
+
UNTITLED_FALLBACK,
|
|
34
|
+
} from "../../memory/conversation-title-service.js";
|
|
35
|
+
import * as externalConversationStore from "../../memory/external-conversation-store.js";
|
|
36
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
|
|
37
|
+
import { routeGuardianReply } from "../../runtime/guardian-reply-router.js";
|
|
38
|
+
import {
|
|
39
|
+
resolveLocalIpcAuthContext,
|
|
40
|
+
resolveLocalIpcTrustContext,
|
|
41
|
+
} from "../../runtime/local-actor-identity.js";
|
|
42
|
+
import * as pendingInteractions from "../../runtime/pending-interactions.js";
|
|
43
|
+
import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
44
|
+
import {
|
|
45
|
+
compileCustomPatterns,
|
|
46
|
+
redactSecrets,
|
|
47
|
+
} from "../../security/secret-scanner.js";
|
|
48
|
+
import { getSubagentManager } from "../../subagent/index.js";
|
|
49
|
+
import { silentlyWithLog } from "../../util/silently.js";
|
|
50
|
+
import { truncate } from "../../util/truncate.js";
|
|
51
|
+
import { createApprovalConversationGenerator } from "../approval-generators.js";
|
|
52
|
+
import { getAssistantName } from "../identity-helpers.js";
|
|
53
|
+
import type { UserMessageAttachment } from "../ipc-contract.js";
|
|
32
54
|
import type {
|
|
33
55
|
CancelRequest,
|
|
34
56
|
ConfirmationResponse,
|
|
@@ -47,16 +69,28 @@ import type {
|
|
|
47
69
|
UndoRequest,
|
|
48
70
|
UsageRequest,
|
|
49
71
|
UserMessage,
|
|
50
|
-
} from
|
|
51
|
-
import { normalizeThreadType } from
|
|
52
|
-
import { executeRecordingIntent } from
|
|
53
|
-
import { resolveRecordingIntent } from
|
|
54
|
-
import {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
72
|
+
} from "../ipc-protocol.js";
|
|
73
|
+
import { normalizeThreadType } from "../ipc-protocol.js";
|
|
74
|
+
import { executeRecordingIntent } from "../recording-executor.js";
|
|
75
|
+
import { resolveRecordingIntent } from "../recording-intent.js";
|
|
76
|
+
import {
|
|
77
|
+
classifyRecordingIntentFallback,
|
|
78
|
+
containsRecordingKeywords,
|
|
79
|
+
} from "../recording-intent-fallback.js";
|
|
80
|
+
import type { Session } from "../session.js";
|
|
81
|
+
import {
|
|
82
|
+
buildSessionErrorMessage,
|
|
83
|
+
classifySessionError,
|
|
84
|
+
} from "../session-error.js";
|
|
85
|
+
import { resolveChannelCapabilities } from "../session-runtime-assembly.js";
|
|
86
|
+
import { generateVideoThumbnail } from "../video-thumbnail.js";
|
|
87
|
+
import {
|
|
88
|
+
handleRecordingPause,
|
|
89
|
+
handleRecordingRestart,
|
|
90
|
+
handleRecordingResume,
|
|
91
|
+
handleRecordingStart,
|
|
92
|
+
handleRecordingStop,
|
|
93
|
+
} from "./recording.js";
|
|
60
94
|
import {
|
|
61
95
|
defineHandlers,
|
|
62
96
|
type HandlerContext,
|
|
@@ -68,24 +102,28 @@ import {
|
|
|
68
102
|
pendingStandaloneSecrets,
|
|
69
103
|
renderHistoryContent,
|
|
70
104
|
wireEscalationHandler,
|
|
71
|
-
} from
|
|
105
|
+
} from "./shared.js";
|
|
72
106
|
|
|
73
|
-
const desktopApprovalConversationGenerator =
|
|
107
|
+
const desktopApprovalConversationGenerator =
|
|
108
|
+
createApprovalConversationGenerator();
|
|
74
109
|
|
|
75
110
|
function syncCanonicalStatusFromIpcConfirmationDecision(
|
|
76
111
|
requestId: string,
|
|
77
|
-
decision: ConfirmationResponse[
|
|
112
|
+
decision: ConfirmationResponse["decision"],
|
|
78
113
|
): void {
|
|
79
|
-
const targetStatus =
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
const targetStatus =
|
|
115
|
+
decision === "deny" || decision === "always_deny"
|
|
116
|
+
? ("denied" as const)
|
|
117
|
+
: ("approved" as const);
|
|
82
118
|
|
|
83
119
|
try {
|
|
84
|
-
resolveCanonicalGuardianRequest(requestId,
|
|
120
|
+
resolveCanonicalGuardianRequest(requestId, "pending", {
|
|
121
|
+
status: targetStatus,
|
|
122
|
+
});
|
|
85
123
|
} catch (err) {
|
|
86
124
|
log.debug(
|
|
87
125
|
{ err, requestId, targetStatus },
|
|
88
|
-
|
|
126
|
+
"Failed to resolve canonical request from IPC confirmation response",
|
|
89
127
|
);
|
|
90
128
|
}
|
|
91
129
|
}
|
|
@@ -97,20 +135,14 @@ function makeIpcEventSender(params: {
|
|
|
97
135
|
conversationId: string;
|
|
98
136
|
sourceChannel: string;
|
|
99
137
|
}): (event: ServerMessage) => void {
|
|
100
|
-
const {
|
|
101
|
-
ctx,
|
|
102
|
-
socket,
|
|
103
|
-
session,
|
|
104
|
-
conversationId,
|
|
105
|
-
sourceChannel,
|
|
106
|
-
} = params;
|
|
138
|
+
const { ctx, socket, session, conversationId, sourceChannel } = params;
|
|
107
139
|
|
|
108
140
|
return (event: ServerMessage) => {
|
|
109
|
-
if (event.type ===
|
|
141
|
+
if (event.type === "confirmation_request") {
|
|
110
142
|
pendingInteractions.register(event.requestId, {
|
|
111
143
|
session,
|
|
112
144
|
conversationId,
|
|
113
|
-
kind:
|
|
145
|
+
kind: "confirmation",
|
|
114
146
|
confirmationDetails: {
|
|
115
147
|
toolName: event.toolName,
|
|
116
148
|
input: event.input,
|
|
@@ -124,30 +156,30 @@ function makeIpcEventSender(params: {
|
|
|
124
156
|
});
|
|
125
157
|
|
|
126
158
|
try {
|
|
127
|
-
const
|
|
159
|
+
const trustContext = session.trustContext;
|
|
128
160
|
createCanonicalGuardianRequest({
|
|
129
161
|
id: event.requestId,
|
|
130
|
-
kind:
|
|
131
|
-
sourceType:
|
|
162
|
+
kind: "tool_approval",
|
|
163
|
+
sourceType: "desktop",
|
|
132
164
|
sourceChannel,
|
|
133
165
|
conversationId,
|
|
134
|
-
guardianPrincipalId:
|
|
166
|
+
guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
|
|
135
167
|
toolName: event.toolName,
|
|
136
|
-
status:
|
|
168
|
+
status: "pending",
|
|
137
169
|
requestCode: generateCanonicalRequestCode(),
|
|
138
170
|
expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
|
|
139
171
|
});
|
|
140
172
|
} catch (err) {
|
|
141
173
|
log.debug(
|
|
142
174
|
{ err, requestId: event.requestId, conversationId },
|
|
143
|
-
|
|
175
|
+
"Failed to create canonical request from IPC confirmation event",
|
|
144
176
|
);
|
|
145
177
|
}
|
|
146
|
-
} else if (event.type ===
|
|
178
|
+
} else if (event.type === "secret_request") {
|
|
147
179
|
pendingInteractions.register(event.requestId, {
|
|
148
180
|
session,
|
|
149
181
|
conversationId,
|
|
150
|
-
kind:
|
|
182
|
+
kind: "secret",
|
|
151
183
|
});
|
|
152
184
|
}
|
|
153
185
|
|
|
@@ -172,7 +204,7 @@ export async function handleUserMessage(
|
|
|
172
204
|
wireEscalationHandler(session, socket, ctx);
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
const ipcChannel = parseChannelId(msg.channel) ??
|
|
207
|
+
const ipcChannel = parseChannelId(msg.channel) ?? "vellum";
|
|
176
208
|
const sendEvent = makeIpcEventSender({
|
|
177
209
|
ctx,
|
|
178
210
|
socket,
|
|
@@ -187,8 +219,9 @@ export async function handleUserMessage(
|
|
|
187
219
|
const ipcInterface = parseInterfaceId(msg.interface);
|
|
188
220
|
if (!ipcInterface) {
|
|
189
221
|
ctx.send(socket, {
|
|
190
|
-
type:
|
|
191
|
-
message:
|
|
222
|
+
type: "error",
|
|
223
|
+
message:
|
|
224
|
+
"Invalid user_message: interface is required and must be valid",
|
|
192
225
|
});
|
|
193
226
|
return;
|
|
194
227
|
}
|
|
@@ -201,30 +234,34 @@ export async function handleUserMessage(
|
|
|
201
234
|
|
|
202
235
|
// Update channel capabilities eagerly so both immediate and queued paths
|
|
203
236
|
// reflect the latest PTT / microphone state from the client.
|
|
204
|
-
session.setChannelCapabilities(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
237
|
+
session.setChannelCapabilities(
|
|
238
|
+
resolveChannelCapabilities(ipcChannel, ipcInterface, {
|
|
239
|
+
pttActivationKey: msg.pttActivationKey,
|
|
240
|
+
microphonePermissionGranted: msg.microphonePermissionGranted,
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
208
243
|
|
|
209
244
|
const dispatchUserMessage = (
|
|
210
245
|
content: string,
|
|
211
246
|
attachments: UserMessageAttachment[],
|
|
212
247
|
dispatchRequestId: string,
|
|
213
|
-
source:
|
|
248
|
+
source: "user_message" | "secure_redirect_resume",
|
|
214
249
|
activeSurfaceId?: string,
|
|
215
250
|
currentPage?: string,
|
|
216
251
|
displayContent?: string,
|
|
217
252
|
): void => {
|
|
218
|
-
const receivedDescription =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
253
|
+
const receivedDescription =
|
|
254
|
+
source === "user_message"
|
|
255
|
+
? "User message received"
|
|
256
|
+
: "Resuming message after secure credential save";
|
|
257
|
+
const queuedDescription =
|
|
258
|
+
source === "user_message"
|
|
259
|
+
? "Message queued (session busy)"
|
|
260
|
+
: "Resumed message queued (session busy)";
|
|
261
|
+
|
|
262
|
+
session.traceEmitter.emit("request_received", receivedDescription, {
|
|
226
263
|
requestId: dispatchRequestId,
|
|
227
|
-
status:
|
|
264
|
+
status: "info",
|
|
228
265
|
attributes: { source },
|
|
229
266
|
});
|
|
230
267
|
|
|
@@ -240,30 +277,46 @@ export async function handleUserMessage(
|
|
|
240
277
|
displayContent,
|
|
241
278
|
);
|
|
242
279
|
if (result.rejected) {
|
|
243
|
-
rlog.warn({ source },
|
|
244
|
-
session.traceEmitter.emit(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
280
|
+
rlog.warn({ source }, "Message rejected — queue is full");
|
|
281
|
+
session.traceEmitter.emit(
|
|
282
|
+
"request_error",
|
|
283
|
+
"Message rejected — queue is full",
|
|
284
|
+
{
|
|
285
|
+
requestId: dispatchRequestId,
|
|
286
|
+
status: "error",
|
|
287
|
+
attributes: {
|
|
288
|
+
reason: "queue_full",
|
|
289
|
+
queueDepth: session.getQueueDepth(),
|
|
290
|
+
source,
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
ctx.send(
|
|
295
|
+
socket,
|
|
296
|
+
buildSessionErrorMessage(msg.sessionId, {
|
|
297
|
+
code: "QUEUE_FULL",
|
|
298
|
+
userMessage:
|
|
299
|
+
"Message queue is full (max depth: 10). Please wait for current messages to be processed.",
|
|
300
|
+
retryable: true,
|
|
301
|
+
debugDetails: "Message rejected — session queue is full",
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
255
304
|
return;
|
|
256
305
|
}
|
|
257
306
|
if (result.queued) {
|
|
258
307
|
const position = session.getQueueDepth();
|
|
259
308
|
rlog.info({ source, position }, queuedDescription);
|
|
260
|
-
session.traceEmitter.emit(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
309
|
+
session.traceEmitter.emit(
|
|
310
|
+
"request_queued",
|
|
311
|
+
`Message queued at position ${position}`,
|
|
312
|
+
{
|
|
313
|
+
requestId: dispatchRequestId,
|
|
314
|
+
status: "info",
|
|
315
|
+
attributes: { position, source },
|
|
316
|
+
},
|
|
317
|
+
);
|
|
265
318
|
ctx.send(socket, {
|
|
266
|
-
type:
|
|
319
|
+
type: "message_queued",
|
|
267
320
|
sessionId: msg.sessionId,
|
|
268
321
|
requestId: dispatchRequestId,
|
|
269
322
|
position,
|
|
@@ -271,8 +324,13 @@ export async function handleUserMessage(
|
|
|
271
324
|
return;
|
|
272
325
|
}
|
|
273
326
|
|
|
274
|
-
rlog.info({ source },
|
|
275
|
-
session.emitActivityState(
|
|
327
|
+
rlog.info({ source }, "Processing user message");
|
|
328
|
+
session.emitActivityState(
|
|
329
|
+
"thinking",
|
|
330
|
+
"message_dequeued",
|
|
331
|
+
"assistant_turn",
|
|
332
|
+
dispatchRequestId,
|
|
333
|
+
);
|
|
276
334
|
session.setTurnChannelContext({
|
|
277
335
|
userMessageChannel: ipcChannel,
|
|
278
336
|
assistantMessageChannel: ipcChannel,
|
|
@@ -284,45 +342,69 @@ export async function handleUserMessage(
|
|
|
284
342
|
session.setAssistantId(DAEMON_INTERNAL_ASSISTANT_ID);
|
|
285
343
|
// Resolve local IPC actor identity through the same trust pipeline
|
|
286
344
|
// used by HTTP channel ingress. The vellum guardian binding provides
|
|
287
|
-
// the guardianPrincipalId, and
|
|
345
|
+
// the guardianPrincipalId, and resolveTrustContext classifies the
|
|
288
346
|
// local user as 'guardian' via binding match.
|
|
289
|
-
session.
|
|
347
|
+
session.setTrustContext(resolveLocalIpcTrustContext(ipcChannel));
|
|
290
348
|
// Align IPC sessions with the same AuthContext shape as HTTP sessions.
|
|
291
349
|
session.setAuthContext(resolveLocalIpcAuthContext(msg.sessionId));
|
|
292
350
|
session.setCommandIntent(null);
|
|
293
351
|
// Fire-and-forget: don't block the IPC handler so the connection can
|
|
294
352
|
// continue receiving messages (e.g. cancel, confirmations, or
|
|
295
353
|
// additional user_message that will be queued by the session).
|
|
296
|
-
session
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
354
|
+
session
|
|
355
|
+
.processMessage(
|
|
356
|
+
content,
|
|
357
|
+
attachments,
|
|
358
|
+
sendEvent,
|
|
359
|
+
dispatchRequestId,
|
|
360
|
+
activeSurfaceId,
|
|
361
|
+
currentPage,
|
|
362
|
+
undefined,
|
|
363
|
+
displayContent,
|
|
364
|
+
)
|
|
365
|
+
.catch((err) => {
|
|
366
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
367
|
+
rlog.error(
|
|
368
|
+
{ err, source },
|
|
369
|
+
"Error processing user message (session or provider failure)",
|
|
370
|
+
);
|
|
371
|
+
ctx.send(socket, {
|
|
372
|
+
type: "error",
|
|
373
|
+
message: `Failed to process message: ${message}`,
|
|
374
|
+
});
|
|
375
|
+
const classified = classifySessionError(err, { phase: "agent_loop" });
|
|
376
|
+
ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
|
|
377
|
+
});
|
|
303
378
|
};
|
|
304
379
|
|
|
305
380
|
const config = getConfig();
|
|
306
|
-
let messageText = msg.content ??
|
|
381
|
+
let messageText = msg.content ?? "";
|
|
307
382
|
|
|
308
383
|
// Block inbound messages that contain secrets and redirect to secure prompt
|
|
309
384
|
if (!msg.bypassSecretCheck) {
|
|
310
385
|
const ingressCheck = checkIngressForSecrets(messageText);
|
|
311
386
|
if (ingressCheck.blocked) {
|
|
312
|
-
rlog.warn(
|
|
387
|
+
rlog.warn(
|
|
388
|
+
{ detectedTypes: ingressCheck.detectedTypes },
|
|
389
|
+
"Blocked user message containing secrets",
|
|
390
|
+
);
|
|
313
391
|
ctx.send(socket, {
|
|
314
|
-
type:
|
|
392
|
+
type: "error",
|
|
315
393
|
message: ingressCheck.userNotice!,
|
|
316
|
-
category:
|
|
394
|
+
category: "secret_blocked",
|
|
317
395
|
});
|
|
318
396
|
|
|
319
397
|
const compiledCustom = config.secretDetection.customPatterns?.length
|
|
320
398
|
? compileCustomPatterns(config.secretDetection.customPatterns)
|
|
321
399
|
: undefined;
|
|
322
|
-
const redactedMessageText = redactSecrets(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
400
|
+
const redactedMessageText = redactSecrets(
|
|
401
|
+
messageText,
|
|
402
|
+
{
|
|
403
|
+
enabled: true,
|
|
404
|
+
base64Threshold: config.secretDetection.entropyThreshold,
|
|
405
|
+
},
|
|
406
|
+
compiledCustom,
|
|
407
|
+
).trim();
|
|
326
408
|
|
|
327
409
|
// Redirect: trigger a secure prompt so the user can enter the secret safely.
|
|
328
410
|
// After save, continue the same request with redacted text so the model keeps
|
|
@@ -330,25 +412,29 @@ export async function handleUserMessage(
|
|
|
330
412
|
session.redirectToSecurePrompt(ingressCheck.detectedTypes, {
|
|
331
413
|
onStored: (record) => {
|
|
332
414
|
ctx.send(socket, {
|
|
333
|
-
type:
|
|
415
|
+
type: "assistant_text_delta",
|
|
416
|
+
sessionId: msg.sessionId,
|
|
417
|
+
text: "Saved your secret securely. Continuing with your request.",
|
|
418
|
+
});
|
|
419
|
+
ctx.send(socket, {
|
|
420
|
+
type: "message_complete",
|
|
334
421
|
sessionId: msg.sessionId,
|
|
335
|
-
text: 'Saved your secret securely. Continuing with your request.',
|
|
336
422
|
});
|
|
337
|
-
ctx.send(socket, { type: 'message_complete', sessionId: msg.sessionId });
|
|
338
423
|
|
|
339
424
|
const continuationParts: string[] = [];
|
|
340
|
-
if (redactedMessageText.length > 0)
|
|
425
|
+
if (redactedMessageText.length > 0)
|
|
426
|
+
continuationParts.push(redactedMessageText);
|
|
341
427
|
continuationParts.push(
|
|
342
428
|
`I entered the redacted secret via the Secure Credential UI and saved it as credential ${record.service}/${record.field}. ` +
|
|
343
|
-
|
|
429
|
+
"Continue with my request using that stored credential and do not ask me to paste the secret again.",
|
|
344
430
|
);
|
|
345
|
-
const continuationMessage = continuationParts.join(
|
|
431
|
+
const continuationMessage = continuationParts.join("\n\n");
|
|
346
432
|
const continuationRequestId = uuid();
|
|
347
433
|
dispatchUserMessage(
|
|
348
434
|
continuationMessage,
|
|
349
435
|
msg.attachments ?? [],
|
|
350
436
|
continuationRequestId,
|
|
351
|
-
|
|
437
|
+
"secure_redirect_resume",
|
|
352
438
|
msg.activeSurfaceId,
|
|
353
439
|
msg.currentPage,
|
|
354
440
|
);
|
|
@@ -359,94 +445,205 @@ export async function handleUserMessage(
|
|
|
359
445
|
}
|
|
360
446
|
|
|
361
447
|
// ── Structured command intent (bypasses text parsing) ──────────────────
|
|
362
|
-
if (
|
|
448
|
+
if (
|
|
449
|
+
config.daemon.standaloneRecording &&
|
|
450
|
+
msg.commandIntent?.domain === "screen_recording"
|
|
451
|
+
) {
|
|
363
452
|
const action = msg.commandIntent.action;
|
|
364
|
-
rlog.info(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
453
|
+
rlog.info(
|
|
454
|
+
{ action, source: "commandIntent" },
|
|
455
|
+
"Recording command intent received in user_message",
|
|
456
|
+
);
|
|
457
|
+
if (action === "start") {
|
|
458
|
+
const recordingId = handleRecordingStart(
|
|
459
|
+
msg.sessionId,
|
|
460
|
+
{ promptForSource: true },
|
|
461
|
+
socket,
|
|
462
|
+
ctx,
|
|
463
|
+
);
|
|
464
|
+
const responseText = recordingId
|
|
465
|
+
? "Starting screen recording."
|
|
466
|
+
: "A recording is already active.";
|
|
368
467
|
ctx.send(socket, {
|
|
369
|
-
type:
|
|
468
|
+
type: "assistant_text_delta",
|
|
370
469
|
text: responseText,
|
|
371
470
|
sessionId: msg.sessionId,
|
|
372
471
|
});
|
|
373
|
-
ctx.send(socket, {
|
|
374
|
-
|
|
375
|
-
|
|
472
|
+
ctx.send(socket, {
|
|
473
|
+
type: "message_complete",
|
|
474
|
+
sessionId: msg.sessionId,
|
|
475
|
+
});
|
|
476
|
+
await conversationStore.addMessage(
|
|
477
|
+
msg.sessionId,
|
|
478
|
+
"user",
|
|
479
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
480
|
+
);
|
|
481
|
+
await conversationStore.addMessage(
|
|
482
|
+
msg.sessionId,
|
|
483
|
+
"assistant",
|
|
484
|
+
JSON.stringify([{ type: "text", text: responseText }]),
|
|
485
|
+
);
|
|
376
486
|
// Keep in-memory session history aligned with DB so regenerate() and
|
|
377
487
|
// other history operations that rely on session.messages stay consistent.
|
|
378
488
|
// Only push when agent loop is NOT active to avoid corrupting role alternation.
|
|
379
489
|
if (!session.isProcessing()) {
|
|
380
|
-
session.messages.push({
|
|
381
|
-
|
|
490
|
+
session.messages.push({
|
|
491
|
+
role: "user",
|
|
492
|
+
content: [{ type: "text", text: messageText }],
|
|
493
|
+
});
|
|
494
|
+
session.messages.push({
|
|
495
|
+
role: "assistant",
|
|
496
|
+
content: [{ type: "text", text: responseText }],
|
|
497
|
+
});
|
|
382
498
|
}
|
|
383
499
|
return;
|
|
384
|
-
} else if (action ===
|
|
500
|
+
} else if (action === "stop") {
|
|
385
501
|
const stopped = handleRecordingStop(msg.sessionId, ctx) !== undefined;
|
|
386
|
-
const responseText = stopped
|
|
502
|
+
const responseText = stopped
|
|
503
|
+
? "Stopping the recording."
|
|
504
|
+
: "No active recording to stop.";
|
|
387
505
|
ctx.send(socket, {
|
|
388
|
-
type:
|
|
506
|
+
type: "assistant_text_delta",
|
|
389
507
|
text: responseText,
|
|
390
508
|
sessionId: msg.sessionId,
|
|
391
509
|
});
|
|
392
|
-
ctx.send(socket, {
|
|
393
|
-
|
|
394
|
-
|
|
510
|
+
ctx.send(socket, {
|
|
511
|
+
type: "message_complete",
|
|
512
|
+
sessionId: msg.sessionId,
|
|
513
|
+
});
|
|
514
|
+
await conversationStore.addMessage(
|
|
515
|
+
msg.sessionId,
|
|
516
|
+
"user",
|
|
517
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
518
|
+
);
|
|
519
|
+
await conversationStore.addMessage(
|
|
520
|
+
msg.sessionId,
|
|
521
|
+
"assistant",
|
|
522
|
+
JSON.stringify([{ type: "text", text: responseText }]),
|
|
523
|
+
);
|
|
395
524
|
if (!session.isProcessing()) {
|
|
396
|
-
session.messages.push({
|
|
397
|
-
|
|
525
|
+
session.messages.push({
|
|
526
|
+
role: "user",
|
|
527
|
+
content: [{ type: "text", text: messageText }],
|
|
528
|
+
});
|
|
529
|
+
session.messages.push({
|
|
530
|
+
role: "assistant",
|
|
531
|
+
content: [{ type: "text", text: responseText }],
|
|
532
|
+
});
|
|
398
533
|
}
|
|
399
534
|
return;
|
|
400
|
-
} else if (action ===
|
|
401
|
-
const restartResult = handleRecordingRestart(
|
|
535
|
+
} else if (action === "restart") {
|
|
536
|
+
const restartResult = handleRecordingRestart(
|
|
537
|
+
msg.sessionId,
|
|
538
|
+
socket,
|
|
539
|
+
ctx,
|
|
540
|
+
);
|
|
402
541
|
ctx.send(socket, {
|
|
403
|
-
type:
|
|
542
|
+
type: "assistant_text_delta",
|
|
404
543
|
text: restartResult.responseText,
|
|
405
544
|
sessionId: msg.sessionId,
|
|
406
545
|
});
|
|
407
|
-
ctx.send(socket, {
|
|
408
|
-
|
|
409
|
-
|
|
546
|
+
ctx.send(socket, {
|
|
547
|
+
type: "message_complete",
|
|
548
|
+
sessionId: msg.sessionId,
|
|
549
|
+
});
|
|
550
|
+
await conversationStore.addMessage(
|
|
551
|
+
msg.sessionId,
|
|
552
|
+
"user",
|
|
553
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
554
|
+
);
|
|
555
|
+
await conversationStore.addMessage(
|
|
556
|
+
msg.sessionId,
|
|
557
|
+
"assistant",
|
|
558
|
+
JSON.stringify([{ type: "text", text: restartResult.responseText }]),
|
|
559
|
+
);
|
|
410
560
|
if (!session.isProcessing()) {
|
|
411
|
-
session.messages.push({
|
|
412
|
-
|
|
561
|
+
session.messages.push({
|
|
562
|
+
role: "user",
|
|
563
|
+
content: [{ type: "text", text: messageText }],
|
|
564
|
+
});
|
|
565
|
+
session.messages.push({
|
|
566
|
+
role: "assistant",
|
|
567
|
+
content: [{ type: "text", text: restartResult.responseText }],
|
|
568
|
+
});
|
|
413
569
|
}
|
|
414
570
|
return;
|
|
415
|
-
} else if (action ===
|
|
571
|
+
} else if (action === "pause") {
|
|
416
572
|
const paused = handleRecordingPause(msg.sessionId, ctx) !== undefined;
|
|
417
|
-
const responseText = paused
|
|
573
|
+
const responseText = paused
|
|
574
|
+
? "Pausing the recording."
|
|
575
|
+
: "No active recording to pause.";
|
|
418
576
|
ctx.send(socket, {
|
|
419
|
-
type:
|
|
577
|
+
type: "assistant_text_delta",
|
|
420
578
|
text: responseText,
|
|
421
579
|
sessionId: msg.sessionId,
|
|
422
580
|
});
|
|
423
|
-
ctx.send(socket, {
|
|
424
|
-
|
|
425
|
-
|
|
581
|
+
ctx.send(socket, {
|
|
582
|
+
type: "message_complete",
|
|
583
|
+
sessionId: msg.sessionId,
|
|
584
|
+
});
|
|
585
|
+
await conversationStore.addMessage(
|
|
586
|
+
msg.sessionId,
|
|
587
|
+
"user",
|
|
588
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
589
|
+
);
|
|
590
|
+
await conversationStore.addMessage(
|
|
591
|
+
msg.sessionId,
|
|
592
|
+
"assistant",
|
|
593
|
+
JSON.stringify([{ type: "text", text: responseText }]),
|
|
594
|
+
);
|
|
426
595
|
if (!session.isProcessing()) {
|
|
427
|
-
session.messages.push({
|
|
428
|
-
|
|
596
|
+
session.messages.push({
|
|
597
|
+
role: "user",
|
|
598
|
+
content: [{ type: "text", text: messageText }],
|
|
599
|
+
});
|
|
600
|
+
session.messages.push({
|
|
601
|
+
role: "assistant",
|
|
602
|
+
content: [{ type: "text", text: responseText }],
|
|
603
|
+
});
|
|
429
604
|
}
|
|
430
605
|
return;
|
|
431
|
-
} else if (action ===
|
|
606
|
+
} else if (action === "resume") {
|
|
432
607
|
const resumed = handleRecordingResume(msg.sessionId, ctx) !== undefined;
|
|
433
|
-
const responseText = resumed
|
|
608
|
+
const responseText = resumed
|
|
609
|
+
? "Resuming the recording."
|
|
610
|
+
: "No active recording to resume.";
|
|
434
611
|
ctx.send(socket, {
|
|
435
|
-
type:
|
|
612
|
+
type: "assistant_text_delta",
|
|
436
613
|
text: responseText,
|
|
437
614
|
sessionId: msg.sessionId,
|
|
438
615
|
});
|
|
439
|
-
ctx.send(socket, {
|
|
440
|
-
|
|
441
|
-
|
|
616
|
+
ctx.send(socket, {
|
|
617
|
+
type: "message_complete",
|
|
618
|
+
sessionId: msg.sessionId,
|
|
619
|
+
});
|
|
620
|
+
await conversationStore.addMessage(
|
|
621
|
+
msg.sessionId,
|
|
622
|
+
"user",
|
|
623
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
624
|
+
);
|
|
625
|
+
await conversationStore.addMessage(
|
|
626
|
+
msg.sessionId,
|
|
627
|
+
"assistant",
|
|
628
|
+
JSON.stringify([{ type: "text", text: responseText }]),
|
|
629
|
+
);
|
|
442
630
|
if (!session.isProcessing()) {
|
|
443
|
-
session.messages.push({
|
|
444
|
-
|
|
631
|
+
session.messages.push({
|
|
632
|
+
role: "user",
|
|
633
|
+
content: [{ type: "text", text: messageText }],
|
|
634
|
+
});
|
|
635
|
+
session.messages.push({
|
|
636
|
+
role: "assistant",
|
|
637
|
+
content: [{ type: "text", text: responseText }],
|
|
638
|
+
});
|
|
445
639
|
}
|
|
446
640
|
return;
|
|
447
641
|
} else {
|
|
448
642
|
// Unrecognized action — fall through to normal text handling
|
|
449
|
-
rlog.warn(
|
|
643
|
+
rlog.warn(
|
|
644
|
+
{ action, source: "commandIntent" },
|
|
645
|
+
"Unrecognized screen_recording action, falling through to text handling",
|
|
646
|
+
);
|
|
450
647
|
}
|
|
451
648
|
}
|
|
452
649
|
|
|
@@ -457,10 +654,14 @@ export async function handleUserMessage(
|
|
|
457
654
|
const dynamicNames = [name].filter(Boolean) as string[];
|
|
458
655
|
const intentResult = resolveRecordingIntent(messageText, dynamicNames);
|
|
459
656
|
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
657
|
+
if (
|
|
658
|
+
intentResult.kind === "start_only" ||
|
|
659
|
+
intentResult.kind === "stop_only" ||
|
|
660
|
+
intentResult.kind === "start_and_stop_only" ||
|
|
661
|
+
intentResult.kind === "restart_only" ||
|
|
662
|
+
intentResult.kind === "pause_only" ||
|
|
663
|
+
intentResult.kind === "resume_only"
|
|
664
|
+
) {
|
|
464
665
|
const execResult = executeRecordingIntent(intentResult, {
|
|
465
666
|
conversationId: msg.sessionId,
|
|
466
667
|
socket,
|
|
@@ -468,25 +669,49 @@ export async function handleUserMessage(
|
|
|
468
669
|
});
|
|
469
670
|
|
|
470
671
|
if (execResult.handled) {
|
|
471
|
-
rlog.info(
|
|
672
|
+
rlog.info(
|
|
673
|
+
{ kind: intentResult.kind },
|
|
674
|
+
"Recording intent intercepted in user_message",
|
|
675
|
+
);
|
|
472
676
|
ctx.send(socket, {
|
|
473
|
-
type:
|
|
677
|
+
type: "assistant_text_delta",
|
|
474
678
|
text: execResult.responseText!,
|
|
475
679
|
sessionId: msg.sessionId,
|
|
476
680
|
});
|
|
477
|
-
ctx.send(socket, {
|
|
478
|
-
|
|
479
|
-
|
|
681
|
+
ctx.send(socket, {
|
|
682
|
+
type: "message_complete",
|
|
683
|
+
sessionId: msg.sessionId,
|
|
684
|
+
});
|
|
685
|
+
await conversationStore.addMessage(
|
|
686
|
+
msg.sessionId,
|
|
687
|
+
"user",
|
|
688
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
689
|
+
);
|
|
690
|
+
await conversationStore.addMessage(
|
|
691
|
+
msg.sessionId,
|
|
692
|
+
"assistant",
|
|
693
|
+
JSON.stringify([{ type: "text", text: execResult.responseText! }]),
|
|
694
|
+
);
|
|
480
695
|
if (!session.isProcessing()) {
|
|
481
|
-
session.messages.push({
|
|
482
|
-
|
|
696
|
+
session.messages.push({
|
|
697
|
+
role: "user",
|
|
698
|
+
content: [{ type: "text", text: messageText }],
|
|
699
|
+
});
|
|
700
|
+
session.messages.push({
|
|
701
|
+
role: "assistant",
|
|
702
|
+
content: [{ type: "text", text: execResult.responseText! }],
|
|
703
|
+
});
|
|
483
704
|
}
|
|
484
705
|
return;
|
|
485
706
|
}
|
|
486
707
|
}
|
|
487
708
|
|
|
488
|
-
if (
|
|
489
|
-
|
|
709
|
+
if (
|
|
710
|
+
intentResult.kind === "start_with_remainder" ||
|
|
711
|
+
intentResult.kind === "stop_with_remainder" ||
|
|
712
|
+
intentResult.kind === "start_and_stop_with_remainder" ||
|
|
713
|
+
intentResult.kind === "restart_with_remainder"
|
|
714
|
+
) {
|
|
490
715
|
const execResult = executeRecordingIntent(intentResult, {
|
|
491
716
|
conversationId: msg.sessionId,
|
|
492
717
|
socket,
|
|
@@ -501,40 +726,75 @@ export async function handleUserMessage(
|
|
|
501
726
|
messageText = msg.content;
|
|
502
727
|
|
|
503
728
|
// Execute the recording side effects that executeRecordingIntent deferred
|
|
504
|
-
if (intentResult.kind ===
|
|
729
|
+
if (intentResult.kind === "stop_with_remainder") {
|
|
505
730
|
handleRecordingStop(msg.sessionId, ctx);
|
|
506
731
|
}
|
|
507
|
-
if (intentResult.kind ===
|
|
508
|
-
handleRecordingStart(
|
|
732
|
+
if (intentResult.kind === "start_with_remainder") {
|
|
733
|
+
handleRecordingStart(
|
|
734
|
+
msg.sessionId,
|
|
735
|
+
{ promptForSource: true },
|
|
736
|
+
socket,
|
|
737
|
+
ctx,
|
|
738
|
+
);
|
|
509
739
|
}
|
|
510
740
|
// start_and_stop_with_remainder / restart_with_remainder — route through
|
|
511
741
|
// handleRecordingRestart which properly cleans up maps between stop and start.
|
|
512
|
-
if (
|
|
513
|
-
|
|
742
|
+
if (
|
|
743
|
+
intentResult.kind === "restart_with_remainder" ||
|
|
744
|
+
intentResult.kind === "start_and_stop_with_remainder"
|
|
745
|
+
) {
|
|
746
|
+
const restartResult = handleRecordingRestart(
|
|
747
|
+
msg.sessionId,
|
|
748
|
+
socket,
|
|
749
|
+
ctx,
|
|
750
|
+
);
|
|
514
751
|
// Only fall back to plain start for start_and_stop_with_remainder.
|
|
515
752
|
// restart_with_remainder should NOT silently start a new recording when idle.
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
|
|
753
|
+
if (
|
|
754
|
+
!restartResult.initiated &&
|
|
755
|
+
restartResult.reason === "no_active_recording" &&
|
|
756
|
+
intentResult.kind === "start_and_stop_with_remainder"
|
|
757
|
+
) {
|
|
758
|
+
handleRecordingStart(
|
|
759
|
+
msg.sessionId,
|
|
760
|
+
{ promptForSource: true },
|
|
761
|
+
socket,
|
|
762
|
+
ctx,
|
|
763
|
+
);
|
|
519
764
|
}
|
|
520
765
|
}
|
|
521
766
|
|
|
522
|
-
rlog.info(
|
|
767
|
+
rlog.info(
|
|
768
|
+
{ remaining: msg.content, kind: intentResult.kind },
|
|
769
|
+
"Recording intent with remainder — continuing with remaining text",
|
|
770
|
+
);
|
|
523
771
|
}
|
|
524
772
|
|
|
525
773
|
// 'none' — deterministic resolver found nothing; try LLM fallback
|
|
526
774
|
// if the text contains recording-related keywords.
|
|
527
|
-
if (
|
|
775
|
+
if (
|
|
776
|
+
intentResult.kind === "none" &&
|
|
777
|
+
containsRecordingKeywords(messageText)
|
|
778
|
+
) {
|
|
528
779
|
const fallback = await classifyRecordingIntentFallback(messageText);
|
|
529
|
-
rlog.info(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
780
|
+
rlog.info(
|
|
781
|
+
{
|
|
782
|
+
fallbackAction: fallback.action,
|
|
783
|
+
fallbackConfidence: fallback.confidence,
|
|
784
|
+
},
|
|
785
|
+
"Recording intent LLM fallback result",
|
|
786
|
+
);
|
|
787
|
+
|
|
788
|
+
if (fallback.action !== "none" && fallback.confidence === "high") {
|
|
789
|
+
const kindMap: Record<
|
|
790
|
+
string,
|
|
791
|
+
import("../recording-intent.js").RecordingIntentResult
|
|
792
|
+
> = {
|
|
793
|
+
start: { kind: "start_only" },
|
|
794
|
+
stop: { kind: "stop_only" },
|
|
795
|
+
restart: { kind: "restart_only" },
|
|
796
|
+
pause: { kind: "pause_only" },
|
|
797
|
+
resume: { kind: "resume_only" },
|
|
538
798
|
};
|
|
539
799
|
const mapped = kindMap[fallback.action];
|
|
540
800
|
if (mapped) {
|
|
@@ -545,18 +805,40 @@ export async function handleUserMessage(
|
|
|
545
805
|
});
|
|
546
806
|
|
|
547
807
|
if (execResult.handled) {
|
|
548
|
-
rlog.info(
|
|
808
|
+
rlog.info(
|
|
809
|
+
{ kind: mapped.kind, source: "llm_fallback" },
|
|
810
|
+
"Recording intent intercepted via LLM fallback",
|
|
811
|
+
);
|
|
549
812
|
ctx.send(socket, {
|
|
550
|
-
type:
|
|
813
|
+
type: "assistant_text_delta",
|
|
551
814
|
text: execResult.responseText!,
|
|
552
815
|
sessionId: msg.sessionId,
|
|
553
816
|
});
|
|
554
|
-
ctx.send(socket, {
|
|
555
|
-
|
|
556
|
-
|
|
817
|
+
ctx.send(socket, {
|
|
818
|
+
type: "message_complete",
|
|
819
|
+
sessionId: msg.sessionId,
|
|
820
|
+
});
|
|
821
|
+
await conversationStore.addMessage(
|
|
822
|
+
msg.sessionId,
|
|
823
|
+
"user",
|
|
824
|
+
JSON.stringify([{ type: "text", text: messageText }]),
|
|
825
|
+
);
|
|
826
|
+
await conversationStore.addMessage(
|
|
827
|
+
msg.sessionId,
|
|
828
|
+
"assistant",
|
|
829
|
+
JSON.stringify([
|
|
830
|
+
{ type: "text", text: execResult.responseText! },
|
|
831
|
+
]),
|
|
832
|
+
);
|
|
557
833
|
if (!session.isProcessing()) {
|
|
558
|
-
session.messages.push({
|
|
559
|
-
|
|
834
|
+
session.messages.push({
|
|
835
|
+
role: "user",
|
|
836
|
+
content: [{ type: "text", text: messageText }],
|
|
837
|
+
});
|
|
838
|
+
session.messages.push({
|
|
839
|
+
role: "assistant",
|
|
840
|
+
content: [{ type: "text", text: execResult.responseText! }],
|
|
841
|
+
});
|
|
560
842
|
}
|
|
561
843
|
return;
|
|
562
844
|
}
|
|
@@ -570,41 +852,45 @@ export async function handleUserMessage(
|
|
|
570
852
|
// gate on queue depth: users often retry "approve"/"yes" while the queue
|
|
571
853
|
// is draining after a prior denial, and requiring an empty queue causes a
|
|
572
854
|
// deny/retry cascade where natural-language approvals never land.
|
|
573
|
-
if (
|
|
574
|
-
session.hasAnyPendingConfirmation()
|
|
575
|
-
&& messageText.trim().length > 0
|
|
576
|
-
) {
|
|
855
|
+
if (session.hasAnyPendingConfirmation() && messageText.trim().length > 0) {
|
|
577
856
|
try {
|
|
578
857
|
const pendingInteractionRequestIdsForConversation = pendingInteractions
|
|
579
858
|
.getByConversation(msg.sessionId)
|
|
580
859
|
.filter(
|
|
581
860
|
(interaction) =>
|
|
582
|
-
interaction.kind ===
|
|
583
|
-
|
|
584
|
-
|
|
861
|
+
interaction.kind === "confirmation" &&
|
|
862
|
+
interaction.session === session &&
|
|
863
|
+
session.hasPendingConfirmation(interaction.requestId),
|
|
585
864
|
)
|
|
586
865
|
.map((interaction) => interaction.requestId);
|
|
587
866
|
|
|
588
867
|
const pendingCanonicalRequestIdsForConversation = [
|
|
589
|
-
...listPendingCanonicalGuardianRequestsByDestinationConversation(
|
|
590
|
-
.
|
|
868
|
+
...listPendingCanonicalGuardianRequestsByDestinationConversation(
|
|
869
|
+
msg.sessionId,
|
|
870
|
+
ipcChannel,
|
|
871
|
+
)
|
|
872
|
+
.filter((request) => request.kind === "tool_approval")
|
|
591
873
|
.map((request) => request.id),
|
|
592
874
|
...listCanonicalGuardianRequests({
|
|
593
|
-
status:
|
|
875
|
+
status: "pending",
|
|
594
876
|
conversationId: msg.sessionId,
|
|
595
|
-
kind:
|
|
877
|
+
kind: "tool_approval",
|
|
596
878
|
}).map((request) => request.id),
|
|
597
|
-
].filter((pendingRequestId) =>
|
|
879
|
+
].filter((pendingRequestId) =>
|
|
880
|
+
session.hasPendingConfirmation(pendingRequestId),
|
|
881
|
+
);
|
|
598
882
|
|
|
599
|
-
const pendingRequestIdsForConversation = Array.from(
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
883
|
+
const pendingRequestIdsForConversation = Array.from(
|
|
884
|
+
new Set([
|
|
885
|
+
...pendingInteractionRequestIdsForConversation,
|
|
886
|
+
...pendingCanonicalRequestIdsForConversation,
|
|
887
|
+
]),
|
|
888
|
+
);
|
|
603
889
|
|
|
604
890
|
if (pendingRequestIdsForConversation.length > 0) {
|
|
605
891
|
// Resolve the local IPC actor's principal via the vellum guardian binding
|
|
606
892
|
// for principal-based authorization in the canonical decision primitive.
|
|
607
|
-
const localCtx =
|
|
893
|
+
const localCtx = resolveLocalIpcTrustContext(ipcChannel);
|
|
608
894
|
const routerResult = await routeGuardianReply({
|
|
609
895
|
messageText: messageText.trim(),
|
|
610
896
|
channel: ipcChannel,
|
|
@@ -617,13 +903,16 @@ export async function handleUserMessage(
|
|
|
617
903
|
pendingRequestIds: pendingRequestIdsForConversation,
|
|
618
904
|
approvalConversationGenerator: desktopApprovalConversationGenerator,
|
|
619
905
|
emissionContext: {
|
|
620
|
-
source:
|
|
906
|
+
source: "inline_nl",
|
|
621
907
|
causedByRequestId: requestId,
|
|
622
908
|
decisionText: messageText.trim(),
|
|
623
909
|
},
|
|
624
910
|
});
|
|
625
911
|
|
|
626
|
-
if (
|
|
912
|
+
if (
|
|
913
|
+
routerResult.consumed &&
|
|
914
|
+
routerResult.type !== "nl_keep_pending"
|
|
915
|
+
) {
|
|
627
916
|
// Success-path emissions (approved/denied) are handled centrally
|
|
628
917
|
// by handleConfirmationResponse (called via the resolver chain).
|
|
629
918
|
// However, stale/failed paths never reach handleConfirmationResponse,
|
|
@@ -632,8 +921,8 @@ export async function handleUserMessage(
|
|
|
632
921
|
session.emitConfirmationStateChanged({
|
|
633
922
|
sessionId: msg.sessionId,
|
|
634
923
|
requestId: routerResult.requestId,
|
|
635
|
-
state:
|
|
636
|
-
source:
|
|
924
|
+
state: "resolved_stale",
|
|
925
|
+
source: "inline_nl",
|
|
637
926
|
causedByRequestId: requestId,
|
|
638
927
|
decisionText: messageText.trim(),
|
|
639
928
|
});
|
|
@@ -644,23 +933,29 @@ export async function handleUserMessage(
|
|
|
644
933
|
assistantMessageChannel: ipcChannel,
|
|
645
934
|
userMessageInterface: ipcInterface,
|
|
646
935
|
assistantMessageInterface: ipcInterface,
|
|
647
|
-
provenanceTrustClass:
|
|
936
|
+
provenanceTrustClass: "guardian" as const,
|
|
648
937
|
};
|
|
649
938
|
|
|
650
|
-
const consumedUserMessage = createUserMessage(
|
|
939
|
+
const consumedUserMessage = createUserMessage(
|
|
940
|
+
messageText,
|
|
941
|
+
msg.attachments ?? [],
|
|
942
|
+
);
|
|
651
943
|
await conversationStore.addMessage(
|
|
652
944
|
msg.sessionId,
|
|
653
|
-
|
|
945
|
+
"user",
|
|
654
946
|
JSON.stringify(consumedUserMessage.content),
|
|
655
947
|
consumedChannelMeta,
|
|
656
948
|
);
|
|
657
949
|
|
|
658
|
-
const replyText =
|
|
659
|
-
|
|
950
|
+
const replyText =
|
|
951
|
+
routerResult.replyText?.trim() ||
|
|
952
|
+
(routerResult.decisionApplied
|
|
953
|
+
? "Decision applied."
|
|
954
|
+
: "Request already resolved.");
|
|
660
955
|
const consumedAssistantMessage = createAssistantMessage(replyText);
|
|
661
956
|
await conversationStore.addMessage(
|
|
662
957
|
msg.sessionId,
|
|
663
|
-
|
|
958
|
+
"assistant",
|
|
664
959
|
JSON.stringify(consumedAssistantMessage.content),
|
|
665
960
|
consumedChannelMeta,
|
|
666
961
|
);
|
|
@@ -669,19 +964,22 @@ export async function handleUserMessage(
|
|
|
669
964
|
if (!session.isProcessing()) {
|
|
670
965
|
// Keep in-memory history aligned with persisted transcript so
|
|
671
966
|
// session-history operations (undo/regenerate) target the same turn.
|
|
672
|
-
session.messages.push(
|
|
967
|
+
session.messages.push(
|
|
968
|
+
consumedUserMessage,
|
|
969
|
+
consumedAssistantMessage,
|
|
970
|
+
);
|
|
673
971
|
}
|
|
674
972
|
|
|
675
973
|
// Mirror the normal queued/dequeued lifecycle so desktop clients can
|
|
676
974
|
// reconcile queued bubble state for this just-sent user message.
|
|
677
975
|
ctx.send(socket, {
|
|
678
|
-
type:
|
|
976
|
+
type: "message_queued",
|
|
679
977
|
sessionId: msg.sessionId,
|
|
680
978
|
requestId,
|
|
681
979
|
position: 0,
|
|
682
980
|
});
|
|
683
981
|
ctx.send(socket, {
|
|
684
|
-
type:
|
|
982
|
+
type: "message_dequeued",
|
|
685
983
|
sessionId: msg.sessionId,
|
|
686
984
|
requestId,
|
|
687
985
|
});
|
|
@@ -693,27 +991,34 @@ export async function handleUserMessage(
|
|
|
693
991
|
// client will see it on the next transcript reload / session switch.
|
|
694
992
|
if (!session.isProcessing()) {
|
|
695
993
|
ctx.send(socket, {
|
|
696
|
-
type:
|
|
994
|
+
type: "assistant_text_delta",
|
|
697
995
|
text: replyText,
|
|
698
996
|
sessionId: msg.sessionId,
|
|
699
997
|
});
|
|
700
998
|
}
|
|
701
999
|
ctx.send(socket, {
|
|
702
|
-
type:
|
|
1000
|
+
type: "message_request_complete",
|
|
703
1001
|
sessionId: msg.sessionId,
|
|
704
1002
|
requestId,
|
|
705
1003
|
runStillActive: session.isProcessing(),
|
|
706
1004
|
});
|
|
707
1005
|
|
|
708
1006
|
rlog.info(
|
|
709
|
-
{
|
|
710
|
-
|
|
1007
|
+
{
|
|
1008
|
+
routerType: routerResult.type,
|
|
1009
|
+
decisionApplied: routerResult.decisionApplied,
|
|
1010
|
+
routerRequestId: routerResult.requestId,
|
|
1011
|
+
},
|
|
1012
|
+
"Consumed pending-confirmation reply before auto-deny",
|
|
711
1013
|
);
|
|
712
1014
|
return;
|
|
713
1015
|
}
|
|
714
1016
|
}
|
|
715
1017
|
} catch (err) {
|
|
716
|
-
rlog.warn(
|
|
1018
|
+
rlog.warn(
|
|
1019
|
+
{ err },
|
|
1020
|
+
"Failed to process pending-confirmation reply; falling back to auto-deny behavior",
|
|
1021
|
+
);
|
|
717
1022
|
}
|
|
718
1023
|
}
|
|
719
1024
|
|
|
@@ -721,16 +1026,21 @@ export async function handleUserMessage(
|
|
|
721
1026
|
// agent can process the user's follow-up message instead. The agent
|
|
722
1027
|
// will see the denial and can re-request the tool if still needed.
|
|
723
1028
|
if (session.hasAnyPendingConfirmation()) {
|
|
724
|
-
rlog.info(
|
|
1029
|
+
rlog.info("Auto-denying pending confirmation(s) due to new user message");
|
|
725
1030
|
// Emit authoritative confirmation state for each auto-denied request
|
|
726
1031
|
// before the prompter clears them.
|
|
727
|
-
for (const interaction of pendingInteractions.getByConversation(
|
|
728
|
-
|
|
1032
|
+
for (const interaction of pendingInteractions.getByConversation(
|
|
1033
|
+
msg.sessionId,
|
|
1034
|
+
)) {
|
|
1035
|
+
if (
|
|
1036
|
+
interaction.session === session &&
|
|
1037
|
+
interaction.kind === "confirmation"
|
|
1038
|
+
) {
|
|
729
1039
|
session.emitConfirmationStateChanged({
|
|
730
1040
|
sessionId: msg.sessionId,
|
|
731
1041
|
requestId: interaction.requestId,
|
|
732
|
-
state:
|
|
733
|
-
source:
|
|
1042
|
+
state: "denied",
|
|
1043
|
+
source: "auto_deny",
|
|
734
1044
|
causedByRequestId: requestId,
|
|
735
1045
|
});
|
|
736
1046
|
}
|
|
@@ -738,9 +1048,17 @@ export async function handleUserMessage(
|
|
|
738
1048
|
session.denyAllPendingConfirmations();
|
|
739
1049
|
// Keep the pending-interaction tracker aligned with the prompter so
|
|
740
1050
|
// stale request IDs are not reused as routing candidates.
|
|
741
|
-
for (const interaction of pendingInteractions.getByConversation(
|
|
742
|
-
|
|
743
|
-
|
|
1051
|
+
for (const interaction of pendingInteractions.getByConversation(
|
|
1052
|
+
msg.sessionId,
|
|
1053
|
+
)) {
|
|
1054
|
+
if (
|
|
1055
|
+
interaction.session === session &&
|
|
1056
|
+
interaction.kind === "confirmation"
|
|
1057
|
+
) {
|
|
1058
|
+
syncCanonicalStatusFromIpcConfirmationDecision(
|
|
1059
|
+
interaction.requestId,
|
|
1060
|
+
"deny",
|
|
1061
|
+
);
|
|
744
1062
|
pendingInteractions.resolve(interaction.requestId);
|
|
745
1063
|
}
|
|
746
1064
|
}
|
|
@@ -750,16 +1068,19 @@ export async function handleUserMessage(
|
|
|
750
1068
|
messageText,
|
|
751
1069
|
msg.attachments ?? [],
|
|
752
1070
|
requestId,
|
|
753
|
-
|
|
1071
|
+
"user_message",
|
|
754
1072
|
msg.activeSurfaceId,
|
|
755
1073
|
msg.currentPage,
|
|
756
1074
|
originalContentBeforeStrip,
|
|
757
1075
|
);
|
|
758
1076
|
} catch (err) {
|
|
759
1077
|
const message = err instanceof Error ? err.message : String(err);
|
|
760
|
-
rlog.error({ err },
|
|
761
|
-
ctx.send(socket, {
|
|
762
|
-
|
|
1078
|
+
rlog.error({ err }, "Error setting up user message processing");
|
|
1079
|
+
ctx.send(socket, {
|
|
1080
|
+
type: "error",
|
|
1081
|
+
message: `Failed to process message: ${message}`,
|
|
1082
|
+
});
|
|
1083
|
+
const classified = classifySessionError(err, { phase: "handler" });
|
|
763
1084
|
ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
|
|
764
1085
|
}
|
|
765
1086
|
}
|
|
@@ -781,9 +1102,12 @@ export function handleConfirmationResponse(
|
|
|
781
1102
|
msg.selectedPattern,
|
|
782
1103
|
msg.selectedScope,
|
|
783
1104
|
undefined,
|
|
784
|
-
{ source:
|
|
1105
|
+
{ source: "button" },
|
|
1106
|
+
);
|
|
1107
|
+
syncCanonicalStatusFromIpcConfirmationDecision(
|
|
1108
|
+
msg.requestId,
|
|
1109
|
+
msg.decision,
|
|
785
1110
|
);
|
|
786
|
-
syncCanonicalStatusFromIpcConfirmationDecision(msg.requestId, msg.decision);
|
|
787
1111
|
pendingInteractions.resolve(msg.requestId);
|
|
788
1112
|
return;
|
|
789
1113
|
}
|
|
@@ -798,13 +1122,19 @@ export function handleConfirmationResponse(
|
|
|
798
1122
|
msg.selectedPattern,
|
|
799
1123
|
msg.selectedScope,
|
|
800
1124
|
);
|
|
801
|
-
syncCanonicalStatusFromIpcConfirmationDecision(
|
|
1125
|
+
syncCanonicalStatusFromIpcConfirmationDecision(
|
|
1126
|
+
msg.requestId,
|
|
1127
|
+
msg.decision,
|
|
1128
|
+
);
|
|
802
1129
|
pendingInteractions.resolve(msg.requestId);
|
|
803
1130
|
return;
|
|
804
1131
|
}
|
|
805
1132
|
}
|
|
806
1133
|
|
|
807
|
-
log.warn(
|
|
1134
|
+
log.warn(
|
|
1135
|
+
{ requestId: msg.requestId },
|
|
1136
|
+
"No session found with pending confirmation for requestId",
|
|
1137
|
+
);
|
|
808
1138
|
}
|
|
809
1139
|
|
|
810
1140
|
export function handleSecretResponse(
|
|
@@ -818,7 +1148,10 @@ export function handleSecretResponse(
|
|
|
818
1148
|
if (standalone) {
|
|
819
1149
|
clearTimeout(standalone.timer);
|
|
820
1150
|
pendingStandaloneSecrets.delete(msg.requestId);
|
|
821
|
-
standalone.resolve({
|
|
1151
|
+
standalone.resolve({
|
|
1152
|
+
value: msg.value ?? null,
|
|
1153
|
+
delivery: msg.delivery ?? "store",
|
|
1154
|
+
});
|
|
822
1155
|
pendingInteractions.resolve(msg.requestId);
|
|
823
1156
|
return;
|
|
824
1157
|
}
|
|
@@ -834,52 +1167,86 @@ export function handleSecretResponse(
|
|
|
834
1167
|
return;
|
|
835
1168
|
}
|
|
836
1169
|
}
|
|
837
|
-
log.warn(
|
|
1170
|
+
log.warn(
|
|
1171
|
+
{ requestId: msg.requestId },
|
|
1172
|
+
"No session found with pending secret prompt for requestId",
|
|
1173
|
+
);
|
|
838
1174
|
}
|
|
839
1175
|
|
|
840
|
-
export function handleSessionList(
|
|
841
|
-
|
|
1176
|
+
export function handleSessionList(
|
|
1177
|
+
socket: net.Socket,
|
|
1178
|
+
ctx: HandlerContext,
|
|
1179
|
+
offset = 0,
|
|
1180
|
+
limit = 50,
|
|
1181
|
+
): void {
|
|
1182
|
+
const conversations = conversationStore.listConversations(
|
|
1183
|
+
limit,
|
|
1184
|
+
false,
|
|
1185
|
+
offset,
|
|
1186
|
+
);
|
|
842
1187
|
const totalCount = conversationStore.countConversations();
|
|
843
1188
|
const conversationIds = conversations.map((c) => c.id);
|
|
844
|
-
const bindings =
|
|
1189
|
+
const bindings =
|
|
1190
|
+
externalConversationStore.getBindingsForConversations(conversationIds);
|
|
845
1191
|
const attentionStates = getAttentionStateByConversationIds(conversationIds);
|
|
846
|
-
const displayMetas =
|
|
1192
|
+
const displayMetas =
|
|
1193
|
+
conversationStore.getDisplayMetaForConversations(conversationIds);
|
|
847
1194
|
ctx.send(socket, {
|
|
848
|
-
type:
|
|
1195
|
+
type: "session_list_response",
|
|
849
1196
|
sessions: conversations.map((c) => {
|
|
850
1197
|
const binding = bindings.get(c.id);
|
|
851
1198
|
const originChannel = parseChannelId(c.originChannel);
|
|
852
1199
|
const originInterface = parseInterfaceId(c.originInterface);
|
|
853
1200
|
const attn = attentionStates.get(c.id);
|
|
854
1201
|
const displayMeta = displayMetas.get(c.id);
|
|
855
|
-
const assistantAttention = attn
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1202
|
+
const assistantAttention = attn
|
|
1203
|
+
? {
|
|
1204
|
+
hasUnseenLatestAssistantMessage:
|
|
1205
|
+
attn.latestAssistantMessageAt != null &&
|
|
1206
|
+
(attn.lastSeenAssistantMessageAt == null ||
|
|
1207
|
+
attn.lastSeenAssistantMessageAt <
|
|
1208
|
+
attn.latestAssistantMessageAt),
|
|
1209
|
+
...(attn.latestAssistantMessageAt != null
|
|
1210
|
+
? { latestAssistantMessageAt: attn.latestAssistantMessageAt }
|
|
1211
|
+
: {}),
|
|
1212
|
+
...(attn.lastSeenAssistantMessageAt != null
|
|
1213
|
+
? { lastSeenAssistantMessageAt: attn.lastSeenAssistantMessageAt }
|
|
1214
|
+
: {}),
|
|
1215
|
+
...(attn.lastSeenConfidence != null
|
|
1216
|
+
? { lastSeenConfidence: attn.lastSeenConfidence }
|
|
1217
|
+
: {}),
|
|
1218
|
+
...(attn.lastSeenSignalType != null
|
|
1219
|
+
? { lastSeenSignalType: attn.lastSeenSignalType }
|
|
1220
|
+
: {}),
|
|
1221
|
+
}
|
|
1222
|
+
: undefined;
|
|
863
1223
|
return {
|
|
864
1224
|
id: c.id,
|
|
865
|
-
title: c.title ??
|
|
1225
|
+
title: c.title ?? "Untitled",
|
|
866
1226
|
createdAt: c.createdAt,
|
|
867
1227
|
updatedAt: c.updatedAt,
|
|
868
1228
|
threadType: normalizeThreadType(c.threadType),
|
|
869
|
-
source: c.source ??
|
|
870
|
-
...(binding && isChannelId(binding.sourceChannel)
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1229
|
+
source: c.source ?? "user",
|
|
1230
|
+
...(binding && isChannelId(binding.sourceChannel)
|
|
1231
|
+
? {
|
|
1232
|
+
channelBinding: {
|
|
1233
|
+
sourceChannel: binding.sourceChannel,
|
|
1234
|
+
externalChatId: binding.externalChatId,
|
|
1235
|
+
externalUserId: binding.externalUserId,
|
|
1236
|
+
displayName: binding.displayName,
|
|
1237
|
+
username: binding.username,
|
|
1238
|
+
},
|
|
1239
|
+
}
|
|
1240
|
+
: {}),
|
|
1241
|
+
...(c.scheduleJobId ? { scheduleJobId: c.scheduleJobId } : {}),
|
|
879
1242
|
...(originChannel ? { conversationOriginChannel: originChannel } : {}),
|
|
880
|
-
...(originInterface
|
|
1243
|
+
...(originInterface
|
|
1244
|
+
? { conversationOriginInterface: originInterface }
|
|
1245
|
+
: {}),
|
|
881
1246
|
...(assistantAttention ? { assistantAttention } : {}),
|
|
882
|
-
...(displayMeta?.displayOrder != null
|
|
1247
|
+
...(displayMeta?.displayOrder != null
|
|
1248
|
+
? { displayOrder: displayMeta.displayOrder }
|
|
1249
|
+
: {}),
|
|
883
1250
|
...(displayMeta?.isPinned ? { isPinned: displayMeta.isPinned } : {}),
|
|
884
1251
|
};
|
|
885
1252
|
}),
|
|
@@ -887,14 +1254,17 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
|
|
|
887
1254
|
});
|
|
888
1255
|
}
|
|
889
1256
|
|
|
890
|
-
export function handleSessionsClear(
|
|
1257
|
+
export function handleSessionsClear(
|
|
1258
|
+
socket: net.Socket,
|
|
1259
|
+
ctx: HandlerContext,
|
|
1260
|
+
): void {
|
|
891
1261
|
const cleared = ctx.clearAllSessions();
|
|
892
1262
|
// Also clear DB conversations. When a new IPC connection triggers
|
|
893
1263
|
// sendInitialSession, it auto-creates a conversation if none exist.
|
|
894
1264
|
// Without this DB clear, that auto-created row survives, contradicting
|
|
895
1265
|
// the "clear all conversations" intent.
|
|
896
1266
|
conversationStore.clearAll();
|
|
897
|
-
ctx.send(socket, { type:
|
|
1267
|
+
ctx.send(socket, { type: "sessions_clear_response", cleared });
|
|
898
1268
|
}
|
|
899
1269
|
|
|
900
1270
|
export async function handleSessionCreate(
|
|
@@ -903,7 +1273,8 @@ export async function handleSessionCreate(
|
|
|
903
1273
|
ctx: HandlerContext,
|
|
904
1274
|
): Promise<void> {
|
|
905
1275
|
const threadType = normalizeThreadType(msg.threadType);
|
|
906
|
-
const title =
|
|
1276
|
+
const title =
|
|
1277
|
+
msg.title ?? (msg.initialMessage ? GENERATING_TITLE : "New Conversation");
|
|
907
1278
|
const conversation = conversationStore.createConversation({
|
|
908
1279
|
title,
|
|
909
1280
|
threadType,
|
|
@@ -922,9 +1293,9 @@ export async function handleSessionCreate(
|
|
|
922
1293
|
}
|
|
923
1294
|
|
|
924
1295
|
ctx.send(socket, {
|
|
925
|
-
type:
|
|
1296
|
+
type: "session_info",
|
|
926
1297
|
sessionId: conversation.id,
|
|
927
|
-
title: conversation.title ??
|
|
1298
|
+
title: conversation.title ?? "New Conversation",
|
|
928
1299
|
...(msg.correlationId ? { correlationId: msg.correlationId } : {}),
|
|
929
1300
|
threadType: normalizeThreadType(conversation.threadType),
|
|
930
1301
|
});
|
|
@@ -939,11 +1310,11 @@ export async function handleSessionCreate(
|
|
|
939
1310
|
if (title === GENERATING_TITLE) {
|
|
940
1311
|
queueGenerateConversationTitle({
|
|
941
1312
|
conversationId: conversation.id,
|
|
942
|
-
context: { origin:
|
|
1313
|
+
context: { origin: "ipc" },
|
|
943
1314
|
userMessage: msg.initialMessage,
|
|
944
1315
|
onTitleUpdated: (newTitle) => {
|
|
945
1316
|
ctx.send(socket, {
|
|
946
|
-
type:
|
|
1317
|
+
type: "session_title_updated",
|
|
947
1318
|
sessionId: conversation.id,
|
|
948
1319
|
title: newTitle,
|
|
949
1320
|
});
|
|
@@ -953,7 +1324,8 @@ export async function handleSessionCreate(
|
|
|
953
1324
|
|
|
954
1325
|
ctx.socketToSession.set(socket, conversation.id);
|
|
955
1326
|
const requestId = uuid();
|
|
956
|
-
const transportChannel =
|
|
1327
|
+
const transportChannel =
|
|
1328
|
+
parseChannelId(msg.transport?.channelId) ?? "vellum";
|
|
957
1329
|
const sendEvent = makeIpcEventSender({
|
|
958
1330
|
ctx,
|
|
959
1331
|
socket,
|
|
@@ -966,33 +1338,45 @@ export async function handleSessionCreate(
|
|
|
966
1338
|
userMessageChannel: transportChannel,
|
|
967
1339
|
assistantMessageChannel: transportChannel,
|
|
968
1340
|
});
|
|
969
|
-
const transportInterface: InterfaceId =
|
|
1341
|
+
const transportInterface: InterfaceId =
|
|
1342
|
+
parseInterfaceId(msg.transport?.interfaceId) ?? "vellum";
|
|
970
1343
|
session.setTurnInterfaceContext({
|
|
971
1344
|
userMessageInterface: transportInterface,
|
|
972
1345
|
assistantMessageInterface: transportInterface,
|
|
973
1346
|
});
|
|
974
|
-
session
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1347
|
+
session
|
|
1348
|
+
.processMessage(msg.initialMessage, [], sendEvent, requestId)
|
|
1349
|
+
.catch((err) => {
|
|
1350
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1351
|
+
log.error(
|
|
1352
|
+
{ err, sessionId: conversation.id },
|
|
1353
|
+
"Error processing initial message",
|
|
1354
|
+
);
|
|
1355
|
+
ctx.send(socket, {
|
|
1356
|
+
type: "error",
|
|
1357
|
+
message: `Failed to process initial message: ${message}`,
|
|
1358
|
+
});
|
|
978
1359
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1360
|
+
// Replace stuck loading placeholder with a stable fallback title
|
|
1361
|
+
// if title generation hasn't already completed or been renamed.
|
|
1362
|
+
try {
|
|
1363
|
+
const current = conversationStore.getConversation(conversation.id);
|
|
1364
|
+
if (current && current.title === GENERATING_TITLE) {
|
|
1365
|
+
const fallback = UNTITLED_FALLBACK;
|
|
1366
|
+
conversationStore.updateConversationTitle(
|
|
1367
|
+
conversation.id,
|
|
1368
|
+
fallback,
|
|
1369
|
+
);
|
|
1370
|
+
ctx.send(socket, {
|
|
1371
|
+
type: "session_title_updated",
|
|
1372
|
+
sessionId: conversation.id,
|
|
1373
|
+
title: fallback,
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
} catch {
|
|
1377
|
+
// Best-effort fallback
|
|
991
1378
|
}
|
|
992
|
-
}
|
|
993
|
-
// Best-effort fallback
|
|
994
|
-
}
|
|
995
|
-
});
|
|
1379
|
+
});
|
|
996
1380
|
}
|
|
997
1381
|
}
|
|
998
1382
|
|
|
@@ -1003,7 +1387,10 @@ export async function handleSessionSwitch(
|
|
|
1003
1387
|
): Promise<void> {
|
|
1004
1388
|
const conversation = conversationStore.getConversation(msg.sessionId);
|
|
1005
1389
|
if (!conversation) {
|
|
1006
|
-
ctx.send(socket, {
|
|
1390
|
+
ctx.send(socket, {
|
|
1391
|
+
type: "error",
|
|
1392
|
+
message: `Session ${msg.sessionId} not found`,
|
|
1393
|
+
});
|
|
1007
1394
|
return;
|
|
1008
1395
|
}
|
|
1009
1396
|
|
|
@@ -1028,9 +1415,9 @@ export async function handleSessionSwitch(
|
|
|
1028
1415
|
}
|
|
1029
1416
|
|
|
1030
1417
|
ctx.send(socket, {
|
|
1031
|
-
type:
|
|
1418
|
+
type: "session_info",
|
|
1032
1419
|
sessionId: conversation.id,
|
|
1033
|
-
title: conversation.title ??
|
|
1420
|
+
title: conversation.title ?? "Untitled",
|
|
1034
1421
|
threadType: normalizeThreadType(conversation.threadType),
|
|
1035
1422
|
});
|
|
1036
1423
|
}
|
|
@@ -1042,18 +1429,25 @@ export function handleSessionRename(
|
|
|
1042
1429
|
): void {
|
|
1043
1430
|
const conversation = conversationStore.getConversation(msg.sessionId);
|
|
1044
1431
|
if (!conversation) {
|
|
1045
|
-
ctx.send(socket, {
|
|
1432
|
+
ctx.send(socket, {
|
|
1433
|
+
type: "error",
|
|
1434
|
+
message: `Session ${msg.sessionId} not found`,
|
|
1435
|
+
});
|
|
1046
1436
|
return;
|
|
1047
1437
|
}
|
|
1048
1438
|
conversationStore.updateConversationTitle(msg.sessionId, msg.title, 0);
|
|
1049
1439
|
ctx.send(socket, {
|
|
1050
|
-
type:
|
|
1440
|
+
type: "session_title_updated",
|
|
1051
1441
|
sessionId: msg.sessionId,
|
|
1052
1442
|
title: msg.title,
|
|
1053
1443
|
});
|
|
1054
1444
|
}
|
|
1055
1445
|
|
|
1056
|
-
export function handleCancel(
|
|
1446
|
+
export function handleCancel(
|
|
1447
|
+
msg: CancelRequest,
|
|
1448
|
+
socket: net.Socket,
|
|
1449
|
+
ctx: HandlerContext,
|
|
1450
|
+
): void {
|
|
1057
1451
|
const sessionId = msg.sessionId || ctx.socketToSession.get(socket);
|
|
1058
1452
|
if (sessionId) {
|
|
1059
1453
|
const session = ctx.sessions.get(sessionId);
|
|
@@ -1080,20 +1474,21 @@ export function handleHistoryRequest(
|
|
|
1080
1474
|
|
|
1081
1475
|
// Resolve include flags: explicit flags override mode, mode provides defaults.
|
|
1082
1476
|
// Default mode is 'light' when no mode and no include flags are specified.
|
|
1083
|
-
const isFullMode = msg.mode ===
|
|
1477
|
+
const isFullMode = msg.mode === "full";
|
|
1084
1478
|
const includeAttachments = msg.includeAttachments ?? isFullMode;
|
|
1085
1479
|
const includeToolImages = msg.includeToolImages ?? isFullMode;
|
|
1086
1480
|
const includeSurfaceData = msg.includeSurfaceData ?? isFullMode;
|
|
1087
1481
|
|
|
1088
|
-
const { messages: dbMessages, hasMore } =
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1482
|
+
const { messages: dbMessages, hasMore } =
|
|
1483
|
+
conversationStore.getMessagesPaginated(
|
|
1484
|
+
msg.sessionId,
|
|
1485
|
+
limit,
|
|
1486
|
+
msg.beforeTimestamp,
|
|
1487
|
+
msg.beforeMessageId,
|
|
1488
|
+
);
|
|
1094
1489
|
|
|
1095
1490
|
const parsed: ParsedHistoryMessage[] = dbMessages.map((m) => {
|
|
1096
|
-
let text =
|
|
1491
|
+
let text = "";
|
|
1097
1492
|
let toolCalls: HistoryToolCall[] = [];
|
|
1098
1493
|
let toolCallsBeforeText = false;
|
|
1099
1494
|
let textSegments: string[] = [];
|
|
@@ -1108,25 +1503,53 @@ export function handleHistoryRequest(
|
|
|
1108
1503
|
textSegments = rendered.textSegments;
|
|
1109
1504
|
contentOrder = rendered.contentOrder;
|
|
1110
1505
|
surfaces = rendered.surfaces;
|
|
1111
|
-
if (m.role ===
|
|
1112
|
-
log.info(
|
|
1506
|
+
if (m.role === "assistant" && toolCalls.length > 0) {
|
|
1507
|
+
log.info(
|
|
1508
|
+
{
|
|
1509
|
+
messageId: m.id,
|
|
1510
|
+
toolCallCount: toolCalls.length,
|
|
1511
|
+
text: truncate(text, 100, ""),
|
|
1512
|
+
},
|
|
1513
|
+
"History message with tool calls",
|
|
1514
|
+
);
|
|
1113
1515
|
}
|
|
1114
1516
|
} catch (err) {
|
|
1115
|
-
log.debug(
|
|
1517
|
+
log.debug(
|
|
1518
|
+
{ err, messageId: m.id },
|
|
1519
|
+
"Failed to parse message content as JSON, using raw text",
|
|
1520
|
+
);
|
|
1116
1521
|
text = m.content;
|
|
1117
1522
|
textSegments = text ? [text] : [];
|
|
1118
|
-
contentOrder = text ? [
|
|
1523
|
+
contentOrder = text ? ["text:0"] : [];
|
|
1119
1524
|
surfaces = [];
|
|
1120
1525
|
}
|
|
1121
|
-
let subagentNotification: ParsedHistoryMessage[
|
|
1526
|
+
let subagentNotification: ParsedHistoryMessage["subagentNotification"];
|
|
1122
1527
|
if (m.metadata) {
|
|
1123
1528
|
try {
|
|
1124
|
-
subagentNotification = (
|
|
1529
|
+
subagentNotification = (
|
|
1530
|
+
JSON.parse(m.metadata) as {
|
|
1531
|
+
subagentNotification?: ParsedHistoryMessage["subagentNotification"];
|
|
1532
|
+
}
|
|
1533
|
+
).subagentNotification;
|
|
1125
1534
|
} catch (err) {
|
|
1126
|
-
log.debug(
|
|
1535
|
+
log.debug(
|
|
1536
|
+
{ err, messageId: m.id },
|
|
1537
|
+
"Failed to parse message metadata as JSON, ignoring",
|
|
1538
|
+
);
|
|
1127
1539
|
}
|
|
1128
1540
|
}
|
|
1129
|
-
return {
|
|
1541
|
+
return {
|
|
1542
|
+
id: m.id,
|
|
1543
|
+
role: m.role,
|
|
1544
|
+
text,
|
|
1545
|
+
timestamp: m.createdAt,
|
|
1546
|
+
toolCalls,
|
|
1547
|
+
toolCallsBeforeText,
|
|
1548
|
+
textSegments,
|
|
1549
|
+
contentOrder,
|
|
1550
|
+
surfaces,
|
|
1551
|
+
...(subagentNotification ? { subagentNotification } : {}),
|
|
1552
|
+
};
|
|
1130
1553
|
});
|
|
1131
1554
|
|
|
1132
1555
|
// Merge tool_result data from user messages into the preceding assistant
|
|
@@ -1136,7 +1559,7 @@ export function handleHistoryRequest(
|
|
|
1136
1559
|
|
|
1137
1560
|
const historyMessages = merged.map((m) => {
|
|
1138
1561
|
let attachments: UserMessageAttachment[] | undefined;
|
|
1139
|
-
if (m.role ===
|
|
1562
|
+
if (m.role === "assistant" && m.id) {
|
|
1140
1563
|
const linked = getAttachmentsForMessage(m.id);
|
|
1141
1564
|
if (linked.length > 0) {
|
|
1142
1565
|
if (includeAttachments) {
|
|
@@ -1144,16 +1567,23 @@ export function handleHistoryRequest(
|
|
|
1144
1567
|
const MAX_INLINE_B64_SIZE = 512 * 1024;
|
|
1145
1568
|
attachments = linked.map((a) => {
|
|
1146
1569
|
const isFileBacked = !a.dataBase64;
|
|
1147
|
-
const omit =
|
|
1148
|
-
|
|
1149
|
-
|
|
1570
|
+
const omit =
|
|
1571
|
+
isFileBacked ||
|
|
1572
|
+
(a.mimeType.startsWith("video/") &&
|
|
1573
|
+
a.dataBase64.length > MAX_INLINE_B64_SIZE);
|
|
1574
|
+
|
|
1575
|
+
if (
|
|
1576
|
+
a.mimeType.startsWith("video/") &&
|
|
1577
|
+
!a.thumbnailBase64 &&
|
|
1578
|
+
a.dataBase64
|
|
1579
|
+
) {
|
|
1150
1580
|
const attachmentId = a.id;
|
|
1151
1581
|
const base64 = a.dataBase64;
|
|
1152
1582
|
silentlyWithLog(
|
|
1153
1583
|
generateVideoThumbnail(base64).then((thumb) => {
|
|
1154
1584
|
if (thumb) setAttachmentThumbnail(attachmentId, thumb);
|
|
1155
1585
|
}),
|
|
1156
|
-
|
|
1586
|
+
"video thumbnail generation",
|
|
1157
1587
|
);
|
|
1158
1588
|
}
|
|
1159
1589
|
|
|
@@ -1162,9 +1592,11 @@ export function handleHistoryRequest(
|
|
|
1162
1592
|
id: a.id,
|
|
1163
1593
|
filename: a.originalFilename,
|
|
1164
1594
|
mimeType: a.mimeType,
|
|
1165
|
-
data: omit ?
|
|
1595
|
+
data: omit ? "" : a.dataBase64,
|
|
1166
1596
|
...(omit ? { sizeBytes: a.sizeBytes } : {}),
|
|
1167
|
-
...(a.thumbnailBase64
|
|
1597
|
+
...(a.thumbnailBase64
|
|
1598
|
+
? { thumbnailData: a.thumbnailBase64 }
|
|
1599
|
+
: {}),
|
|
1168
1600
|
...(fp ? { filePath: fp } : {}),
|
|
1169
1601
|
};
|
|
1170
1602
|
});
|
|
@@ -1176,9 +1608,11 @@ export function handleHistoryRequest(
|
|
|
1176
1608
|
id: a.id,
|
|
1177
1609
|
filename: a.originalFilename,
|
|
1178
1610
|
mimeType: a.mimeType,
|
|
1179
|
-
data:
|
|
1611
|
+
data: "",
|
|
1180
1612
|
sizeBytes: a.sizeBytes,
|
|
1181
|
-
...(a.thumbnailBase64
|
|
1613
|
+
...(a.thumbnailBase64
|
|
1614
|
+
? { thumbnailData: a.thumbnailBase64 }
|
|
1615
|
+
: {}),
|
|
1182
1616
|
...(fp ? { filePath: fp } : {}),
|
|
1183
1617
|
};
|
|
1184
1618
|
});
|
|
@@ -1187,83 +1621,107 @@ export function handleHistoryRequest(
|
|
|
1187
1621
|
}
|
|
1188
1622
|
|
|
1189
1623
|
// In light mode, strip imageData from tool calls
|
|
1190
|
-
const filteredToolCalls =
|
|
1191
|
-
|
|
1192
|
-
?
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1624
|
+
const filteredToolCalls =
|
|
1625
|
+
m.toolCalls.length > 0
|
|
1626
|
+
? includeToolImages
|
|
1627
|
+
? m.toolCalls
|
|
1628
|
+
: m.toolCalls.map((tc) => {
|
|
1629
|
+
if (tc.imageData) {
|
|
1630
|
+
const { imageData: _, ...rest } = tc;
|
|
1631
|
+
return rest;
|
|
1632
|
+
}
|
|
1633
|
+
return tc;
|
|
1634
|
+
})
|
|
1635
|
+
: m.toolCalls;
|
|
1201
1636
|
|
|
1202
1637
|
// In light mode, strip full data from surfaces (keep metadata)
|
|
1203
|
-
const filteredSurfaces =
|
|
1204
|
-
|
|
1205
|
-
?
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1638
|
+
const filteredSurfaces =
|
|
1639
|
+
m.surfaces.length > 0
|
|
1640
|
+
? includeSurfaceData
|
|
1641
|
+
? m.surfaces
|
|
1642
|
+
: m.surfaces.map((s) => ({
|
|
1643
|
+
surfaceId: s.surfaceId,
|
|
1644
|
+
surfaceType: s.surfaceType,
|
|
1645
|
+
title: s.title,
|
|
1646
|
+
data: {
|
|
1647
|
+
...(s.surfaceType === "dynamic_page"
|
|
1648
|
+
? {
|
|
1649
|
+
...(s.data.preview ? { preview: s.data.preview } : {}),
|
|
1650
|
+
...(s.data.appId ? { appId: s.data.appId } : {}),
|
|
1651
|
+
...(s.data.appType ? { appType: s.data.appType } : {}),
|
|
1652
|
+
}
|
|
1653
|
+
: {}),
|
|
1654
|
+
} as Record<string, unknown>,
|
|
1655
|
+
...(s.actions ? { actions: s.actions } : {}),
|
|
1656
|
+
...(s.display ? { display: s.display } : {}),
|
|
1657
|
+
}))
|
|
1658
|
+
: m.surfaces;
|
|
1223
1659
|
|
|
1224
1660
|
// Apply text truncation when maxTextChars is set
|
|
1225
1661
|
let wasTruncated = false;
|
|
1226
1662
|
let textWasTruncated = false;
|
|
1227
1663
|
let text = m.text;
|
|
1228
1664
|
if (msg.maxTextChars !== undefined && text.length > msg.maxTextChars) {
|
|
1229
|
-
text = text.slice(0, msg.maxTextChars) +
|
|
1665
|
+
text = text.slice(0, msg.maxTextChars) + " \u2026 [truncated]";
|
|
1230
1666
|
wasTruncated = true;
|
|
1231
1667
|
textWasTruncated = true;
|
|
1232
1668
|
}
|
|
1233
1669
|
|
|
1234
1670
|
// Apply tool result truncation when maxToolResultChars is set
|
|
1235
|
-
const truncatedToolCalls =
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1671
|
+
const truncatedToolCalls =
|
|
1672
|
+
msg.maxToolResultChars !== undefined && filteredToolCalls.length > 0
|
|
1673
|
+
? filteredToolCalls.map((tc) => {
|
|
1674
|
+
if (
|
|
1675
|
+
tc.result !== undefined &&
|
|
1676
|
+
tc.result.length > msg.maxToolResultChars!
|
|
1677
|
+
) {
|
|
1678
|
+
wasTruncated = true;
|
|
1679
|
+
return {
|
|
1680
|
+
...tc,
|
|
1681
|
+
result:
|
|
1682
|
+
tc.result.slice(0, msg.maxToolResultChars!) +
|
|
1683
|
+
" \u2026 [truncated]",
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
return tc;
|
|
1687
|
+
})
|
|
1688
|
+
: filteredToolCalls;
|
|
1244
1689
|
|
|
1245
1690
|
return {
|
|
1246
1691
|
...(m.id ? { id: m.id } : {}),
|
|
1247
1692
|
role: m.role,
|
|
1248
1693
|
text,
|
|
1249
1694
|
timestamp: m.timestamp,
|
|
1250
|
-
...(truncatedToolCalls.length > 0
|
|
1695
|
+
...(truncatedToolCalls.length > 0
|
|
1696
|
+
? {
|
|
1697
|
+
toolCalls: truncatedToolCalls,
|
|
1698
|
+
toolCallsBeforeText: m.toolCallsBeforeText,
|
|
1699
|
+
}
|
|
1700
|
+
: {}),
|
|
1251
1701
|
...(attachments ? { attachments } : {}),
|
|
1252
|
-
...(!textWasTruncated && m.textSegments.length > 0
|
|
1253
|
-
|
|
1702
|
+
...(!textWasTruncated && m.textSegments.length > 0
|
|
1703
|
+
? { textSegments: m.textSegments }
|
|
1704
|
+
: {}),
|
|
1705
|
+
...(!textWasTruncated && m.contentOrder.length > 0
|
|
1706
|
+
? { contentOrder: m.contentOrder }
|
|
1707
|
+
: {}),
|
|
1254
1708
|
...(filteredSurfaces.length > 0 ? { surfaces: filteredSurfaces } : {}),
|
|
1255
|
-
...(m.subagentNotification
|
|
1709
|
+
...(m.subagentNotification
|
|
1710
|
+
? { subagentNotification: m.subagentNotification }
|
|
1711
|
+
: {}),
|
|
1256
1712
|
...(wasTruncated ? { wasTruncated: true } : {}),
|
|
1257
1713
|
};
|
|
1258
1714
|
});
|
|
1259
1715
|
|
|
1260
|
-
const oldestTimestamp =
|
|
1716
|
+
const oldestTimestamp =
|
|
1717
|
+
historyMessages.length > 0 ? historyMessages[0].timestamp : undefined;
|
|
1261
1718
|
// Provide the oldest message ID as a tie-breaker cursor so clients can
|
|
1262
1719
|
// paginate without skipping same-millisecond messages at page boundaries.
|
|
1263
|
-
const oldestMessageId =
|
|
1720
|
+
const oldestMessageId =
|
|
1721
|
+
historyMessages.length > 0 ? historyMessages[0].id : undefined;
|
|
1264
1722
|
|
|
1265
1723
|
ctx.send(socket, {
|
|
1266
|
-
type:
|
|
1724
|
+
type: "history_response",
|
|
1267
1725
|
sessionId: msg.sessionId,
|
|
1268
1726
|
messages: historyMessages,
|
|
1269
1727
|
hasMore,
|
|
@@ -1282,12 +1740,16 @@ export function handleUndo(
|
|
|
1282
1740
|
): void {
|
|
1283
1741
|
const session = ctx.sessions.get(msg.sessionId);
|
|
1284
1742
|
if (!session) {
|
|
1285
|
-
ctx.send(socket, { type:
|
|
1743
|
+
ctx.send(socket, { type: "error", message: "No active session" });
|
|
1286
1744
|
return;
|
|
1287
1745
|
}
|
|
1288
1746
|
ctx.touchSession(msg.sessionId);
|
|
1289
1747
|
const removedCount = session.undo();
|
|
1290
|
-
ctx.send(socket, {
|
|
1748
|
+
ctx.send(socket, {
|
|
1749
|
+
type: "undo_complete",
|
|
1750
|
+
removedCount,
|
|
1751
|
+
sessionId: msg.sessionId,
|
|
1752
|
+
});
|
|
1291
1753
|
}
|
|
1292
1754
|
|
|
1293
1755
|
export async function handleRegenerate(
|
|
@@ -1297,14 +1759,14 @@ export async function handleRegenerate(
|
|
|
1297
1759
|
): Promise<void> {
|
|
1298
1760
|
const session = ctx.sessions.get(msg.sessionId);
|
|
1299
1761
|
if (!session) {
|
|
1300
|
-
ctx.send(socket, { type:
|
|
1762
|
+
ctx.send(socket, { type: "error", message: "No active session" });
|
|
1301
1763
|
return;
|
|
1302
1764
|
}
|
|
1303
1765
|
ctx.touchSession(msg.sessionId);
|
|
1304
1766
|
|
|
1305
|
-
const regenerateChannel =
|
|
1306
|
-
session.getTurnChannelContext()?.assistantMessageChannel
|
|
1307
|
-
|
|
1767
|
+
const regenerateChannel =
|
|
1768
|
+
parseChannelId(session.getTurnChannelContext()?.assistantMessageChannel) ??
|
|
1769
|
+
"vellum";
|
|
1308
1770
|
const sendEvent = makeIpcEventSender({
|
|
1309
1771
|
ctx,
|
|
1310
1772
|
socket,
|
|
@@ -1314,23 +1776,29 @@ export async function handleRegenerate(
|
|
|
1314
1776
|
});
|
|
1315
1777
|
session.updateClient(sendEvent, false);
|
|
1316
1778
|
const requestId = uuid();
|
|
1317
|
-
session.traceEmitter.emit(
|
|
1779
|
+
session.traceEmitter.emit("request_received", "Regenerate requested", {
|
|
1318
1780
|
requestId,
|
|
1319
|
-
status:
|
|
1320
|
-
attributes: { source:
|
|
1781
|
+
status: "info",
|
|
1782
|
+
attributes: { source: "regenerate" },
|
|
1321
1783
|
});
|
|
1322
1784
|
try {
|
|
1323
1785
|
await session.regenerate(sendEvent, requestId);
|
|
1324
1786
|
} catch (err) {
|
|
1325
1787
|
const message = err instanceof Error ? err.message : String(err);
|
|
1326
|
-
log.error({ err, sessionId: msg.sessionId },
|
|
1327
|
-
session.traceEmitter.emit(
|
|
1788
|
+
log.error({ err, sessionId: msg.sessionId }, "Error regenerating message");
|
|
1789
|
+
session.traceEmitter.emit("request_error", truncate(message, 200, ""), {
|
|
1328
1790
|
requestId,
|
|
1329
|
-
status:
|
|
1330
|
-
attributes: {
|
|
1791
|
+
status: "error",
|
|
1792
|
+
attributes: {
|
|
1793
|
+
errorClass: err instanceof Error ? err.constructor.name : "Error",
|
|
1794
|
+
message: truncate(message, 500, ""),
|
|
1795
|
+
},
|
|
1331
1796
|
});
|
|
1332
|
-
ctx.send(socket, {
|
|
1333
|
-
|
|
1797
|
+
ctx.send(socket, {
|
|
1798
|
+
type: "error",
|
|
1799
|
+
message: `Failed to regenerate: ${message}`,
|
|
1800
|
+
});
|
|
1801
|
+
const classified = classifySessionError(err, { phase: "regenerate" });
|
|
1334
1802
|
ctx.send(socket, buildSessionErrorMessage(msg.sessionId, classified));
|
|
1335
1803
|
}
|
|
1336
1804
|
}
|
|
@@ -1342,12 +1810,12 @@ export function handleUsageRequest(
|
|
|
1342
1810
|
): void {
|
|
1343
1811
|
const conversation = conversationStore.getConversation(msg.sessionId);
|
|
1344
1812
|
if (!conversation) {
|
|
1345
|
-
ctx.send(socket, { type:
|
|
1813
|
+
ctx.send(socket, { type: "error", message: "No active session" });
|
|
1346
1814
|
return;
|
|
1347
1815
|
}
|
|
1348
1816
|
const config = getConfig();
|
|
1349
1817
|
ctx.send(socket, {
|
|
1350
|
-
type:
|
|
1818
|
+
type: "usage_response",
|
|
1351
1819
|
totalInputTokens: conversation.totalInputTokens,
|
|
1352
1820
|
totalOutputTokens: conversation.totalOutputTokens,
|
|
1353
1821
|
estimatedCost: conversation.totalEstimatedCost,
|
|
@@ -1362,7 +1830,7 @@ export function handleSandboxSet(
|
|
|
1362
1830
|
): void {
|
|
1363
1831
|
log.warn(
|
|
1364
1832
|
{ enabled: msg.enabled },
|
|
1365
|
-
|
|
1833
|
+
"Received deprecated sandbox_set message. Runtime sandbox overrides are ignored.",
|
|
1366
1834
|
);
|
|
1367
1835
|
}
|
|
1368
1836
|
|
|
@@ -1373,18 +1841,24 @@ export function handleDeleteQueuedMessage(
|
|
|
1373
1841
|
): void {
|
|
1374
1842
|
const session = ctx.sessions.get(msg.sessionId);
|
|
1375
1843
|
if (!session) {
|
|
1376
|
-
log.warn(
|
|
1844
|
+
log.warn(
|
|
1845
|
+
{ sessionId: msg.sessionId, requestId: msg.requestId },
|
|
1846
|
+
"No session found for delete_queued_message",
|
|
1847
|
+
);
|
|
1377
1848
|
return;
|
|
1378
1849
|
}
|
|
1379
1850
|
const removed = session.removeQueuedMessage(msg.requestId);
|
|
1380
1851
|
if (removed) {
|
|
1381
1852
|
ctx.send(socket, {
|
|
1382
|
-
type:
|
|
1853
|
+
type: "message_queued_deleted",
|
|
1383
1854
|
sessionId: msg.sessionId,
|
|
1384
1855
|
requestId: msg.requestId,
|
|
1385
1856
|
});
|
|
1386
1857
|
} else {
|
|
1387
|
-
log.warn(
|
|
1858
|
+
log.warn(
|
|
1859
|
+
{ sessionId: msg.sessionId, requestId: msg.requestId },
|
|
1860
|
+
"Queued message not found for deletion",
|
|
1861
|
+
);
|
|
1388
1862
|
}
|
|
1389
1863
|
}
|
|
1390
1864
|
|
|
@@ -1398,7 +1872,7 @@ export function handleConversationSearch(
|
|
|
1398
1872
|
maxMessagesPerConversation: msg.maxMessagesPerConversation,
|
|
1399
1873
|
});
|
|
1400
1874
|
ctx.send(socket, {
|
|
1401
|
-
type:
|
|
1875
|
+
type: "conversation_search_response",
|
|
1402
1876
|
query: msg.query,
|
|
1403
1877
|
results,
|
|
1404
1878
|
});
|
|
@@ -1409,14 +1883,22 @@ export function handleMessageContentRequest(
|
|
|
1409
1883
|
socket: net.Socket,
|
|
1410
1884
|
ctx: HandlerContext,
|
|
1411
1885
|
): void {
|
|
1412
|
-
const dbMessage = conversationStore.getMessageById(
|
|
1886
|
+
const dbMessage = conversationStore.getMessageById(
|
|
1887
|
+
msg.messageId,
|
|
1888
|
+
msg.sessionId,
|
|
1889
|
+
);
|
|
1413
1890
|
if (!dbMessage) {
|
|
1414
|
-
ctx.send(socket, {
|
|
1891
|
+
ctx.send(socket, {
|
|
1892
|
+
type: "error",
|
|
1893
|
+
message: `Message ${msg.messageId} not found in session ${msg.sessionId}`,
|
|
1894
|
+
});
|
|
1415
1895
|
return;
|
|
1416
1896
|
}
|
|
1417
1897
|
|
|
1418
1898
|
let text: string | undefined;
|
|
1419
|
-
let toolCalls:
|
|
1899
|
+
let toolCalls:
|
|
1900
|
+
| Array<{ name: string; result?: string; input?: Record<string, unknown> }>
|
|
1901
|
+
| undefined;
|
|
1420
1902
|
|
|
1421
1903
|
try {
|
|
1422
1904
|
const content = JSON.parse(dbMessage.content);
|
|
@@ -1427,19 +1909,32 @@ export function handleMessageContentRequest(
|
|
|
1427
1909
|
// Handle legacy conversations where tool_result blocks are stored in the
|
|
1428
1910
|
// following user message rather than inline with the assistant message.
|
|
1429
1911
|
// This mirrors the mergeToolResults logic used by handleHistoryRequest.
|
|
1430
|
-
if (
|
|
1431
|
-
|
|
1432
|
-
|
|
1912
|
+
if (
|
|
1913
|
+
dbMessage.role === "assistant" &&
|
|
1914
|
+
mergedToolCalls.some((tc) => tc.result === undefined)
|
|
1915
|
+
) {
|
|
1916
|
+
const nextMsg = conversationStore.getNextMessage(
|
|
1917
|
+
msg.sessionId,
|
|
1918
|
+
dbMessage.createdAt,
|
|
1919
|
+
dbMessage.id,
|
|
1920
|
+
);
|
|
1921
|
+
if (nextMsg && nextMsg.role === "user") {
|
|
1433
1922
|
try {
|
|
1434
1923
|
const nextContent = JSON.parse(nextMsg.content);
|
|
1435
1924
|
const nextRendered = renderHistoryContent(nextContent);
|
|
1436
|
-
if (
|
|
1925
|
+
if (
|
|
1926
|
+
nextRendered.text.trim() === "" &&
|
|
1927
|
+
nextRendered.toolCalls.length > 0
|
|
1928
|
+
) {
|
|
1437
1929
|
for (const resultEntry of nextRendered.toolCalls) {
|
|
1438
|
-
const unresolved = mergedToolCalls.find(
|
|
1930
|
+
const unresolved = mergedToolCalls.find(
|
|
1931
|
+
(tc) => tc.result === undefined,
|
|
1932
|
+
);
|
|
1439
1933
|
if (unresolved) {
|
|
1440
1934
|
unresolved.result = resultEntry.result;
|
|
1441
1935
|
unresolved.isError = resultEntry.isError;
|
|
1442
|
-
if (resultEntry.imageData)
|
|
1936
|
+
if (resultEntry.imageData)
|
|
1937
|
+
unresolved.imageData = resultEntry.imageData;
|
|
1443
1938
|
}
|
|
1444
1939
|
}
|
|
1445
1940
|
}
|
|
@@ -1462,7 +1957,7 @@ export function handleMessageContentRequest(
|
|
|
1462
1957
|
}
|
|
1463
1958
|
|
|
1464
1959
|
ctx.send(socket, {
|
|
1465
|
-
type:
|
|
1960
|
+
type: "message_content_response",
|
|
1466
1961
|
sessionId: msg.sessionId,
|
|
1467
1962
|
messageId: msg.messageId,
|
|
1468
1963
|
...(text !== undefined ? { text } : {}),
|
|
@@ -1479,7 +1974,11 @@ export function handleReorderThreads(
|
|
|
1479
1974
|
return;
|
|
1480
1975
|
}
|
|
1481
1976
|
conversationStore.batchSetDisplayOrders(
|
|
1482
|
-
msg.updates.map((u) => ({
|
|
1977
|
+
msg.updates.map((u) => ({
|
|
1978
|
+
id: u.sessionId,
|
|
1979
|
+
displayOrder: u.displayOrder ?? null,
|
|
1980
|
+
isPinned: u.isPinned ?? false,
|
|
1981
|
+
})),
|
|
1483
1982
|
);
|
|
1484
1983
|
}
|
|
1485
1984
|
|
|
@@ -1487,7 +1986,8 @@ export const sessionHandlers = defineHandlers({
|
|
|
1487
1986
|
user_message: handleUserMessage,
|
|
1488
1987
|
confirmation_response: handleConfirmationResponse,
|
|
1489
1988
|
secret_response: handleSecretResponse,
|
|
1490
|
-
session_list: (msg, socket, ctx) =>
|
|
1989
|
+
session_list: (msg, socket, ctx) =>
|
|
1990
|
+
handleSessionList(socket, ctx, msg.offset ?? 0, msg.limit ?? 50),
|
|
1491
1991
|
session_create: handleSessionCreate,
|
|
1492
1992
|
sessions_clear: (_msg, socket, ctx) => handleSessionsClear(socket, ctx),
|
|
1493
1993
|
session_switch: handleSessionSwitch,
|