@vellumai/assistant 0.6.5 → 0.7.0
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/AGENTS.md +29 -1
- package/ARCHITECTURE.md +60 -53
- package/Dockerfile +25 -3
- package/README.md +8 -10
- package/__tests__/permissions/gateway-threshold-reader.test.ts +277 -0
- package/bun.lock +306 -119
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +26 -120
- package/docs/architecture/security.md +22 -36
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/credential-execution-service.md +7 -5
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/bun.lock +25 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +8 -22
- package/node_modules/@vellumai/ces-client/bun.lock +33 -0
- package/node_modules/@vellumai/ces-client/package.json +25 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
- package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
- package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
- package/node_modules/@vellumai/gateway-client/package.json +23 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
- package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +891 -0
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
- package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +91 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1348 -0
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +333 -0
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
- package/openapi.yaml +3135 -692
- package/package.json +13 -7
- package/scripts/check-circular-deps.ts +80 -0
- package/scripts/generate-openapi.ts +24 -7
- package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +28 -28
- package/src/__tests__/access-request-decision.test.ts +2 -11
- package/src/__tests__/acp-session.test.ts +4 -150
- package/src/__tests__/actor-token-service.test.ts +17 -678
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
- package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
- package/src/__tests__/agent-loop-thinking.test.ts +4 -4
- package/src/__tests__/agent-wake-override-profile.test.ts +261 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
- package/src/__tests__/anthropic-provider.test.ts +127 -15
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/app-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +10 -357
- package/src/__tests__/approval-conversation-turn.test.ts +3 -8
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +2 -1
- package/src/__tests__/approval-routes-http.test.ts +34 -451
- package/src/__tests__/assistant-events-sse-hardening.test.ts +73 -80
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
- package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
- package/src/__tests__/attachments-store.test.ts +46 -1
- package/src/__tests__/audit-log-rotation.test.ts +2 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -20
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/background-shell-bash.test.ts +227 -0
- package/src/__tests__/background-shell-host-bash.test.ts +474 -0
- package/src/__tests__/background-tool-registry.test.ts +145 -0
- package/src/__tests__/background-tool-routes.test.ts +175 -0
- package/src/__tests__/btw-routes.test.ts +147 -183
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +15 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -1
- package/src/__tests__/call-domain.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +11 -13
- package/src/__tests__/call-recovery.test.ts +2 -1
- package/src/__tests__/call-routes-http.test.ts +3 -14
- package/src/__tests__/call-store.test.ts +2 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
- package/src/__tests__/canonical-guardian-store.test.ts +2 -2
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/catalog-files.test.ts +0 -26
- package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +79 -49
- package/src/__tests__/channel-approval.test.ts +9 -7
- package/src/__tests__/channel-approvals.test.ts +9 -180
- package/src/__tests__/channel-delivery-store.test.ts +11 -10
- package/src/__tests__/channel-guardian.test.ts +14 -25
- package/src/__tests__/channel-readiness-service.test.ts +8 -6
- package/src/__tests__/channel-reply-delivery.test.ts +3 -19
- package/src/__tests__/channel-retry-sweep.test.ts +2 -5
- package/src/__tests__/checker.test.ts +447 -3806
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
- package/src/__tests__/cli.test.ts +1 -38
- package/src/__tests__/compaction-events.test.ts +500 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +109 -0
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +25 -203
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
- package/src/__tests__/contact-store-user-file.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +71 -18
- package/src/__tests__/contacts-write.test.ts +6 -61
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
- package/src/__tests__/context-search-agent-runner.test.ts +998 -0
- package/src/__tests__/context-search-conversations-source.test.ts +320 -0
- package/src/__tests__/context-search-fanout.test.ts +380 -0
- package/src/__tests__/context-search-memory-source.test.ts +311 -0
- package/src/__tests__/context-search-pkb-source.test.ts +444 -0
- package/src/__tests__/context-search-types.test.ts +95 -0
- package/src/__tests__/context-search-workspace-source.test.ts +545 -0
- package/src/__tests__/context-window-manager.test.ts +380 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +14 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +631 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +41 -32
- package/src/__tests__/conversation-agent-loop.test.ts +54 -143
- package/src/__tests__/conversation-analysis-routes.test.ts +60 -82
- package/src/__tests__/conversation-attachments.test.ts +9 -20
- package/src/__tests__/conversation-attention-store.test.ts +2 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +4 -2
- package/src/__tests__/conversation-clear-safety.test.ts +53 -95
- package/src/__tests__/conversation-confirmation-signals.test.ts +7 -40
- package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +5 -4
- package/src/__tests__/conversation-fork-crud.test.ts +26 -55
- package/src/__tests__/conversation-fork-route.test.ts +5 -74
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +216 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +4 -95
- package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +0 -1
- package/src/__tests__/conversation-list-source.test.ts +2 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
- package/src/__tests__/conversation-pairing.test.ts +174 -11
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -294
- package/src/__tests__/conversation-process-callsite.test.ts +3 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +22 -8
- package/src/__tests__/conversation-queue.test.ts +30 -47
- package/src/__tests__/conversation-routes-disk-view.test.ts +131 -103
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +80 -55
- package/src/__tests__/conversation-routes-slash-commands.test.ts +83 -12
- package/src/__tests__/conversation-runtime-assembly.test.ts +196 -194
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-commands.test.ts +6 -43
- package/src/__tests__/conversation-slash-queue.test.ts +7 -3
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -3
- package/src/__tests__/conversation-speed-override.test.ts +6 -2
- package/src/__tests__/conversation-starter-routes.test.ts +177 -55
- package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +2 -375
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +42 -3
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
- package/src/__tests__/conversation-unread-route.test.ts +1 -1
- package/src/__tests__/conversation-usage.test.ts +3 -2
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -2
- package/src/__tests__/conversations-defer-cli.test.ts +150 -0
- package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
- package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
- package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
- package/src/__tests__/credential-execution-client.test.ts +1 -1
- package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +16 -2
- package/src/__tests__/credentials-cli.test.ts +45 -21
- package/src/__tests__/daemon-credential-client.test.ts +23 -108
- package/src/__tests__/db-acp-history.test.ts +284 -0
- package/src/__tests__/db-activation-state.test.ts +240 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/delete-propagation.test.ts +3 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +39 -32
- package/src/__tests__/dm-backfill.test.ts +3 -2
- package/src/__tests__/edit-propagation.test.ts +5 -7
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +1 -1
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/events-client-registration.test.ts +297 -0
- package/src/__tests__/file-write-tool.test.ts +2 -4
- package/src/__tests__/filing-service.test.ts +144 -17
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/followup-tools.test.ts +2 -1
- package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
- package/src/__tests__/gateway-only-guard.test.ts +4 -3
- package/src/__tests__/gemini-provider.test.ts +276 -10
- package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
- package/src/__tests__/guardian-action-store.test.ts +2 -1
- package/src/__tests__/guardian-action-sweep.test.ts +9 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
- package/src/__tests__/guardian-dispatch.test.ts +14 -11
- package/src/__tests__/guardian-grant-minting.test.ts +9 -15
- package/src/__tests__/guardian-outbound-http.test.ts +71 -106
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +34 -90
- package/src/__tests__/guardian-routing-state.test.ts +14 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +253 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +8 -4
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +39 -21
- package/src/__tests__/helpers/call-route-handler.ts +72 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
- package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
- package/src/__tests__/helpers/mock-logger.ts +36 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-browser-e2e-cloud.test.ts +309 -1
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +12 -2
- package/src/__tests__/host-browser-routes.test.ts +36 -91
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +10 -2
- package/src/__tests__/host-proxy-interface.test.ts +38 -4
- package/src/__tests__/host-shell-tool.test.ts +2 -4
- package/src/__tests__/host-transfer-pending-interactions.test.ts +160 -0
- package/src/__tests__/host-transfer-proxy.test.ts +733 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +20 -11
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/injector-chain.test.ts +525 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -206
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/invite-redemption-service.test.ts +2 -1
- package/src/__tests__/invite-routes-http.test.ts +80 -12
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
- package/src/__tests__/list-messages-attachments.test.ts +52 -55
- package/src/__tests__/list-messages-page-latest.test.ts +283 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
- package/src/__tests__/llm-call-pipeline.test.ts +284 -0
- package/src/__tests__/llm-context-normalization.test.ts +69 -4
- package/src/__tests__/llm-context-route-provider.test.ts +39 -113
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
- package/src/__tests__/llm-resolver.test.ts +211 -0
- package/src/__tests__/llm-schema.test.ts +56 -0
- package/src/__tests__/llm-usage-store.test.ts +2 -1
- package/src/__tests__/log-export-workspace.test.ts +28 -17
- package/src/__tests__/mcp-abort-signal.test.ts +2 -3
- package/src/__tests__/mcp-client-auth.test.ts +2 -3
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-admin-recall.test.ts +221 -0
- package/src/__tests__/memory-recall-log-store.test.ts +2 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +399 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +14 -13
- package/src/__tests__/migration-export-http.test.ts +17 -17
- package/src/__tests__/migration-export-to-gcs.test.ts +491 -0
- package/src/__tests__/migration-import-commit-http.test.ts +16 -16
- package/src/__tests__/migration-import-from-gcs.test.ts +533 -0
- package/src/__tests__/migration-import-from-url.test.ts +21 -91
- package/src/__tests__/migration-import-preflight-http.test.ts +13 -13
- package/src/__tests__/migration-jobs-status.test.ts +164 -0
- package/src/__tests__/migration-validate-http.test.ts +48 -83
- package/src/__tests__/mock-gateway-ipc.ts +32 -62
- package/src/__tests__/model-intents.test.ts +16 -1
- package/src/__tests__/nl-approval-parser.test.ts +13 -17
- package/src/__tests__/non-member-access-request.test.ts +13 -5
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +109 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +77 -123
- package/src/__tests__/oauth-cli.test.ts +28 -13
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +6 -6
- package/src/__tests__/oauth-providers-routes.test.ts +81 -103
- package/src/__tests__/oauth-store.test.ts +44 -77
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +105 -6
- package/src/__tests__/openai-responses-provider.test.ts +146 -4
- package/src/__tests__/openrouter-provider-only.test.ts +22 -4
- package/src/__tests__/overflow-reduce-pipeline.test.ts +671 -0
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +378 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +27 -20
- package/src/__tests__/platform.test.ts +10 -59
- package/src/__tests__/playbook-execution.test.ts +2 -1
- package/src/__tests__/playbook-tools.test.ts +2 -1
- package/src/__tests__/plugin-bootstrap.test.ts +529 -0
- package/src/__tests__/plugin-registry.test.ts +303 -0
- package/src/__tests__/plugin-route-contribution.test.ts +294 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +292 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +195 -14
- package/src/__tests__/profiler-routes.test.ts +112 -177
- package/src/__tests__/provider-send-message-override-profile.test.ts +223 -0
- package/src/__tests__/proxy-approval-callback.test.ts +6 -493
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +4 -2
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +0 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +1 -2
- package/src/__tests__/relay-server.test.ts +19 -4
- package/src/__tests__/require-fresh-approval.test.ts +19 -168
- package/src/__tests__/resolve-trust-class.test.ts +2 -1
- package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
- package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
- package/src/__tests__/runtime-events-sse-parity.test.ts +12 -13
- package/src/__tests__/runtime-events-sse.test.ts +13 -21
- package/src/__tests__/schedule-routes.test.ts +304 -77
- package/src/__tests__/schedule-store.test.ts +119 -1
- package/src/__tests__/schedule-tools.test.ts +2 -1
- package/src/__tests__/scheduler-recurrence.test.ts +16 -71
- package/src/__tests__/scheduler-reuse-conversation.test.ts +12 -51
- package/src/__tests__/scheduler-wake.test.ts +356 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
- package/src/__tests__/secret-detection-handler.test.ts +2 -19
- package/src/__tests__/secret-ingress-http.test.ts +38 -21
- package/src/__tests__/secret-routes-managed-proxy.test.ts +46 -102
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +38 -25
- package/src/__tests__/sequence-store.test.ts +2 -1
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
- package/src/__tests__/set-permission-mode.test.ts +0 -10
- package/src/__tests__/settings-routes.test.ts +35 -68
- package/src/__tests__/skill-boundary-guard.test.ts +105 -0
- package/src/__tests__/skill-load-inline-command.test.ts +2 -2
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-runtime-path.test.ts +64 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +11 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
- package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
- package/src/__tests__/slack-share-routes.test.ts +37 -72
- package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
- package/src/__tests__/subagent-notify-parent.test.ts +6 -29
- package/src/__tests__/subagent-role-registry.test.ts +3 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
- package/src/__tests__/subagent-tools.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +149 -57
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-management-tools.test.ts +2 -1
- package/src/__tests__/task-memory-cleanup.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +5 -16
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +5 -314
- package/src/__tests__/thread-backfill.test.ts +3 -2
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +484 -0
- package/src/__tests__/tool-approval-handler.test.ts +21 -63
- package/src/__tests__/tool-audit-listener.test.ts +3 -3
- package/src/__tests__/tool-domain-event-publisher.test.ts +3 -3
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +429 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +61 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +28 -56
- package/src/__tests__/tool-executor.test.ts +434 -1604
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
- package/src/__tests__/trusted-contact-verification.test.ts +2 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
- package/src/__tests__/twilio-routes.test.ts +25 -66
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
- package/src/__tests__/usage-routes.test.ts +73 -90
- package/src/__tests__/user-plugin-loader.test.ts +233 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -2
- package/src/__tests__/verification-control-plane-policy.test.ts +95 -14
- package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
- package/src/__tests__/voice-invite-redemption.test.ts +2 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
- package/src/__tests__/voice-session-bridge.test.ts +285 -106
- package/src/__tests__/volume-security-guard.test.ts +0 -2
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
- package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
- package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
- package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
- package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +274 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/acp/__tests__/client-handler.test.ts +64 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
- package/src/acp/__tests__/helpers/which-stub.ts +45 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
- package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
- package/src/acp/__tests__/session-manager.test.ts +83 -0
- package/src/acp/client-handler.ts +23 -139
- package/src/acp/resolve-agent.test.ts +291 -0
- package/src/acp/resolve-agent.ts +176 -0
- package/src/acp/session-manager.ts +166 -7
- package/src/acp/types.ts +2 -50
- package/src/agent/loop.ts +365 -104
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +296 -0
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +109 -103
- package/src/avatar/character-components.ts +6 -6
- package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -15
- package/src/backup/__tests__/paths.test.ts +3 -2
- package/src/backup/backup-worker.ts +3 -24
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +7 -11
- package/src/browser/__tests__/operations.test.ts +0 -35
- package/src/browser/operations.ts +1 -47
- package/src/bundler/app-compiler.ts +84 -1
- package/src/bundler/package-resolver.ts +2 -6
- package/src/calls/active-call-lease.ts +1 -1
- package/src/calls/call-constants.ts +1 -1
- package/src/calls/call-controller.ts +1 -5
- package/src/calls/call-domain.ts +14 -14
- package/src/calls/call-pointer-messages.ts +4 -9
- package/src/calls/call-state.ts +2 -2
- package/src/calls/call-store.ts +2 -1
- package/src/calls/guardian-action-sweep.ts +9 -25
- package/src/calls/guardian-dispatch.ts +1 -20
- package/src/calls/media-stream-audio-transcode.ts +2 -41
- package/src/calls/media-stream-server.ts +2 -3
- package/src/calls/media-stream-stt-session.ts +1 -3
- package/src/calls/relay-access-wait.ts +5 -8
- package/src/calls/relay-server.ts +15 -18
- package/src/calls/relay-setup-router.ts +2 -2
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/twilio-routes.ts +160 -78
- package/src/calls/voice-control-protocol.ts +10 -10
- package/src/calls/voice-ingress-preflight.ts +2 -2
- package/src/calls/voice-session-bridge.ts +137 -42
- package/src/channels/__tests__/types.test.ts +28 -6
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +48 -30
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +92 -214
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +4 -15
- package/src/cli/commands/__tests__/browser.test.ts +36 -31
- package/src/cli/commands/__tests__/cache.test.ts +23 -18
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +396 -0
- package/src/cli/commands/__tests__/task.test.ts +36 -35
- package/src/cli/commands/__tests__/trust.test.ts +602 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
- package/src/cli/commands/__tests__/ui.test.ts +17 -17
- package/src/cli/commands/__tests__/watchers.test.ts +29 -29
- package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
- package/src/cli/commands/attachment.ts +12 -8
- package/src/cli/commands/auth.ts +1 -1
- package/src/cli/commands/avatar.ts +192 -9
- package/src/cli/commands/backup.ts +16 -46
- package/src/cli/commands/browser.ts +52 -4
- package/src/cli/commands/cache.ts +7 -5
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/clients.ts +137 -0
- package/src/cli/commands/completions.ts +3 -10
- package/src/cli/commands/contacts.ts +10 -10
- package/src/cli/commands/conversations-defer.ts +364 -0
- package/src/cli/commands/conversations-import.ts +2 -3
- package/src/cli/commands/conversations.ts +115 -57
- package/src/cli/commands/credential-execution.ts +1 -1
- package/src/cli/commands/credentials.ts +139 -5
- package/src/cli/commands/default-action.ts +1 -1
- package/src/cli/commands/domain.ts +2 -2
- package/src/cli/commands/email.ts +7 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/keys.ts +2 -2
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory-v2.ts +343 -0
- package/src/cli/commands/memory.ts +8 -8
- package/src/cli/commands/notifications.ts +87 -121
- package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +4 -4
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/shared.ts +29 -2
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
- package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
- package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
- package/src/cli/commands/platform/connect.ts +3 -3
- package/src/cli/commands/platform/disconnect.ts +4 -6
- package/src/cli/commands/platform/index.ts +12 -10
- package/src/cli/commands/routes.ts +7 -1
- package/src/cli/commands/sequence.ts +7 -7
- package/src/cli/commands/skills.ts +189 -84
- package/src/cli/commands/task.ts +12 -10
- package/src/cli/commands/trust.ts +460 -162
- package/src/cli/commands/ui.ts +3 -3
- package/src/cli/commands/usage.ts +10 -5
- package/src/cli/commands/watchers.ts +8 -8
- package/src/cli/commands/webhooks.ts +270 -0
- package/src/cli/lib/daemon-avatar-client.ts +37 -0
- package/src/cli/lib/daemon-credential-client.ts +27 -189
- package/src/cli/lib/ipc-params.ts +22 -0
- package/src/cli/program.ts +29 -29
- package/src/cli.ts +1 -61
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/acp-defaults.test.ts +57 -0
- package/src/config/acp-defaults.ts +40 -0
- package/src/config/acp-schema.ts +1 -1
- package/src/config/assistant-feature-flags.ts +18 -142
- package/src/config/bundled-skills/acp/SKILL.md +44 -16
- package/src/config/bundled-skills/acp/TOOLS.json +45 -1
- package/src/config/bundled-skills/{screen-watch/tools/start-screen-watch.ts → acp/tools/acp-list-agents.ts} +2 -2
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +25 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +31 -44
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
- package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/SKILL.md +2 -17
- package/src/config/bundled-skills/settings/TOOLS.json +0 -56
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-tool-registry.ts +4 -21
- package/src/config/env.ts +7 -8
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +51 -33
- package/src/config/loader.ts +12 -15
- package/src/config/schema.ts +22 -70
- package/src/config/schemas/__tests__/filing.test.ts +58 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +186 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +12 -0
- package/src/config/schemas/host-browser.ts +2 -2
- package/src/config/schemas/inference.ts +0 -2
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +51 -10
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory-v2.ts +176 -0
- package/src/config/schemas/memory.ts +2 -0
- package/src/config/schemas/security.ts +0 -60
- package/src/config/schemas/services.ts +46 -7
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +95 -6
- package/src/config/types.ts +0 -41
- package/src/contacts/contact-store.ts +2 -2
- package/src/contacts/contacts-write.ts +0 -38
- package/src/contacts/types.ts +8 -10
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +4 -64
- package/src/context/window-manager.ts +191 -17
- package/src/credential-execution/approval-bridge.ts +7 -69
- package/src/credential-execution/client.ts +17 -422
- package/src/credential-execution/feature-gates.ts +1 -2
- package/src/credential-execution/managed-catalog.ts +1 -1
- package/src/credential-health/credential-health-service.ts +20 -7
- package/src/daemon/__tests__/conversation-feed-event.test.ts +304 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/__tests__/daemon-skill-host.test.ts +272 -0
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
- package/src/daemon/approval-generators.ts +2 -14
- package/src/daemon/classifier.ts +0 -106
- package/src/daemon/config-watcher.ts +14 -56
- package/src/daemon/connection-policy.ts +0 -14
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +120 -28
- package/src/daemon/conversation-agent-loop.ts +1113 -701
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +11 -20
- package/src/daemon/conversation-launch.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-notifiers.ts +3 -111
- package/src/daemon/conversation-process.ts +23 -20
- package/src/daemon/conversation-runtime-assembly.ts +530 -471
- package/src/daemon/conversation-slash.ts +4 -160
- package/src/daemon/conversation-store.ts +368 -0
- package/src/daemon/conversation-surfaces.ts +5 -4
- package/src/daemon/conversation-tool-setup.ts +49 -161
- package/src/daemon/conversation.ts +126 -217
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/daemon-skill-host.ts +262 -0
- package/src/daemon/external-plugins-bootstrap.ts +532 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-channels.ts +2 -2
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/config-ingress.ts +24 -2
- package/src/daemon/handlers/config-model.test.ts +17 -0
- package/src/daemon/handlers/config-model.ts +18 -52
- package/src/daemon/handlers/config-telegram.ts +6 -53
- package/src/daemon/handlers/config-voice.ts +1 -1
- package/src/daemon/handlers/conversations.ts +22 -156
- package/src/daemon/handlers/recording.ts +1 -1
- package/src/daemon/handlers/shared.ts +34 -35
- package/src/daemon/handlers/skills.ts +20 -24
- package/src/daemon/host-transfer-proxy.ts +500 -0
- package/src/daemon/lifecycle.ts +56 -326
- package/src/daemon/meet-host-startup.ts +51 -0
- package/src/daemon/meet-host-supervisor.ts +781 -0
- package/src/daemon/meet-manifest-loader.ts +410 -0
- package/src/daemon/memory-v2-startup.ts +35 -0
- package/src/daemon/message-protocol.ts +4 -7
- package/src/daemon/message-types/acp.ts +1 -0
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +65 -2
- package/src/daemon/message-types/host-transfer.ts +41 -0
- package/src/daemon/message-types/integrations.ts +6 -0
- package/src/daemon/message-types/messages.ts +26 -14
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +0 -6
- package/src/daemon/message-types/shared.ts +5 -2
- package/src/daemon/message-types/subagents.ts +2 -1
- package/src/daemon/message-types/workspace.ts +0 -2
- package/src/daemon/pkb-reminder-builder.test.ts +13 -12
- package/src/daemon/pkb-reminder-builder.ts +8 -16
- package/src/daemon/process-message.ts +616 -0
- package/src/daemon/providers-setup.ts +14 -6
- package/src/daemon/server.ts +79 -1272
- package/src/daemon/shutdown-handlers.ts +3 -13
- package/src/daemon/startup-error.ts +1 -1
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +223 -0
- package/src/email/feature-gate.ts +1 -1
- package/src/events/domain-events.ts +1 -8
- package/src/events/tool-audit-listener.ts +2 -8
- package/src/events/tool-metrics-listener.ts +1 -4
- package/src/filing/filing-service.ts +194 -54
- package/src/followups/followup-store.ts +3 -71
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +52 -8
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
- package/src/home/__tests__/rollup-producer.test.ts +67 -2
- package/src/home/assistant-feed-authoring.ts +8 -1
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +42 -3
- package/src/home/relationship-state-writer.ts +1 -1
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rewrite-feed-title.ts +58 -0
- package/src/home/rollup-producer.ts +16 -3
- package/src/inbound/platform-callback-registration.ts +1 -17
- package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
- package/src/ipc/__tests__/browser-ipc.test.ts +75 -51
- package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
- package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +254 -0
- package/src/ipc/__tests__/skill-server.test.ts +182 -0
- package/src/ipc/__tests__/socket-path.test.ts +44 -37
- package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
- package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
- package/src/ipc/assistant-server.ts +450 -0
- package/src/ipc/cli-client.ts +3 -3
- package/src/ipc/gateway-client.test.ts +131 -0
- package/src/ipc/gateway-client.ts +98 -120
- package/src/ipc/ipc-framing.ts +281 -0
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +152 -0
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +219 -0
- package/src/ipc/routes/db-proxy.ts +73 -0
- package/src/ipc/routes/route-adapter.ts +32 -0
- package/src/ipc/routes/trust-rules.test.ts +218 -0
- package/src/ipc/skill-ipc-types.ts +13 -0
- package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +402 -0
- package/src/ipc/skill-routes/__tests__/identity.test.ts +81 -0
- package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
- package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
- package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
- package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
- package/src/ipc/skill-routes/config.ts +47 -0
- package/src/ipc/skill-routes/events.ts +131 -0
- package/src/ipc/skill-routes/identity.ts +34 -0
- package/src/ipc/skill-routes/index.ts +37 -0
- package/src/ipc/skill-routes/log.ts +40 -0
- package/src/ipc/skill-routes/memory.ts +76 -0
- package/src/ipc/skill-routes/platform.ts +39 -0
- package/src/ipc/skill-routes/providers.ts +163 -0
- package/src/ipc/skill-routes/registries.ts +393 -0
- package/src/ipc/skill-server.ts +771 -0
- package/src/ipc/skill-socket-path.ts +20 -0
- package/src/ipc/socket-cleanup.ts +92 -0
- package/src/ipc/socket-path.ts +55 -48
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
- package/src/live-voice/__tests__/protocol.test.ts +295 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +421 -0
- package/src/live-voice/live-voice-archive.ts +758 -0
- package/src/live-voice/live-voice-metrics.ts +472 -0
- package/src/live-voice/live-voice-session-manager.ts +222 -0
- package/src/live-voice/live-voice-session.ts +1144 -0
- package/src/live-voice/live-voice-tts.ts +260 -0
- package/src/live-voice/protocol.ts +524 -0
- package/src/mcp/client.ts +2 -2
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
- package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
- package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
- package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
- package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
- package/src/memory/admin.ts +65 -7
- package/src/memory/app-git-service.ts +0 -14
- package/src/memory/attachments-store.ts +14 -16
- package/src/memory/auto-analysis-enqueue.ts +2 -17
- package/src/memory/canonical-guardian-store.ts +2 -1
- package/src/memory/channel-verification-sessions.ts +1 -1
- package/src/memory/checkpoints.ts +1 -1
- package/src/memory/context-search/agent-protocol.ts +424 -0
- package/src/memory/context-search/agent-runner.ts +1295 -0
- package/src/memory/context-search/format.ts +160 -0
- package/src/memory/context-search/limits.ts +106 -0
- package/src/memory/context-search/search.ts +387 -0
- package/src/memory/context-search/sources/conversations.ts +278 -0
- package/src/memory/context-search/sources/memory.ts +90 -0
- package/src/memory/context-search/sources/pkb.ts +468 -0
- package/src/memory/context-search/sources/workspace.ts +1255 -0
- package/src/memory/context-search/types.ts +49 -0
- package/src/memory/conversation-analyze-job.ts +3 -24
- package/src/memory/conversation-attention-store.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +117 -145
- package/src/memory/conversation-directories.ts +1 -11
- package/src/memory/conversation-display-order-migration.ts +11 -2
- package/src/memory/conversation-group-migration.ts +20 -4
- package/src/memory/conversation-key-store.ts +3 -4
- package/src/memory/conversation-queries.ts +69 -29
- package/src/memory/conversation-starter-validation.ts +88 -0
- package/src/memory/conversation-starters-cadence.ts +1 -1
- package/src/memory/conversation-title-service.ts +27 -1
- package/src/memory/db-init.ts +22 -4
- package/src/memory/db-maintenance.ts +1 -1
- package/src/memory/delivery-channels.ts +1 -14
- package/src/memory/delivery-crud.ts +2 -32
- package/src/memory/delivery-status.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +44 -5
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +412 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
- package/src/memory/graph/bootstrap.test.ts +277 -0
- package/src/memory/graph/bootstrap.ts +10 -6
- package/src/memory/graph/capability-seed.ts +3 -3
- package/src/memory/graph/compaction.ts +1 -1
- package/src/memory/graph/consolidation.ts +13 -10
- package/src/memory/graph/conversation-graph-memory.ts +151 -1
- package/src/memory/graph/decay.ts +1 -1
- package/src/memory/graph/extraction.ts +63 -23
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +95 -2
- package/src/memory/graph/graph-search.ts +22 -7
- package/src/memory/graph/image-ref-utils.ts +1 -1
- package/src/memory/graph/retriever.test.ts +158 -4
- package/src/memory/graph/retriever.ts +27 -8
- package/src/memory/graph/store.test.ts +2 -1
- package/src/memory/graph/store.ts +1 -1
- package/src/memory/graph/tool-handlers.ts +73 -247
- package/src/memory/graph/tools.ts +35 -53
- package/src/memory/group-crud.ts +1 -2
- package/src/memory/guardian-action-store.ts +2 -1
- package/src/memory/guardian-approvals.ts +1 -1
- package/src/memory/guardian-rate-limits.ts +1 -1
- package/src/memory/indexer.ts +43 -17
- package/src/memory/invite-store.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +1 -1
- package/src/memory/job-handlers/cleanup.ts +2 -1
- package/src/memory/job-handlers/conversation-starters.ts +18 -10
- package/src/memory/job-handlers/embedding.test.ts +2 -1
- package/src/memory/job-handlers/embedding.ts +1 -1
- package/src/memory/job-handlers/index-maintenance.ts +1 -1
- package/src/memory/job-handlers/summarization.ts +3 -3
- package/src/memory/job-utils.ts +3 -3
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
- package/src/memory/jobs/embed-concept-page.ts +210 -0
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/jobs-worker.ts +58 -5
- package/src/memory/lifecycle-events-store.ts +1 -1
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +1 -1
- package/src/memory/media-store.ts +1 -1
- package/src/memory/memory-recall-log-store.ts +1 -1
- package/src/memory/migrations/038-actor-token-records.ts +3 -0
- package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
- package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
- package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
- package/src/memory/migrations/230-acp-session-history.ts +41 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
- package/src/memory/migrations/232-activation-state.ts +38 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +7 -0
- package/src/memory/pkb/pkb-index.test.ts +5 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +5 -5
- package/src/memory/pkb/pkb-search.test.ts +148 -7
- package/src/memory/pkb/pkb-search.ts +65 -30
- package/src/memory/published-pages-store.ts +1 -1
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/acp.ts +30 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +2 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/scoped-approval-grants.ts +2 -1
- package/src/memory/search/semantic.ts +2 -2
- package/src/memory/shared-app-links-store.ts +2 -1
- package/src/memory/tool-usage-store.ts +1 -1
- package/src/memory/trace-event-store.ts +2 -1
- package/src/memory/turn-events-store.ts +1 -1
- package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
- package/src/memory/v2/__tests__/activation.test.ts +956 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +610 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +395 -0
- package/src/memory/v2/__tests__/edges.test.ts +435 -0
- package/src/memory/v2/__tests__/injection.test.ts +792 -0
- package/src/memory/v2/__tests__/migration.test.ts +812 -0
- package/src/memory/v2/__tests__/page-store.test.ts +334 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
- package/src/memory/v2/__tests__/sim.test.ts +549 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +351 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
- package/src/memory/v2/activation-store.ts +109 -0
- package/src/memory/v2/activation.ts +490 -0
- package/src/memory/v2/backfill-jobs.ts +442 -0
- package/src/memory/v2/consolidation-job.ts +304 -0
- package/src/memory/v2/edges.ts +217 -0
- package/src/memory/v2/injection.ts +307 -0
- package/src/memory/v2/migration.ts +654 -0
- package/src/memory/v2/now-text.ts +38 -0
- package/src/memory/v2/page-store.ts +245 -0
- package/src/memory/v2/prompts/consolidation.ts +185 -0
- package/src/memory/v2/prompts/sweep.ts +56 -0
- package/src/memory/v2/qdrant.ts +342 -0
- package/src/memory/v2/sim.ts +206 -0
- package/src/memory/v2/skill-content.ts +42 -0
- package/src/memory/v2/skill-qdrant.ts +395 -0
- package/src/memory/v2/skill-store.ts +128 -0
- package/src/memory/v2/sweep-job.ts +298 -0
- package/src/memory/v2/types.ts +116 -0
- package/src/memory/validation.ts +1 -1
- package/src/messaging/providers/index.ts +262 -0
- package/src/messaging/providers/slack/api.ts +242 -0
- package/src/messaging/providers/slack/message-metadata.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/messaging/providers/slack/send.ts +383 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
- package/src/messaging/providers/telegram-bot/api.ts +253 -0
- package/src/messaging/providers/telegram-bot/client.ts +17 -58
- package/src/messaging/providers/telegram-bot/send.ts +232 -0
- package/src/messaging/providers/whatsapp/adapter.ts +4 -36
- package/src/messaging/providers/whatsapp/api.ts +319 -0
- package/src/messaging/providers/whatsapp/client.ts +4 -48
- package/src/messaging/providers/whatsapp/send.ts +209 -0
- package/src/notifications/adapters/slack.ts +5 -23
- package/src/notifications/adapters/telegram.ts +8 -29
- package/src/notifications/conversation-candidates.ts +1 -1
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/conversation-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -6
- package/src/notifications/decision-engine.ts +1 -1
- package/src/notifications/decisions-store.ts +1 -1
- package/src/notifications/deliveries-store.ts +2 -1
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +1 -11
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/connection-resolver.ts +11 -2
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +32 -15
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/outbound-proxy/index.ts +0 -1
- package/src/permissions/approval-policy.test.ts +398 -106
- package/src/permissions/approval-policy.ts +134 -108
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +280 -345
- package/src/permissions/gateway-threshold-reader.ts +177 -0
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +8 -9
- package/src/permissions/risk-types.ts +24 -153
- package/src/permissions/types.ts +19 -47
- package/src/permissions/workspace-policy.ts +10 -7
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +488 -0
- package/src/plugins/defaults/llm-call.ts +79 -0
- package/src/plugins/defaults/memory-retrieval.ts +221 -0
- package/src/plugins/defaults/overflow-reduce.ts +185 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +103 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +301 -0
- package/src/plugins/types.ts +1133 -0
- package/src/plugins/user-loader.ts +203 -0
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +197 -0
- package/src/prompts/persona-resolver.ts +2 -4
- package/src/prompts/system-prompt.ts +39 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
- package/src/providers/__tests__/retry-callsite.test.ts +3 -6
- package/src/providers/anthropic/client.ts +71 -19
- package/src/providers/call-site-routing.ts +7 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/gemini/client.ts +96 -22
- package/src/providers/managed-proxy/context.ts +0 -12
- package/src/providers/model-catalog.ts +123 -25
- package/src/providers/model-intents.ts +6 -7
- package/src/providers/openai/chat-completions-provider.ts +37 -7
- package/src/providers/openai/responses-provider.ts +39 -4
- package/src/providers/openrouter/client.ts +9 -6
- package/src/providers/provider-env-vars.ts +4 -12
- package/src/providers/provider-send-message.ts +16 -11
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +52 -23
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
- package/src/providers/speech-to-text/openai-whisper.ts +3 -6
- package/src/providers/speech-to-text/provider-catalog.ts +75 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/providers/speech-to-text/xai.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +22 -10
- package/src/runtime/AGENTS.md +27 -17
- package/src/runtime/__tests__/agent-wake.test.ts +33 -9
- package/src/runtime/__tests__/client-registry.test.ts +271 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
- package/src/runtime/access-request-helper.ts +9 -20
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/agent-wake.ts +174 -68
- package/src/runtime/approval-conversation-turn.ts +2 -15
- package/src/runtime/approval-message-composer.ts +11 -60
- package/src/runtime/assistant-event.ts +18 -66
- package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
- package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
- package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
- package/src/runtime/auth/context.ts +9 -0
- package/src/runtime/auth/middleware.ts +4 -4
- package/src/runtime/auth/route-policy.ts +195 -4
- package/src/runtime/auth/token-service.ts +1 -100
- package/src/runtime/capability-tokens.ts +89 -313
- package/src/runtime/channel-approval-types.ts +1 -6
- package/src/runtime/channel-approvals.ts +7 -79
- package/src/runtime/channel-readiness-service.ts +2 -2
- package/src/runtime/channel-reply-delivery.ts +2 -8
- package/src/runtime/channel-retry-sweep.ts +20 -17
- package/src/runtime/client-registry.ts +254 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
- package/src/runtime/gateway-client.ts +37 -378
- package/src/runtime/guardian-action-grant-minter.ts +2 -3
- package/src/runtime/guardian-action-message-composer.ts +11 -52
- package/src/runtime/guardian-action-service.ts +19 -7
- package/src/runtime/guardian-decision-types.ts +4 -65
- package/src/runtime/guardian-reply-router.ts +10 -19
- package/src/runtime/guardian-vellum-migration.ts +5 -64
- package/src/runtime/http-errors.ts +3 -0
- package/src/runtime/http-router.ts +50 -7
- package/src/runtime/http-server.ts +345 -1041
- package/src/runtime/http-types.ts +15 -100
- package/src/runtime/interactive-ui-types.ts +145 -0
- package/src/runtime/interactive-ui.ts +38 -196
- package/src/runtime/invite-redemption-service.ts +1 -1
- package/src/runtime/invite-redemption-templates.ts +1 -1
- package/src/runtime/local-actor-identity.ts +13 -43
- package/src/runtime/message-composer-types.ts +134 -0
- package/src/runtime/middleware/rate-limiter.ts +1 -1
- package/src/runtime/middleware/request-logger.ts +5 -2
- package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +16 -0
- package/src/runtime/migrations/job-registry.ts +281 -0
- package/src/runtime/migrations/vbundle-builder.ts +4 -26
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -13
- package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
- package/src/runtime/nl-approval-parser.ts +16 -21
- package/src/runtime/pending-interactions.ts +29 -12
- package/src/runtime/routes/__tests__/acp-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +204 -320
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
- package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
- package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
- package/src/runtime/routes/access-request-decision.ts +25 -50
- package/src/runtime/routes/acp-routes.test.ts +371 -0
- package/src/runtime/routes/acp-routes.ts +392 -166
- package/src/runtime/routes/app-management-routes.ts +464 -660
- package/src/runtime/routes/app-routes.ts +192 -177
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +133 -434
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
- package/src/runtime/routes/attachment-routes.ts +409 -253
- package/src/runtime/routes/audio-routes.ts +51 -18
- package/src/runtime/routes/avatar-routes.ts +82 -75
- package/src/runtime/routes/background-tool-routes.ts +94 -0
- package/src/runtime/routes/backup-routes.ts +154 -336
- package/src/runtime/routes/brain-graph-routes.ts +83 -110
- package/src/runtime/routes/browser-routes.ts +141 -0
- package/src/runtime/routes/btw-routes.ts +62 -106
- package/src/runtime/routes/cache-routes.ts +96 -0
- package/src/runtime/routes/call-routes.ts +208 -247
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
- package/src/runtime/routes/channel-delivery-routes.ts +25 -27
- package/src/runtime/routes/channel-readiness-routes.ts +83 -120
- package/src/runtime/routes/channel-route-definitions.ts +62 -0
- package/src/runtime/routes/channel-route-shared.ts +14 -18
- package/src/runtime/routes/channel-verification-routes.ts +207 -187
- package/src/runtime/routes/client-routes.ts +48 -0
- package/src/runtime/routes/contact-routes.ts +533 -407
- package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
- package/src/runtime/routes/conversation-attention-routes.ts +55 -67
- package/src/runtime/routes/conversation-list-routes.ts +265 -0
- package/src/runtime/routes/conversation-management-routes.ts +626 -715
- package/src/runtime/routes/conversation-query-routes.ts +510 -460
- package/src/runtime/routes/conversation-routes.ts +652 -457
- package/src/runtime/routes/conversation-starter-routes.ts +121 -71
- package/src/runtime/routes/credential-prompt-routes.ts +124 -0
- package/src/runtime/routes/debug-routes.ts +34 -39
- package/src/runtime/routes/defer-routes.ts +230 -0
- package/src/runtime/routes/diagnostics-routes.ts +79 -70
- package/src/runtime/routes/documents-routes.ts +117 -106
- package/src/runtime/routes/errors.ts +132 -0
- package/src/runtime/routes/events-routes.ts +97 -58
- package/src/runtime/routes/filing-routes.ts +65 -78
- package/src/runtime/routes/global-search-routes.ts +51 -57
- package/src/runtime/routes/group-routes.ts +199 -181
- package/src/runtime/routes/guardian-action-routes.ts +103 -169
- package/src/runtime/routes/guardian-approval-interception.ts +27 -58
- package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
- package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
- package/src/runtime/routes/heartbeat-routes.ts +194 -209
- package/src/runtime/routes/home-feed-routes.ts +85 -187
- package/src/runtime/routes/home-state-routes.ts +27 -24
- package/src/runtime/routes/host-bash-routes.ts +42 -52
- package/src/runtime/routes/host-browser-routes.ts +38 -69
- package/src/runtime/routes/host-cu-routes.ts +74 -70
- package/src/runtime/routes/host-file-routes.ts +50 -60
- package/src/runtime/routes/host-transfer-routes.ts +220 -0
- package/src/runtime/routes/http-adapter.ts +172 -0
- package/src/runtime/routes/identity-routes.ts +83 -79
- package/src/runtime/routes/inbound-conversation.ts +11 -18
- package/src/runtime/routes/inbound-message-handler.ts +162 -123
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +79 -138
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +54 -90
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +19 -26
- package/src/runtime/routes/index.ts +197 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
- package/src/runtime/routes/integrations/slack/channel.ts +69 -66
- package/src/runtime/routes/integrations/slack/share.ts +49 -58
- package/src/runtime/routes/integrations/telegram.ts +91 -74
- package/src/runtime/routes/integrations/twilio.ts +163 -240
- package/src/runtime/routes/integrations/vercel.ts +57 -54
- package/src/runtime/routes/interface-routes.ts +43 -0
- package/src/runtime/routes/internal-oauth-routes.ts +56 -0
- package/src/runtime/routes/internal-twilio-routes.ts +46 -0
- package/src/runtime/routes/llm-context-normalization.ts +4 -2
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +90 -100
- package/src/runtime/routes/memory-item-routes.test.ts +153 -175
- package/src/runtime/routes/memory-item-routes.ts +243 -323
- package/src/runtime/routes/memory-v2-routes.ts +193 -0
- package/src/runtime/routes/migration-rollback-routes.ts +167 -212
- package/src/runtime/routes/migration-routes.ts +877 -377
- package/src/runtime/routes/notification-routes.ts +199 -70
- package/src/runtime/routes/oauth-apps.ts +254 -251
- package/src/runtime/routes/oauth-providers.ts +66 -57
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +224 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +60 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +250 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +195 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +159 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +207 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +175 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +27 -0
- package/src/runtime/routes/playground/force-compact.ts +60 -0
- package/src/runtime/routes/playground/guard.ts +36 -0
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +18 -0
- package/src/runtime/routes/playground/inject-failures.ts +143 -0
- package/src/runtime/routes/playground/reset-circuit.ts +89 -0
- package/src/runtime/routes/playground/seed-conversation.ts +113 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +74 -0
- package/src/runtime/routes/playground/state.ts +77 -0
- package/src/runtime/routes/profiler-routes.ts +132 -167
- package/src/runtime/routes/ps-routes.ts +120 -0
- package/src/runtime/routes/recording-routes.ts +197 -258
- package/src/runtime/routes/rename-conversation-routes.ts +89 -0
- package/src/runtime/routes/schedule-routes.ts +284 -207
- package/src/runtime/routes/secret-routes.ts +219 -265
- package/src/runtime/routes/secrets-deps.ts +24 -0
- package/src/runtime/routes/settings-routes.ts +361 -441
- package/src/runtime/routes/skills-routes.ts +434 -469
- package/src/runtime/routes/stt-routes.ts +196 -206
- package/src/runtime/routes/subagents-routes.ts +125 -141
- package/src/runtime/routes/suggest-trust-rule-routes.ts +244 -0
- package/src/runtime/routes/surface-action-routes.ts +135 -190
- package/src/runtime/routes/surface-content-routes.ts +84 -118
- package/src/runtime/routes/task-routes.ts +354 -0
- package/src/runtime/routes/telemetry-routes.ts +33 -49
- package/src/runtime/routes/trace-event-routes.ts +55 -74
- package/src/runtime/routes/trust-rules-routes.ts +147 -239
- package/src/runtime/routes/tts-routes.ts +187 -169
- package/src/runtime/routes/types.ts +139 -0
- package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
- package/src/runtime/routes/upgrade-broadcast-routes.ts +156 -197
- package/src/runtime/routes/usage-routes.ts +143 -169
- package/src/runtime/routes/user-routes.ts +102 -18
- package/src/runtime/routes/wake-conversation-routes.ts +49 -0
- package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
- package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
- package/src/runtime/routes/work-items-routes.test.ts +10 -20
- package/src/runtime/routes/work-items-routes.ts +418 -433
- package/src/runtime/routes/workspace-commit-routes.ts +30 -61
- package/src/runtime/routes/workspace-routes.test.ts +254 -381
- package/src/runtime/routes/workspace-routes.ts +238 -246
- package/src/runtime/runtime-mode.ts +8 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +80 -118
- package/src/runtime/services/analyze-conversation.ts +14 -41
- package/src/runtime/services/conversation-serializer.ts +181 -0
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/runtime/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +13 -49
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +70 -2
- package/src/schedule/scheduler.ts +149 -8
- package/src/security/ces-credential-client.ts +32 -169
- package/src/security/ces-rpc-credential-backend.ts +1 -1
- package/src/security/credential-backend.ts +6 -6
- package/src/security/oauth-completion-page.ts +1 -1
- package/src/security/oauth2.ts +3 -6
- package/src/sequence/analytics.ts +1 -1
- package/src/sequence/guardrails.ts +3 -3
- package/src/sequence/store.ts +2 -1
- package/src/signals/bash.ts +1 -1
- package/src/signals/event-stream.ts +1 -1
- package/src/skills/catalog-cache.ts +19 -5
- package/src/skills/catalog-files.ts +0 -5
- package/src/skills/catalog-install.ts +28 -18
- package/src/skills/category-inference.ts +0 -11
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/remote-skill-policy.ts +6 -7
- package/src/subagent/index.ts +2 -6
- package/src/subagent/manager.ts +27 -23
- package/src/subagent/types.ts +9 -0
- package/src/tasks/SPEC.md +2 -2
- package/src/tasks/task-compiler.ts +1 -1
- package/src/tasks/task-runner.ts +2 -22
- package/src/tasks/task-store.ts +1 -1
- package/src/tools/acp/list-agents.test.ts +115 -0
- package/src/tools/acp/list-agents.ts +31 -0
- package/src/tools/acp/spawn.test.ts +379 -0
- package/src/tools/acp/spawn.ts +142 -62
- package/src/tools/acp/steer.test.ts +101 -0
- package/src/tools/acp/steer.ts +38 -0
- package/src/tools/background-tool-registry.ts +98 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +122 -26
- package/src/tools/browser/browser-manager.ts +1 -8
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/browser/cdp-client/types.ts +4 -1
- package/src/tools/computer-use/definitions.ts +1 -1
- package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
- package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
- package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
- package/src/tools/credentials/broker-types.ts +2 -1
- package/src/tools/document/editor-template.ts +1 -1
- package/src/tools/execution-timeout.ts +1 -1
- package/src/tools/executor.ts +123 -76
- package/src/tools/host-filesystem/transfer.test.ts +268 -0
- package/src/tools/host-filesystem/transfer.ts +234 -0
- package/src/tools/host-terminal/host-shell.ts +189 -11
- package/src/tools/mcp/mcp-tool-factory.ts +1 -1
- package/src/tools/memory/register.test.ts +161 -1
- package/src/tools/memory/register.ts +19 -34
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +103 -255
- package/src/tools/policy-context.ts +5 -8
- package/src/tools/registry.ts +156 -4
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +13 -154
- package/src/tools/shared/shell-output.ts +4 -1
- package/src/tools/side-effects.ts +2 -2
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/subagent/spawn.ts +35 -11
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/safe-env.ts +9 -1
- package/src/tools/terminal/shell.ts +161 -31
- package/src/tools/tool-approval-handler.ts +4 -70
- package/src/tools/tool-input-summary.ts +10 -0
- package/src/tools/types.ts +157 -151
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/debounce.ts +0 -21
- package/src/util/errors.ts +0 -8
- package/src/util/log-redact.ts +0 -1
- package/src/util/platform.ts +85 -119
- package/src/util/pricing.ts +135 -9
- package/src/watcher/engine.ts +42 -20
- package/src/watcher/watcher-store.ts +2 -1
- package/src/work-items/work-item-store.ts +1 -1
- package/src/workspace/git-service.ts +1 -6
- package/src/workspace/migrations/006-services-config.ts +11 -4
- package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
- package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
- package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
- package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
- package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
- package/src/workspace/migrations/060-memory-v2-init.ts +53 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
- package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
- package/src/__tests__/ephemeral-permissions.test.ts +0 -474
- package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/pairing-concurrent.test.ts +0 -84
- package/src/__tests__/pairing-routes.test.ts +0 -181
- package/src/__tests__/parser.test.ts +0 -595
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -512
- package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
- package/src/__tests__/permission-mode.test.ts +0 -89
- package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
- package/src/__tests__/risk-classifier-parity.test.ts +0 -230
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/shell-identity.test.ts +0 -370
- package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
- package/src/__tests__/shell-parser-property.test.ts +0 -936
- package/src/__tests__/starter-bundle.test.ts +0 -173
- package/src/__tests__/stt-catalog-parity.test.ts +0 -282
- package/src/__tests__/task-runner.test.ts +0 -224
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -357
- package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
- package/src/__tests__/trust-store.test.ts +0 -2013
- package/src/__tests__/v2-consent-policy.test.ts +0 -103
- package/src/browser/identifiers.ts +0 -51
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/cli/db.ts +0 -1
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/external-skills-bootstrap.ts +0 -41
- package/src/daemon/message-types/trust.ts +0 -71
- package/src/daemon/pairing-store.ts +0 -229
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -61
- package/src/ipc/routes/browser.ts +0 -96
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/index.ts +0 -21
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/oauth/scope-policy.ts +0 -89
- package/src/permissions/bash-risk-classifier.test.ts +0 -1208
- package/src/permissions/bash-risk-classifier.ts +0 -707
- package/src/permissions/command-registry.test.ts +0 -535
- package/src/permissions/command-registry.ts +0 -825
- package/src/permissions/defaults.ts +0 -313
- package/src/permissions/file-risk-classifier.test.ts +0 -535
- package/src/permissions/file-risk-classifier.ts +0 -274
- package/src/permissions/permission-mode.ts +0 -24
- package/src/permissions/shell-identity.ts +0 -337
- package/src/permissions/skill-risk-classifier.test.ts +0 -311
- package/src/permissions/skill-risk-classifier.ts +0 -214
- package/src/permissions/trust-client.ts +0 -359
- package/src/permissions/trust-store-interface.ts +0 -100
- package/src/permissions/trust-store.ts +0 -1330
- package/src/permissions/v2-consent-policy.ts +0 -87
- package/src/permissions/web-risk-classifier.test.ts +0 -170
- package/src/permissions/web-risk-classifier.ts +0 -89
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
- package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
- package/src/runtime/actor-refresh-token-store.ts +0 -156
- package/src/runtime/actor-token-store.ts +0 -207
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
- package/src/runtime/auth/credential-service.ts +0 -352
- package/src/runtime/conversation-approval-overrides.ts +0 -86
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/browser-extension-pair-routes.ts +0 -556
- package/src/runtime/routes/channel-routes.ts +0 -112
- package/src/runtime/routes/contact-routes.test.ts +0 -298
- package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
- package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
- package/src/runtime/routes/invite-routes.ts +0 -280
- package/src/runtime/routes/pairing-routes.ts +0 -431
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/signals/shotgun.ts +0 -203
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/terminal/parser.ts +0 -623
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/types/qrcode.d.ts +0 -13
- package/src/util/network-info.ts +0 -55
- /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Route handlers for conversation messages and suggestions.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
existsSync,
|
|
6
|
+
readdirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
statSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from "node:fs";
|
|
5
11
|
import { join, relative } from "node:path";
|
|
6
12
|
|
|
7
13
|
import { z } from "zod";
|
|
@@ -13,6 +19,7 @@ import {
|
|
|
13
19
|
} from "../../agent/message-types.js";
|
|
14
20
|
import {
|
|
15
21
|
canServiceRegistryBrowser,
|
|
22
|
+
canServiceSseBrowser,
|
|
16
23
|
CHANNEL_IDS,
|
|
17
24
|
INTERFACE_IDS,
|
|
18
25
|
type InterfaceId,
|
|
@@ -23,6 +30,7 @@ import {
|
|
|
23
30
|
} from "../../channels/types.js";
|
|
24
31
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
25
32
|
import { getConfig } from "../../config/loader.js";
|
|
33
|
+
import { createApprovalConversationGenerator } from "../../daemon/approval-generators.js";
|
|
26
34
|
import type { Conversation } from "../../daemon/conversation.js";
|
|
27
35
|
import {
|
|
28
36
|
buildModelInfoEvent,
|
|
@@ -33,6 +41,7 @@ import {
|
|
|
33
41
|
resolveSlash,
|
|
34
42
|
type SlashContext,
|
|
35
43
|
} from "../../daemon/conversation-slash.js";
|
|
44
|
+
import { getOrCreateConversation as getOrCreateConversationInstance } from "../../daemon/conversation-store.js";
|
|
36
45
|
import {
|
|
37
46
|
getCannedFirstGreeting,
|
|
38
47
|
isWakeUpGreeting,
|
|
@@ -42,17 +51,26 @@ import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
|
|
|
42
51
|
import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
|
|
43
52
|
import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
|
|
44
53
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
54
|
+
import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
|
|
45
55
|
import type { ServerMessage } from "../../daemon/message-protocol.js";
|
|
46
56
|
import type {
|
|
47
57
|
HostProxyTransportMetadata,
|
|
48
58
|
NonHostProxyTransportMetadata,
|
|
49
59
|
} from "../../daemon/message-types/conversations.js";
|
|
50
|
-
import
|
|
60
|
+
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
61
|
+
import { emitFeedEvent } from "../../home/emit-feed-event.js";
|
|
51
62
|
import {
|
|
52
63
|
writeOnboardingSidecar,
|
|
53
64
|
writeRelationshipState,
|
|
54
65
|
} from "../../home/relationship-state-writer.js";
|
|
55
|
-
import
|
|
66
|
+
import { rewriteCommandPreview } from "../../home/rewrite-command-preview.js";
|
|
67
|
+
import { ipcCall } from "../../ipc/gateway-client.js";
|
|
68
|
+
import {
|
|
69
|
+
getAttachmentById,
|
|
70
|
+
getAttachmentMetadataForMessage,
|
|
71
|
+
getAttachmentsByIds,
|
|
72
|
+
getSourcePathsForAttachments,
|
|
73
|
+
} from "../../memory/attachments-store.js";
|
|
56
74
|
import {
|
|
57
75
|
createCanonicalGuardianRequest,
|
|
58
76
|
generateCanonicalRequestCode,
|
|
@@ -68,6 +86,7 @@ import {
|
|
|
68
86
|
hasMessages,
|
|
69
87
|
type MessageRow,
|
|
70
88
|
provenanceFromTrustContext,
|
|
89
|
+
setConversationInferenceProfile,
|
|
71
90
|
setConversationOriginChannelIfUnset,
|
|
72
91
|
setConversationOriginInterfaceIfUnset,
|
|
73
92
|
} from "../../memory/conversation-crud.js";
|
|
@@ -82,17 +101,19 @@ import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
|
82
101
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
83
102
|
import { summarizeToolInput } from "../../tools/tool-input-summary.js";
|
|
84
103
|
import { getLogger } from "../../util/logger.js";
|
|
85
|
-
import {
|
|
104
|
+
import {
|
|
105
|
+
getInterfacesDir,
|
|
106
|
+
getWorkspacePromptPath,
|
|
107
|
+
} from "../../util/platform.js";
|
|
86
108
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
87
109
|
import { buildAssistantEvent } from "../assistant-event.js";
|
|
110
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
88
111
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
89
|
-
import type { AuthContext } from "../auth/types.js";
|
|
90
112
|
import { getChromeExtensionRegistry } from "../chrome-extension-registry.js";
|
|
113
|
+
import { getClientRegistry } from "../client-registry.js";
|
|
91
114
|
import { bridgeConfirmationRequestToGuardian } from "../confirmation-request-guardian-bridge.js";
|
|
92
115
|
import { routeGuardianReply } from "../guardian-reply-router.js";
|
|
93
116
|
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
94
|
-
import { httpError } from "../http-errors.js";
|
|
95
|
-
import type { RouteDefinition } from "../http-router.js";
|
|
96
117
|
import type {
|
|
97
118
|
ApprovalConversationGenerator,
|
|
98
119
|
RuntimeAttachmentMetadata,
|
|
@@ -105,6 +126,9 @@ import {
|
|
|
105
126
|
resolveTrustContext,
|
|
106
127
|
withSourceChannel,
|
|
107
128
|
} from "../trust-context-resolver.js";
|
|
129
|
+
import { BadRequestError, InternalError, RouteError } from "./errors.js";
|
|
130
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
131
|
+
import { RouteResponse } from "./types.js";
|
|
108
132
|
|
|
109
133
|
const log = getLogger("conversation-routes");
|
|
110
134
|
|
|
@@ -112,6 +136,15 @@ const log = getLogger("conversation-routes");
|
|
|
112
136
|
const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/g;
|
|
113
137
|
|
|
114
138
|
const SUGGESTION_CACHE_MAX = 100;
|
|
139
|
+
const VALID_RISK_THRESHOLDS = ["none", "low", "medium", "high"] as const;
|
|
140
|
+
type RiskThreshold = (typeof VALID_RISK_THRESHOLDS)[number];
|
|
141
|
+
|
|
142
|
+
function isValidRiskThreshold(value: unknown): value is RiskThreshold {
|
|
143
|
+
return (
|
|
144
|
+
typeof value === "string" &&
|
|
145
|
+
VALID_RISK_THRESHOLDS.includes(value as RiskThreshold)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
115
148
|
|
|
116
149
|
function collectCanonicalGuardianRequestHintIds(
|
|
117
150
|
conversationId: string,
|
|
@@ -359,11 +392,11 @@ function getInterfaceFilesWithMtimes(
|
|
|
359
392
|
}
|
|
360
393
|
|
|
361
394
|
export function handleListMessages(
|
|
362
|
-
|
|
395
|
+
{ queryParams }: RouteHandlerArgs,
|
|
363
396
|
interfacesDir: string | null,
|
|
364
|
-
):
|
|
365
|
-
const conversationId =
|
|
366
|
-
const conversationKey =
|
|
397
|
+
): Record<string, unknown> {
|
|
398
|
+
const conversationId = queryParams?.conversationId;
|
|
399
|
+
const conversationKey = queryParams?.conversationKey;
|
|
367
400
|
|
|
368
401
|
let resolvedConversationId: string | undefined;
|
|
369
402
|
if (conversationId) {
|
|
@@ -372,30 +405,40 @@ export function handleListMessages(
|
|
|
372
405
|
const mapping = getConversationByKey(conversationKey);
|
|
373
406
|
resolvedConversationId = mapping?.conversationId;
|
|
374
407
|
} else {
|
|
375
|
-
|
|
376
|
-
"BAD_REQUEST",
|
|
408
|
+
throw new BadRequestError(
|
|
377
409
|
"conversationKey or conversationId query parameter is required",
|
|
378
|
-
400,
|
|
379
410
|
);
|
|
380
411
|
}
|
|
381
412
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const beforeTimestampRaw = url.searchParams.get("beforeTimestamp");
|
|
387
|
-
const limitRaw = url.searchParams.get("limit");
|
|
413
|
+
const beforeTimestampRaw = queryParams?.beforeTimestamp;
|
|
414
|
+
const limitRaw = queryParams?.limit;
|
|
415
|
+
const pageRaw = queryParams?.page;
|
|
388
416
|
|
|
389
417
|
// Validate: reject NaN values with 400
|
|
390
|
-
if (beforeTimestampRaw
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
);
|
|
418
|
+
if (beforeTimestampRaw != null && isNaN(Number(beforeTimestampRaw))) {
|
|
419
|
+
throw new BadRequestError("beforeTimestamp must be a valid number");
|
|
420
|
+
}
|
|
421
|
+
if (limitRaw != null && isNaN(Number(limitRaw))) {
|
|
422
|
+
throw new BadRequestError("limit must be a valid number");
|
|
396
423
|
}
|
|
397
|
-
if (
|
|
398
|
-
|
|
424
|
+
if (pageRaw != null && pageRaw !== "latest") {
|
|
425
|
+
throw new BadRequestError("page must be 'latest' when provided");
|
|
426
|
+
}
|
|
427
|
+
const isLatestPage = pageRaw === "latest";
|
|
428
|
+
|
|
429
|
+
if (!resolvedConversationId) {
|
|
430
|
+
// Unresolved conversation keys still need to advertise the stable
|
|
431
|
+
// `page=latest` contract so the web client can rely on metadata fields
|
|
432
|
+
// being present even before any message is persisted.
|
|
433
|
+
if (isLatestPage && beforeTimestampRaw == null) {
|
|
434
|
+
return {
|
|
435
|
+
messages: [],
|
|
436
|
+
hasMore: false,
|
|
437
|
+
oldestTimestamp: null,
|
|
438
|
+
oldestMessageId: null,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
return { messages: [] };
|
|
399
442
|
}
|
|
400
443
|
|
|
401
444
|
const beforeTimestamp = beforeTimestampRaw
|
|
@@ -406,10 +449,12 @@ export function handleListMessages(
|
|
|
406
449
|
? Math.min(Math.max(Math.floor(Number(limitRaw)), 1), 500)
|
|
407
450
|
: undefined;
|
|
408
451
|
|
|
409
|
-
//
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
|
|
452
|
+
// Paginate when either `beforeTimestamp` (older-page request) or
|
|
453
|
+
// `page=latest` (initial newest-N request) is set. When both are sent,
|
|
454
|
+
// `beforeTimestamp` wins because the caller is explicitly asking for an
|
|
455
|
+
// older page; `getMessagesPaginated` ignores `beforeTimestamp === undefined`
|
|
456
|
+
// and returns the newest `limit` messages in chronological order.
|
|
457
|
+
const isPaginated = beforeTimestamp != null || isLatestPage;
|
|
413
458
|
|
|
414
459
|
let rawMessages: MessageRow[];
|
|
415
460
|
let hasMore = false;
|
|
@@ -574,12 +619,12 @@ export function handleListMessages(
|
|
|
574
619
|
// aren't lost before DB compaction relinks them.
|
|
575
620
|
const idsToQuery = [m.id, ...(mergedIdMap.get(m.id) ?? [])];
|
|
576
621
|
const linked = idsToQuery.flatMap((id) =>
|
|
577
|
-
|
|
622
|
+
getAttachmentMetadataForMessage(id),
|
|
578
623
|
);
|
|
579
624
|
if (linked.length > 0) {
|
|
580
625
|
msgAttachments = linked.map((a) => {
|
|
581
626
|
if (a.mimeType.startsWith("image/")) {
|
|
582
|
-
const full =
|
|
627
|
+
const full = getAttachmentById(a.id, {
|
|
583
628
|
hydrateFileData: true,
|
|
584
629
|
});
|
|
585
630
|
return {
|
|
@@ -655,15 +700,28 @@ export function handleListMessages(
|
|
|
655
700
|
rawMessages.length > 0 ? rawMessages[0].createdAt : undefined;
|
|
656
701
|
const oldestMessageId =
|
|
657
702
|
rawMessages.length > 0 ? rawMessages[0].id : undefined;
|
|
658
|
-
|
|
703
|
+
// `page=latest` always emits both metadata fields so the web client has
|
|
704
|
+
// a stable contract; emit `null` when the conversation is empty.
|
|
705
|
+
// The existing `beforeTimestamp` branch keeps its conditional shape to
|
|
706
|
+
// avoid disturbing current callers.
|
|
707
|
+
if (isLatestPage && beforeTimestamp == null) {
|
|
708
|
+
return {
|
|
709
|
+
messages,
|
|
710
|
+
hasMore,
|
|
711
|
+
oldestTimestamp: oldestTimestamp ?? null,
|
|
712
|
+
oldestMessageId: oldestMessageId ?? null,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return {
|
|
659
717
|
messages,
|
|
660
718
|
hasMore,
|
|
661
719
|
...(oldestTimestamp != null ? { oldestTimestamp } : {}),
|
|
662
720
|
...(oldestMessageId != null ? { oldestMessageId } : {}),
|
|
663
|
-
}
|
|
721
|
+
};
|
|
664
722
|
}
|
|
665
723
|
|
|
666
|
-
return
|
|
724
|
+
return { messages };
|
|
667
725
|
}
|
|
668
726
|
|
|
669
727
|
// ── Tool-result merging ─────────────────────────────────────────────
|
|
@@ -994,10 +1052,59 @@ function makeHubPublisher(
|
|
|
994
1052
|
allowlistOptions: msg.allowlistOptions,
|
|
995
1053
|
scopeOptions: msg.scopeOptions,
|
|
996
1054
|
persistentDecisionsAllowed: msg.persistentDecisionsAllowed,
|
|
997
|
-
temporaryOptionsAvailable: msg.temporaryOptionsAvailable,
|
|
998
1055
|
},
|
|
999
1056
|
});
|
|
1000
1057
|
|
|
1058
|
+
const inputRecord = msg.input as Record<string, unknown>;
|
|
1059
|
+
const commandPreview =
|
|
1060
|
+
redactSecrets(summarizeToolInput(msg.toolName, inputRecord)) ||
|
|
1061
|
+
undefined;
|
|
1062
|
+
const technicalTitle = commandPreview
|
|
1063
|
+
? `Requesting permission: ${commandPreview}`
|
|
1064
|
+
: `Requesting approval to use ${msg.toolName}.`;
|
|
1065
|
+
const dedupKey = `tool-approval:${msg.requestId}`;
|
|
1066
|
+
|
|
1067
|
+
// Emit immediately with the technical preview.
|
|
1068
|
+
void emitFeedEvent({
|
|
1069
|
+
source: "assistant",
|
|
1070
|
+
title: technicalTitle,
|
|
1071
|
+
summary: technicalTitle,
|
|
1072
|
+
dedupKey,
|
|
1073
|
+
urgency: msg.riskLevel === "high" ? "high" : "medium",
|
|
1074
|
+
conversationId,
|
|
1075
|
+
detailPanel: { kind: "toolPermission" },
|
|
1076
|
+
}).catch((err) => {
|
|
1077
|
+
log.warn(
|
|
1078
|
+
{ err, requestId: msg.requestId },
|
|
1079
|
+
"Failed to emit tool approval request feed event",
|
|
1080
|
+
);
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
// Background: rewrite into prose and update the feed item.
|
|
1084
|
+
if (commandPreview) {
|
|
1085
|
+
void rewriteCommandPreview(msg.toolName, commandPreview)
|
|
1086
|
+
.then((prose) => {
|
|
1087
|
+
if (prose) {
|
|
1088
|
+
const proseTitle = `Requesting permission: ${prose}`;
|
|
1089
|
+
return emitFeedEvent({
|
|
1090
|
+
source: "assistant",
|
|
1091
|
+
title: proseTitle,
|
|
1092
|
+
summary: proseTitle,
|
|
1093
|
+
dedupKey,
|
|
1094
|
+
urgency: msg.riskLevel === "high" ? "high" : "medium",
|
|
1095
|
+
conversationId,
|
|
1096
|
+
detailPanel: { kind: "toolPermission" },
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
})
|
|
1100
|
+
.catch((err) => {
|
|
1101
|
+
log.warn(
|
|
1102
|
+
{ err, requestId: msg.requestId },
|
|
1103
|
+
"Failed to update feed event with prose rewrite",
|
|
1104
|
+
);
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1001
1108
|
// Create a canonical guardian request so HTTP handlers can find it
|
|
1002
1109
|
// via applyCanonicalGuardianDecision.
|
|
1003
1110
|
try {
|
|
@@ -1168,83 +1275,93 @@ function registerHostProxyPendingInteraction(
|
|
|
1168
1275
|
});
|
|
1169
1276
|
return msg.requestId;
|
|
1170
1277
|
}
|
|
1278
|
+
if (msg.type === "host_transfer_request") {
|
|
1279
|
+
pendingInteractions.register(msg.requestId, {
|
|
1280
|
+
conversation,
|
|
1281
|
+
conversationId,
|
|
1282
|
+
kind: "host_transfer",
|
|
1283
|
+
});
|
|
1284
|
+
return msg.requestId;
|
|
1285
|
+
}
|
|
1171
1286
|
return undefined;
|
|
1172
1287
|
}
|
|
1173
1288
|
|
|
1174
1289
|
/**
|
|
1175
1290
|
* Resolve the host_browser sender function for a conversation turn.
|
|
1176
1291
|
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1181
|
-
*
|
|
1292
|
+
* Transport selection:
|
|
1293
|
+
* 1. **WebSocket registry** — when the guardian has an active entry in
|
|
1294
|
+
* ChromeExtensionRegistry (self-hosted direct WS connection), the
|
|
1295
|
+
* registry-routed sender is returned. Frames go directly over the
|
|
1296
|
+
* WebSocket to the extension.
|
|
1297
|
+
* 2. **SSE event hub** — when no WebSocket connection exists but a
|
|
1298
|
+
* chrome-extension client is connected via SSE (cloud/platform mode),
|
|
1299
|
+
* the SSE hub sender (`onEvent`) is returned. The extension receives
|
|
1300
|
+
* `host_browser_request` frames as SSE events and POSTs results back
|
|
1301
|
+
* to `/v1/host-browser-result`.
|
|
1182
1302
|
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1186
|
-
*
|
|
1187
|
-
*
|
|
1188
|
-
* registry throws on a missing connection.
|
|
1189
|
-
*
|
|
1190
|
-
* This helper is interface-agnostic: both chrome-extension and macOS turns
|
|
1191
|
-
* can obtain a registry-routed sender when extension connectivity exists.
|
|
1192
|
-
* The `isRegistryRouted` flag lets the caller decide whether to set
|
|
1193
|
-
* `hostBrowserSenderOverride` and whether to provision a `HostBrowserProxy`
|
|
1194
|
-
* for interfaces that don't statically support host_browser (e.g. macOS).
|
|
1303
|
+
* When neither transport is available, `onEvent` is returned as the
|
|
1304
|
+
* default sender (used by macOS for its native host_browser path).
|
|
1305
|
+
* `hasSseExtension` is `false` in that case so the caller can avoid
|
|
1306
|
+
* provisioning a stale `HostBrowserProxy` for interfaces that don't
|
|
1307
|
+
* natively support host_browser.
|
|
1195
1308
|
*/
|
|
1196
1309
|
function resolveHostBrowserSender(
|
|
1197
1310
|
conversation: Conversation,
|
|
1198
1311
|
conversationId: string,
|
|
1199
|
-
|
|
1312
|
+
actorPrincipalId: string | undefined,
|
|
1200
1313
|
onEvent: (msg: ServerMessage) => void,
|
|
1201
1314
|
sourceInterface: InterfaceId,
|
|
1202
|
-
): {
|
|
1203
|
-
|
|
1315
|
+
): {
|
|
1316
|
+
sender: (msg: ServerMessage) => void;
|
|
1317
|
+
isRegistryRouted: boolean;
|
|
1318
|
+
hasSseExtension: boolean;
|
|
1319
|
+
} {
|
|
1204
1320
|
const guardianId =
|
|
1205
|
-
conversation.trustContext?.guardianPrincipalId ??
|
|
1206
|
-
authContext.actorPrincipalId;
|
|
1321
|
+
conversation.trustContext?.guardianPrincipalId ?? actorPrincipalId;
|
|
1207
1322
|
const hasExtensionConnection =
|
|
1208
1323
|
!!guardianId && !!getChromeExtensionRegistry().get(guardianId);
|
|
1209
1324
|
|
|
1210
|
-
//
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
// Build a registry-routed sender. The guardian principal ID is resolved
|
|
1219
|
-
// at send time rather than captured here so that queue-drain restores
|
|
1220
|
-
// (which re-fire this closure outside the original POST context) follow
|
|
1221
|
-
// the conversation's bound guardian identity rather than a stale
|
|
1222
|
-
// authContext.actorPrincipalId.
|
|
1223
|
-
const registrySender = (msg: ServerMessage): void => {
|
|
1224
|
-
const requestId = registerHostProxyPendingInteraction(
|
|
1225
|
-
msg,
|
|
1226
|
-
conversation,
|
|
1227
|
-
conversationId,
|
|
1228
|
-
);
|
|
1229
|
-
const gid =
|
|
1230
|
-
conversation.trustContext?.guardianPrincipalId ??
|
|
1231
|
-
authContext.actorPrincipalId;
|
|
1232
|
-
if (!gid) {
|
|
1233
|
-
if (requestId) pendingInteractions.resolve(requestId);
|
|
1234
|
-
throw new Error(
|
|
1235
|
-
"host_browser send skipped: no guardianId on AuthContext",
|
|
1236
|
-
);
|
|
1237
|
-
}
|
|
1238
|
-
const ok = getChromeExtensionRegistry().send(gid, msg);
|
|
1239
|
-
if (!ok) {
|
|
1240
|
-
if (requestId) pendingInteractions.resolve(requestId);
|
|
1241
|
-
throw new Error(
|
|
1242
|
-
`host_browser send failed: no active connection for guardian ${gid}`,
|
|
1325
|
+
// Priority 1: WebSocket registry — direct WS to the extension.
|
|
1326
|
+
if (hasExtensionConnection) {
|
|
1327
|
+
const registrySender = (msg: ServerMessage): void => {
|
|
1328
|
+
const requestId = registerHostProxyPendingInteraction(
|
|
1329
|
+
msg,
|
|
1330
|
+
conversation,
|
|
1331
|
+
conversationId,
|
|
1243
1332
|
);
|
|
1244
|
-
|
|
1245
|
-
|
|
1333
|
+
const gid =
|
|
1334
|
+
conversation.trustContext?.guardianPrincipalId ?? actorPrincipalId;
|
|
1335
|
+
if (!gid) {
|
|
1336
|
+
if (requestId) pendingInteractions.resolve(requestId);
|
|
1337
|
+
throw new Error(
|
|
1338
|
+
"host_browser send skipped: no guardianId on AuthContext",
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
const ok = getChromeExtensionRegistry().send(gid, msg);
|
|
1342
|
+
if (!ok) {
|
|
1343
|
+
if (requestId) pendingInteractions.resolve(requestId);
|
|
1344
|
+
throw new Error(
|
|
1345
|
+
`host_browser send failed: no active connection for guardian ${gid}`,
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
return {
|
|
1350
|
+
sender: registrySender,
|
|
1351
|
+
isRegistryRouted: true,
|
|
1352
|
+
hasSseExtension: false,
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1246
1355
|
|
|
1247
|
-
|
|
1356
|
+
// Priority 2: SSE-connected chrome extension (cloud/platform mode).
|
|
1357
|
+
// Check the ClientRegistry for a chrome-extension client specifically —
|
|
1358
|
+
// getMostRecentByCapability("host_browser") would also match macOS
|
|
1359
|
+
// clients, which handle browser frames through their own native path.
|
|
1360
|
+
const hasSseExtension =
|
|
1361
|
+
canServiceSseBrowser(sourceInterface) &&
|
|
1362
|
+
!!getClientRegistry().getMostRecentByInterface("chrome-extension");
|
|
1363
|
+
|
|
1364
|
+
return { sender: onEvent, isRegistryRouted: false, hasSseExtension };
|
|
1248
1365
|
}
|
|
1249
1366
|
|
|
1250
1367
|
/**
|
|
@@ -1271,7 +1388,7 @@ function resolveHostBrowserSender(
|
|
|
1271
1388
|
* failure. The route handler path must never reject because of a
|
|
1272
1389
|
* best-effort persistence step.
|
|
1273
1390
|
*/
|
|
1274
|
-
function persistOnboardingArtifacts(onboarding: {
|
|
1391
|
+
export function persistOnboardingArtifacts(onboarding: {
|
|
1275
1392
|
tools: string[];
|
|
1276
1393
|
tasks: string[];
|
|
1277
1394
|
tone: string;
|
|
@@ -1283,31 +1400,49 @@ function persistOnboardingArtifacts(onboarding: {
|
|
|
1283
1400
|
const assistantName = onboarding.assistantName?.trim();
|
|
1284
1401
|
if (assistantName) {
|
|
1285
1402
|
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
1286
|
-
|
|
1287
|
-
|
|
1403
|
+
try {
|
|
1404
|
+
if (existsSync(identityPath)) {
|
|
1405
|
+
const content = readFileSync(identityPath, "utf-8");
|
|
1406
|
+
const updated = content.replace(
|
|
1407
|
+
/^- (?:\*\*)?Name:(?:\*\*)?\s*.*$/m,
|
|
1408
|
+
() => `- **Name:** ${assistantName}`,
|
|
1409
|
+
);
|
|
1410
|
+
if (updated !== content) {
|
|
1411
|
+
writeFileSync(identityPath, updated, "utf-8");
|
|
1412
|
+
}
|
|
1413
|
+
} else {
|
|
1288
1414
|
writeFileSync(
|
|
1289
1415
|
identityPath,
|
|
1290
|
-
`# Identity\n\n- Name
|
|
1416
|
+
`# Identity\n\n- **Name:** ${assistantName}\n`,
|
|
1291
1417
|
"utf-8",
|
|
1292
1418
|
);
|
|
1293
|
-
} catch (err) {
|
|
1294
|
-
log.warn(
|
|
1295
|
-
{ err, identityPath },
|
|
1296
|
-
"Failed to seed IDENTITY.md from onboarding",
|
|
1297
|
-
);
|
|
1298
1419
|
}
|
|
1420
|
+
} catch (err) {
|
|
1421
|
+
log.warn(
|
|
1422
|
+
{ err, identityPath },
|
|
1423
|
+
"Failed to seed IDENTITY.md from onboarding",
|
|
1424
|
+
);
|
|
1299
1425
|
}
|
|
1300
1426
|
}
|
|
1301
1427
|
|
|
1302
1428
|
const userName = onboarding.userName?.trim();
|
|
1303
1429
|
if (userName) {
|
|
1304
1430
|
const userPath = getWorkspacePromptPath("USER.md");
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1431
|
+
try {
|
|
1432
|
+
if (existsSync(userPath)) {
|
|
1433
|
+
const content = readFileSync(userPath, "utf-8");
|
|
1434
|
+
const updated = content.replace(
|
|
1435
|
+
/^- (?:\*\*)?Name:(?:\*\*)?\s*.*$/m,
|
|
1436
|
+
() => `- **Name:** ${userName}`,
|
|
1437
|
+
);
|
|
1438
|
+
if (updated !== content) {
|
|
1439
|
+
writeFileSync(userPath, updated, "utf-8");
|
|
1440
|
+
}
|
|
1441
|
+
} else {
|
|
1442
|
+
writeFileSync(userPath, `# User\n\n- **Name:** ${userName}\n`, "utf-8");
|
|
1310
1443
|
}
|
|
1444
|
+
} catch (err) {
|
|
1445
|
+
log.warn({ err, userPath }, "Failed to seed USER.md from onboarding");
|
|
1311
1446
|
}
|
|
1312
1447
|
}
|
|
1313
1448
|
|
|
@@ -1320,15 +1455,13 @@ function persistOnboardingArtifacts(onboarding: {
|
|
|
1320
1455
|
}
|
|
1321
1456
|
|
|
1322
1457
|
export async function handleSendMessage(
|
|
1323
|
-
|
|
1458
|
+
{ body: rawBody, headers }: RouteHandlerArgs,
|
|
1324
1459
|
deps: {
|
|
1325
1460
|
sendMessageDeps?: SendMessageDeps;
|
|
1326
1461
|
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
1327
|
-
heartbeatService?: HeartbeatService;
|
|
1328
1462
|
},
|
|
1329
|
-
|
|
1330
|
-
)
|
|
1331
|
-
const body = (await req.json()) as {
|
|
1463
|
+
): Promise<unknown> {
|
|
1464
|
+
const body = (rawBody ?? {}) as {
|
|
1332
1465
|
conversationKey?: string;
|
|
1333
1466
|
content?: string;
|
|
1334
1467
|
attachmentIds?: string[];
|
|
@@ -1339,7 +1472,10 @@ export async function handleSendMessage(
|
|
|
1339
1472
|
bypassSecretCheck?: boolean;
|
|
1340
1473
|
hostHomeDir?: string;
|
|
1341
1474
|
hostUsername?: string;
|
|
1475
|
+
clientId?: string;
|
|
1342
1476
|
clientMessageId?: string;
|
|
1477
|
+
inferenceProfile?: string | null;
|
|
1478
|
+
riskThreshold?: string;
|
|
1343
1479
|
onboarding?: {
|
|
1344
1480
|
tools: string[];
|
|
1345
1481
|
tasks: string[];
|
|
@@ -1349,35 +1485,70 @@ export async function handleSendMessage(
|
|
|
1349
1485
|
};
|
|
1350
1486
|
};
|
|
1351
1487
|
|
|
1488
|
+
const actorPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
1489
|
+
const principalType = headers?.["x-vellum-principal-type"];
|
|
1490
|
+
|
|
1352
1491
|
const { conversationKey, content, attachmentIds } = body;
|
|
1353
1492
|
const clientMessageId =
|
|
1354
1493
|
typeof body.clientMessageId === "string" ? body.clientMessageId : undefined;
|
|
1494
|
+
const requestedInferenceProfile =
|
|
1495
|
+
typeof body.inferenceProfile === "string"
|
|
1496
|
+
? body.inferenceProfile
|
|
1497
|
+
: undefined;
|
|
1498
|
+
const requestedRiskThreshold = body.riskThreshold;
|
|
1499
|
+
if (
|
|
1500
|
+
body.inferenceProfile != null &&
|
|
1501
|
+
typeof body.inferenceProfile !== "string"
|
|
1502
|
+
) {
|
|
1503
|
+
throw new BadRequestError(
|
|
1504
|
+
"inferenceProfile must be a non-empty string or null",
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
if (requestedInferenceProfile === "") {
|
|
1508
|
+
throw new BadRequestError(
|
|
1509
|
+
"inferenceProfile must be a non-empty string or null",
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
if (requestedInferenceProfile !== undefined) {
|
|
1513
|
+
const profiles = getConfig().llm.profiles ?? {};
|
|
1514
|
+
if (
|
|
1515
|
+
!Object.prototype.hasOwnProperty.call(profiles, requestedInferenceProfile)
|
|
1516
|
+
) {
|
|
1517
|
+
throw new BadRequestError(
|
|
1518
|
+
`Profile "${requestedInferenceProfile}" is not defined in llm.profiles`,
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
if (
|
|
1523
|
+
requestedRiskThreshold !== undefined &&
|
|
1524
|
+
!isValidRiskThreshold(requestedRiskThreshold)
|
|
1525
|
+
) {
|
|
1526
|
+
throw new BadRequestError(
|
|
1527
|
+
`riskThreshold must be one of: ${VALID_RISK_THRESHOLDS.join(", ")}`,
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1355
1530
|
if (!body.sourceChannel || typeof body.sourceChannel !== "string") {
|
|
1356
|
-
|
|
1531
|
+
throw new BadRequestError("sourceChannel is required");
|
|
1357
1532
|
}
|
|
1358
1533
|
const sourceChannel = parseChannelId(body.sourceChannel);
|
|
1359
1534
|
|
|
1360
1535
|
if (!sourceChannel) {
|
|
1361
|
-
|
|
1362
|
-
"BAD_REQUEST",
|
|
1536
|
+
throw new BadRequestError(
|
|
1363
1537
|
`Invalid sourceChannel: ${
|
|
1364
1538
|
body.sourceChannel
|
|
1365
1539
|
}. Valid values: ${CHANNEL_IDS.join(", ")}`,
|
|
1366
|
-
400,
|
|
1367
1540
|
);
|
|
1368
1541
|
}
|
|
1369
1542
|
|
|
1370
1543
|
if (!body.interface || typeof body.interface !== "string") {
|
|
1371
|
-
|
|
1544
|
+
throw new BadRequestError("interface is required");
|
|
1372
1545
|
}
|
|
1373
1546
|
const sourceInterface = parseInterfaceId(body.interface);
|
|
1374
1547
|
if (!sourceInterface) {
|
|
1375
|
-
|
|
1376
|
-
"BAD_REQUEST",
|
|
1548
|
+
throw new BadRequestError(
|
|
1377
1549
|
`Invalid interface: ${body.interface}. Valid values: ${INTERFACE_IDS.join(
|
|
1378
1550
|
", ",
|
|
1379
1551
|
)}`,
|
|
1380
|
-
400,
|
|
1381
1552
|
);
|
|
1382
1553
|
}
|
|
1383
1554
|
|
|
@@ -1389,7 +1560,7 @@ export async function handleSendMessage(
|
|
|
1389
1560
|
|
|
1390
1561
|
// Reject non-string content values (numbers, objects, etc.)
|
|
1391
1562
|
if (content != null && typeof content !== "string") {
|
|
1392
|
-
|
|
1563
|
+
throw new BadRequestError("content must be a string");
|
|
1393
1564
|
}
|
|
1394
1565
|
|
|
1395
1566
|
const trimmedContent = typeof content === "string" ? content.trim() : "";
|
|
@@ -1397,23 +1568,17 @@ export async function handleSendMessage(
|
|
|
1397
1568
|
Array.isArray(attachmentIds) && attachmentIds.length > 0;
|
|
1398
1569
|
|
|
1399
1570
|
if (trimmedContent.length === 0 && !hasAttachments) {
|
|
1400
|
-
|
|
1401
|
-
"BAD_REQUEST",
|
|
1402
|
-
"content or attachmentIds is required",
|
|
1403
|
-
400,
|
|
1404
|
-
);
|
|
1571
|
+
throw new BadRequestError("content or attachmentIds is required");
|
|
1405
1572
|
}
|
|
1406
1573
|
|
|
1407
1574
|
// Validate that all attachment IDs resolve
|
|
1408
1575
|
if (hasAttachments) {
|
|
1409
|
-
const resolved =
|
|
1576
|
+
const resolved = getAttachmentsByIds(attachmentIds);
|
|
1410
1577
|
if (resolved.length !== attachmentIds.length) {
|
|
1411
1578
|
const resolvedIds = new Set(resolved.map((a) => a.id));
|
|
1412
1579
|
const missing = attachmentIds.filter((id) => !resolvedIds.has(id));
|
|
1413
|
-
|
|
1414
|
-
"BAD_REQUEST",
|
|
1580
|
+
throw new BadRequestError(
|
|
1415
1581
|
`Attachment IDs not found: ${missing.join(", ")}`,
|
|
1416
|
-
400,
|
|
1417
1582
|
);
|
|
1418
1583
|
}
|
|
1419
1584
|
}
|
|
@@ -1422,36 +1587,52 @@ export async function handleSendMessage(
|
|
|
1422
1587
|
if (trimmedContent.length > 0 && !body.bypassSecretCheck) {
|
|
1423
1588
|
const ingressResult = checkIngressForSecrets(trimmedContent);
|
|
1424
1589
|
if (ingressResult.blocked) {
|
|
1425
|
-
return
|
|
1426
|
-
{
|
|
1590
|
+
return new RouteResponse(
|
|
1591
|
+
JSON.stringify({
|
|
1427
1592
|
accepted: false,
|
|
1428
1593
|
error: "secret_blocked",
|
|
1429
1594
|
message: ingressResult.userNotice,
|
|
1430
1595
|
detectedTypes: ingressResult.detectedTypes,
|
|
1431
|
-
},
|
|
1432
|
-
{
|
|
1596
|
+
}),
|
|
1597
|
+
{ "content-type": "application/json" },
|
|
1598
|
+
422,
|
|
1433
1599
|
);
|
|
1434
1600
|
}
|
|
1435
1601
|
}
|
|
1436
1602
|
|
|
1437
1603
|
if (!deps.sendMessageDeps) {
|
|
1438
|
-
|
|
1439
|
-
"SERVICE_UNAVAILABLE",
|
|
1604
|
+
throw new RouteError(
|
|
1440
1605
|
"Message processing is not available",
|
|
1606
|
+
"SERVICE_UNAVAILABLE",
|
|
1441
1607
|
503,
|
|
1442
1608
|
);
|
|
1443
1609
|
}
|
|
1444
1610
|
|
|
1445
1611
|
// Desktop messages are always from the guardian — reset the heartbeat
|
|
1446
1612
|
// timer so the next heartbeat is a full interval after this interaction.
|
|
1447
|
-
|
|
1613
|
+
HeartbeatService.getInstance()?.resetTimer();
|
|
1448
1614
|
|
|
1449
|
-
const conversationType =
|
|
1450
|
-
body.conversationType === "private" ? ("private" as const) : undefined;
|
|
1451
1615
|
const mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1452
|
-
conversationType,
|
|
1616
|
+
conversationType: "standard",
|
|
1453
1617
|
});
|
|
1454
1618
|
|
|
1619
|
+
if (requestedRiskThreshold !== undefined) {
|
|
1620
|
+
const result = await ipcCall("set_conversation_threshold", {
|
|
1621
|
+
conversationId: mapping.conversationId,
|
|
1622
|
+
threshold: requestedRiskThreshold,
|
|
1623
|
+
});
|
|
1624
|
+
if (result === undefined) {
|
|
1625
|
+
log.error(
|
|
1626
|
+
{
|
|
1627
|
+
conversationId: mapping.conversationId,
|
|
1628
|
+
threshold: requestedRiskThreshold,
|
|
1629
|
+
},
|
|
1630
|
+
"Failed to set conversation risk threshold override via gateway IPC",
|
|
1631
|
+
);
|
|
1632
|
+
throw new InternalError("Failed to persist risk threshold override");
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1455
1636
|
const smDeps = deps.sendMessageDeps;
|
|
1456
1637
|
|
|
1457
1638
|
// Notify all connected clients that the conversation list changed when
|
|
@@ -1500,25 +1681,33 @@ export async function handleSendMessage(
|
|
|
1500
1681
|
{ transport },
|
|
1501
1682
|
);
|
|
1502
1683
|
|
|
1684
|
+
if (requestedInferenceProfile !== undefined) {
|
|
1685
|
+
setConversationInferenceProfile(
|
|
1686
|
+
mapping.conversationId,
|
|
1687
|
+
requestedInferenceProfile,
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1503
1691
|
// Store pre-chat onboarding context on the conversation when this is the
|
|
1504
|
-
// very first message (no prior messages loaded).
|
|
1505
|
-
//
|
|
1506
|
-
//
|
|
1507
|
-
//
|
|
1508
|
-
//
|
|
1509
|
-
|
|
1510
|
-
conversation.
|
|
1511
|
-
|
|
1692
|
+
// very first message (no prior messages loaded). Artifact persistence
|
|
1693
|
+
// (IDENTITY.md, USER.md, sidecar) is deferred: on the canned greeting
|
|
1694
|
+
// path it runs inside the setTimeout right before warmPromptCache() so
|
|
1695
|
+
// the warmed system prompt includes the identity; on the normal LLM
|
|
1696
|
+
// path it runs immediately before inference starts.
|
|
1697
|
+
const isFirstOnboarding =
|
|
1698
|
+
!!body.onboarding && conversation.messages.length === 0;
|
|
1699
|
+
if (isFirstOnboarding) {
|
|
1700
|
+
conversation.setOnboardingContext(body.onboarding!);
|
|
1512
1701
|
}
|
|
1513
1702
|
|
|
1514
1703
|
// Resolve guardian context from the AuthContext's actorPrincipalId.
|
|
1515
1704
|
// The JWT-verified principal is used as the sender identity through
|
|
1516
1705
|
// the same trust resolution pipeline that channel ingress uses.
|
|
1517
|
-
if (
|
|
1706
|
+
if (actorPrincipalId) {
|
|
1518
1707
|
// Dev bypass (HTTP auth disabled): the synthetic "dev-bypass" principal
|
|
1519
1708
|
// won't match any guardian binding. Resolve from the local guardian
|
|
1520
1709
|
// binding instead, which produces the correct guardian trust context.
|
|
1521
|
-
if (isHttpAuthDisabled() &&
|
|
1710
|
+
if (isHttpAuthDisabled() && actorPrincipalId === "dev-bypass") {
|
|
1522
1711
|
conversation.setTrustContext(resolveLocalTrustContext(sourceChannel));
|
|
1523
1712
|
} else {
|
|
1524
1713
|
const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
@@ -1526,24 +1715,24 @@ export async function handleSendMessage(
|
|
|
1526
1715
|
assistantId,
|
|
1527
1716
|
sourceChannel: "vellum",
|
|
1528
1717
|
conversationExternalId: "local",
|
|
1529
|
-
actorExternalId:
|
|
1718
|
+
actorExternalId: actorPrincipalId,
|
|
1530
1719
|
});
|
|
1531
1720
|
if (trustCtx.trustClass === "unknown") {
|
|
1532
1721
|
// Attempt to heal guardian binding drift: after a DB reset the
|
|
1533
1722
|
// guardian binding gets a new vellum-principal-* UUID while the
|
|
1534
1723
|
// client still holds a valid JWT with the old one. The signing
|
|
1535
1724
|
// key survives the reset, so the JWT is authentic — just stale.
|
|
1536
|
-
const healed = healGuardianBindingDrift(
|
|
1725
|
+
const healed = healGuardianBindingDrift(actorPrincipalId);
|
|
1537
1726
|
if (healed) {
|
|
1538
1727
|
trustCtx = resolveTrustContext({
|
|
1539
1728
|
assistantId,
|
|
1540
1729
|
sourceChannel: "vellum",
|
|
1541
1730
|
conversationExternalId: "local",
|
|
1542
|
-
actorExternalId:
|
|
1731
|
+
actorExternalId: actorPrincipalId,
|
|
1543
1732
|
});
|
|
1544
1733
|
log.info(
|
|
1545
1734
|
{
|
|
1546
|
-
actorPrincipalId:
|
|
1735
|
+
actorPrincipalId: actorPrincipalId,
|
|
1547
1736
|
trustClass: trustCtx.trustClass,
|
|
1548
1737
|
},
|
|
1549
1738
|
"Trust re-resolved after guardian binding drift heal",
|
|
@@ -1551,10 +1740,10 @@ export async function handleSendMessage(
|
|
|
1551
1740
|
} else {
|
|
1552
1741
|
log.warn(
|
|
1553
1742
|
{
|
|
1554
|
-
actorPrincipalId:
|
|
1743
|
+
actorPrincipalId: actorPrincipalId,
|
|
1555
1744
|
sourceChannel,
|
|
1556
1745
|
trustClass: trustCtx.trustClass,
|
|
1557
|
-
principalType:
|
|
1746
|
+
principalType: principalType,
|
|
1558
1747
|
},
|
|
1559
1748
|
"JWT-verified actor resolved to unknown trust class — possible guardian binding drift (e.g. DB reset without re-bootstrap)",
|
|
1560
1749
|
);
|
|
@@ -1593,17 +1782,19 @@ export async function handleSendMessage(
|
|
|
1593
1782
|
conversation.setHostBashProxy(undefined);
|
|
1594
1783
|
}
|
|
1595
1784
|
// Resolve the host_browser sender — registry-routed when the guardian has
|
|
1596
|
-
// an active extension connection, SSE hub
|
|
1597
|
-
//
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1785
|
+
// an active WS extension connection, SSE hub when a chrome-extension is
|
|
1786
|
+
// connected via SSE (cloud mode), or SSE hub as default for macOS.
|
|
1787
|
+
const {
|
|
1788
|
+
sender: browserProxySendToClient,
|
|
1789
|
+
isRegistryRouted,
|
|
1790
|
+
hasSseExtension,
|
|
1791
|
+
} = resolveHostBrowserSender(
|
|
1792
|
+
conversation,
|
|
1793
|
+
mapping.conversationId,
|
|
1794
|
+
actorPrincipalId,
|
|
1795
|
+
onEvent,
|
|
1796
|
+
sourceInterface,
|
|
1797
|
+
);
|
|
1607
1798
|
|
|
1608
1799
|
// Stash the registry-routed sender on the conversation so queue-drain
|
|
1609
1800
|
// restores (which run outside of conversation-routes.ts and only have
|
|
@@ -1618,17 +1809,18 @@ export async function handleSendMessage(
|
|
|
1618
1809
|
conversation.hostBrowserSenderOverride = undefined;
|
|
1619
1810
|
}
|
|
1620
1811
|
|
|
1621
|
-
// Provision the host browser proxy
|
|
1622
|
-
//
|
|
1623
|
-
//
|
|
1624
|
-
//
|
|
1625
|
-
//
|
|
1626
|
-
//
|
|
1627
|
-
//
|
|
1628
|
-
//
|
|
1812
|
+
// Provision the host browser proxy when a viable transport exists:
|
|
1813
|
+
// - macOS: natively supports host_browser via its own SSE path
|
|
1814
|
+
// - WS registry: extension connected via direct WebSocket
|
|
1815
|
+
// - SSE extension: chrome extension connected via SSE (cloud mode)
|
|
1816
|
+
//
|
|
1817
|
+
// For chrome-extension, require an active transport (WS or SSE). Without
|
|
1818
|
+
// one, host_browser_request frames would be emitted to the SSE hub with
|
|
1819
|
+
// no consumer, causing a 30s proxy timeout instead of failing fast.
|
|
1629
1820
|
const shouldProvisionBrowserProxy =
|
|
1630
|
-
supportsHostProxy(sourceInterface
|
|
1631
|
-
(canServiceRegistryBrowser(sourceInterface) && isRegistryRouted)
|
|
1821
|
+
supportsHostProxy(sourceInterface) ||
|
|
1822
|
+
(canServiceRegistryBrowser(sourceInterface) && isRegistryRouted) ||
|
|
1823
|
+
hasSseExtension;
|
|
1632
1824
|
if (shouldProvisionBrowserProxy) {
|
|
1633
1825
|
if (!conversation.isProcessing() || !conversation.hostBrowserProxy) {
|
|
1634
1826
|
const browserProxy = new HostBrowserProxy(
|
|
@@ -1649,8 +1841,15 @@ export async function handleSendMessage(
|
|
|
1649
1841
|
});
|
|
1650
1842
|
conversation.setHostFileProxy(fileProxy);
|
|
1651
1843
|
}
|
|
1844
|
+
if (!conversation.isProcessing() || !conversation.getHostTransferProxy()) {
|
|
1845
|
+
const transferProxy = new HostTransferProxy(onEvent, (requestId) => {
|
|
1846
|
+
pendingInteractions.resolve(requestId);
|
|
1847
|
+
});
|
|
1848
|
+
conversation.setHostTransferProxy(transferProxy);
|
|
1849
|
+
}
|
|
1652
1850
|
} else if (!conversation.isProcessing()) {
|
|
1653
1851
|
conversation.setHostFileProxy(undefined);
|
|
1852
|
+
conversation.setHostTransferProxy(undefined);
|
|
1654
1853
|
}
|
|
1655
1854
|
if (supportsHostProxy(sourceInterface, "host_cu")) {
|
|
1656
1855
|
if (!conversation.isProcessing() || !conversation.hostCuProxy) {
|
|
@@ -1688,9 +1887,10 @@ export async function handleSendMessage(
|
|
|
1688
1887
|
skipProxySenderUpdate: preservingProxies,
|
|
1689
1888
|
});
|
|
1690
1889
|
// Re-enable the browser proxy for turns that provisioned one. This covers:
|
|
1890
|
+
// - macOS: always provisioned (SSE sender or registry-routed when extension
|
|
1891
|
+
// is connected)
|
|
1691
1892
|
// - chrome-extension: natively supports host_browser (non-interactive but
|
|
1692
1893
|
// has a connected client for host_browser_request events)
|
|
1693
|
-
// - macOS with extension: provisioned above when isRegistryRouted is true
|
|
1694
1894
|
//
|
|
1695
1895
|
// The helper bypasses the `hasNoClient` gate so chrome-extension turns can
|
|
1696
1896
|
// drive the browser via CDP without leaking host_bash/host_file tool
|
|
@@ -1703,97 +1903,103 @@ export async function handleSendMessage(
|
|
|
1703
1903
|
|
|
1704
1904
|
// ── Canned first-greeting fast path ──
|
|
1705
1905
|
// On a completely fresh workspace, skip LLM inference for the macOS
|
|
1706
|
-
// wake-up greeting and return a pre-written response.
|
|
1707
|
-
//
|
|
1906
|
+
// wake-up greeting and return a pre-written response. When onboarding
|
|
1907
|
+
// context is present the greeting is personalized using the selections;
|
|
1908
|
+
// otherwise a generic greeting is served. Both paths are instant.
|
|
1708
1909
|
if (isWakeUpGreeting(trimmedContent, conversation.getMessages().length)) {
|
|
1709
|
-
const cannedGreeting = getCannedFirstGreeting();
|
|
1710
|
-
if (cannedGreeting) {
|
|
1711
|
-
conversation.processing = true;
|
|
1712
|
-
let cleanupDeferred = false;
|
|
1713
|
-
try {
|
|
1714
|
-
const provenance = provenanceFromTrustContext(
|
|
1715
|
-
conversation.trustContext,
|
|
1716
|
-
);
|
|
1717
|
-
const channelMeta = {
|
|
1718
|
-
...provenance,
|
|
1719
|
-
userMessageChannel: sourceChannel,
|
|
1720
|
-
assistantMessageChannel: sourceChannel,
|
|
1721
|
-
userMessageInterface: sourceInterface,
|
|
1722
|
-
assistantMessageInterface: sourceInterface,
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
const rawContent = content ?? "";
|
|
1726
|
-
const attachments = hasAttachments
|
|
1727
|
-
? smDeps.resolveAttachments(attachmentIds)
|
|
1728
|
-
: [];
|
|
1729
|
-
const userMsg = createUserMessage(rawContent, attachments);
|
|
1730
|
-
const persisted = await addMessage(
|
|
1731
|
-
mapping.conversationId,
|
|
1732
|
-
"user",
|
|
1733
|
-
JSON.stringify(userMsg.content),
|
|
1734
|
-
channelMeta,
|
|
1735
|
-
);
|
|
1736
|
-
conversation.getMessages().push(userMsg);
|
|
1910
|
+
const cannedGreeting = getCannedFirstGreeting(body.onboarding ?? undefined);
|
|
1737
1911
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1912
|
+
conversation.processing = true;
|
|
1913
|
+
let cleanupDeferred = false;
|
|
1914
|
+
try {
|
|
1915
|
+
const provenance = provenanceFromTrustContext(conversation.trustContext);
|
|
1916
|
+
const channelMeta = {
|
|
1917
|
+
...provenance,
|
|
1918
|
+
userMessageChannel: sourceChannel,
|
|
1919
|
+
assistantMessageChannel: sourceChannel,
|
|
1920
|
+
userMessageInterface: sourceInterface,
|
|
1921
|
+
assistantMessageInterface: sourceInterface,
|
|
1922
|
+
};
|
|
1746
1923
|
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1924
|
+
const rawContent = content ?? "";
|
|
1925
|
+
const attachments = hasAttachments
|
|
1926
|
+
? smDeps.resolveAttachments(attachmentIds)
|
|
1927
|
+
: [];
|
|
1928
|
+
const userMsg = createUserMessage(rawContent, attachments);
|
|
1929
|
+
const persisted = await addMessage(
|
|
1930
|
+
mapping.conversationId,
|
|
1931
|
+
"user",
|
|
1932
|
+
JSON.stringify(userMsg.content),
|
|
1933
|
+
channelMeta,
|
|
1934
|
+
);
|
|
1935
|
+
conversation.getMessages().push(userMsg);
|
|
1755
1936
|
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1937
|
+
setConversationOriginChannelIfUnset(
|
|
1938
|
+
mapping.conversationId,
|
|
1939
|
+
sourceChannel,
|
|
1940
|
+
);
|
|
1941
|
+
setConversationOriginInterfaceIfUnset(
|
|
1942
|
+
mapping.conversationId,
|
|
1943
|
+
sourceInterface,
|
|
1944
|
+
);
|
|
1761
1945
|
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
"canned-greeting queue drain",
|
|
1779
|
-
);
|
|
1780
|
-
}, 0);
|
|
1946
|
+
const conversationId = mapping.conversationId;
|
|
1947
|
+
|
|
1948
|
+
const assistantMsg = createAssistantMessage(cannedGreeting);
|
|
1949
|
+
await addMessage(
|
|
1950
|
+
mapping.conversationId,
|
|
1951
|
+
"assistant",
|
|
1952
|
+
JSON.stringify(assistantMsg.content),
|
|
1953
|
+
channelMeta,
|
|
1954
|
+
);
|
|
1955
|
+
conversation.getMessages().push(assistantMsg);
|
|
1956
|
+
|
|
1957
|
+
const response = {
|
|
1958
|
+
accepted: true,
|
|
1959
|
+
messageId: persisted.id,
|
|
1960
|
+
conversationId,
|
|
1961
|
+
};
|
|
1781
1962
|
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1963
|
+
setTimeout(() => {
|
|
1964
|
+
onEvent({
|
|
1965
|
+
type: "user_message_echo",
|
|
1966
|
+
text: rawContent,
|
|
1967
|
+
conversationId,
|
|
1968
|
+
messageId: persisted.id,
|
|
1969
|
+
clientMessageId,
|
|
1970
|
+
});
|
|
1971
|
+
onEvent({ type: "assistant_text_delta", text: cannedGreeting });
|
|
1972
|
+
onEvent({ type: "message_complete", conversationId });
|
|
1973
|
+
conversation.processing = false;
|
|
1974
|
+
silentlyWithLog(
|
|
1975
|
+
conversation.drainQueue(),
|
|
1976
|
+
"canned-greeting queue drain",
|
|
1785
1977
|
);
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if (!cleanupDeferred && conversation.processing) {
|
|
1790
|
-
conversation.processing = false;
|
|
1791
|
-
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1978
|
+
|
|
1979
|
+
if (isFirstOnboarding) {
|
|
1980
|
+
persistOnboardingArtifacts(body.onboarding!);
|
|
1792
1981
|
}
|
|
1982
|
+
conversation.warmPromptCache();
|
|
1983
|
+
}, 0);
|
|
1984
|
+
|
|
1985
|
+
log.info(
|
|
1986
|
+
{ conversationId, personalized: !!body.onboarding },
|
|
1987
|
+
"Served canned first greeting — skipped LLM inference",
|
|
1988
|
+
);
|
|
1989
|
+
cleanupDeferred = true;
|
|
1990
|
+
return response;
|
|
1991
|
+
} finally {
|
|
1992
|
+
if (!cleanupDeferred && conversation.processing) {
|
|
1993
|
+
conversation.processing = false;
|
|
1994
|
+
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1793
1995
|
}
|
|
1794
1996
|
}
|
|
1795
1997
|
}
|
|
1796
1998
|
|
|
1999
|
+
if (isFirstOnboarding) {
|
|
2000
|
+
persistOnboardingArtifacts(body.onboarding!);
|
|
2001
|
+
}
|
|
2002
|
+
|
|
1797
2003
|
const attachments = hasAttachments
|
|
1798
2004
|
? smDeps.resolveAttachments(attachmentIds)
|
|
1799
2005
|
: [];
|
|
@@ -1828,16 +2034,13 @@ export async function handleSendMessage(
|
|
|
1828
2034
|
verifiedActorPrincipalId,
|
|
1829
2035
|
});
|
|
1830
2036
|
if (inlineReplyResult.consumed) {
|
|
1831
|
-
return
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
},
|
|
1839
|
-
{ status: 202 },
|
|
1840
|
-
);
|
|
2037
|
+
return {
|
|
2038
|
+
accepted: true,
|
|
2039
|
+
conversationId: mapping.conversationId,
|
|
2040
|
+
...(inlineReplyResult.messageId
|
|
2041
|
+
? { messageId: inlineReplyResult.messageId }
|
|
2042
|
+
: {}),
|
|
2043
|
+
};
|
|
1841
2044
|
}
|
|
1842
2045
|
} catch (err) {
|
|
1843
2046
|
log.warn(
|
|
@@ -1869,9 +2072,10 @@ export async function handleSendMessage(
|
|
|
1869
2072
|
clientMessageId,
|
|
1870
2073
|
);
|
|
1871
2074
|
if (enqueueResult.rejected) {
|
|
1872
|
-
return
|
|
1873
|
-
{ accepted: false, error: "queue_full" },
|
|
1874
|
-
{
|
|
2075
|
+
return new RouteResponse(
|
|
2076
|
+
JSON.stringify({ accepted: false, error: "queue_full" }),
|
|
2077
|
+
{ "content-type": "application/json" },
|
|
2078
|
+
429,
|
|
1875
2079
|
);
|
|
1876
2080
|
}
|
|
1877
2081
|
|
|
@@ -1920,10 +2124,11 @@ export async function handleSendMessage(
|
|
|
1920
2124
|
);
|
|
1921
2125
|
}
|
|
1922
2126
|
|
|
1923
|
-
return
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
2127
|
+
return {
|
|
2128
|
+
accepted: true,
|
|
2129
|
+
queued: true,
|
|
2130
|
+
conversationId: mapping.conversationId,
|
|
2131
|
+
};
|
|
1927
2132
|
}
|
|
1928
2133
|
|
|
1929
2134
|
// Auto-deny pending confirmations for idle conversations. The legacy
|
|
@@ -2044,14 +2249,11 @@ export async function handleSendMessage(
|
|
|
2044
2249
|
? await buildModelInfoEvent()
|
|
2045
2250
|
: null;
|
|
2046
2251
|
|
|
2047
|
-
const response =
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
},
|
|
2053
|
-
{ status: 202 },
|
|
2054
|
-
);
|
|
2252
|
+
const response = {
|
|
2253
|
+
accepted: true,
|
|
2254
|
+
messageId: persisted.id,
|
|
2255
|
+
conversationId: mapping.conversationId,
|
|
2256
|
+
};
|
|
2055
2257
|
|
|
2056
2258
|
// Defer event publishing to next tick so the HTTP response reaches the
|
|
2057
2259
|
// client first. This ensures the client's serverToLocalConversationMap is
|
|
@@ -2165,14 +2367,11 @@ export async function handleSendMessage(
|
|
|
2165
2367
|
}
|
|
2166
2368
|
})();
|
|
2167
2369
|
|
|
2168
|
-
return
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
},
|
|
2174
|
-
{ status: 202 },
|
|
2175
|
-
);
|
|
2370
|
+
return {
|
|
2371
|
+
accepted: true,
|
|
2372
|
+
messageId: persisted.id,
|
|
2373
|
+
conversationId,
|
|
2374
|
+
};
|
|
2176
2375
|
}
|
|
2177
2376
|
|
|
2178
2377
|
const resolvedContent = slashResult.content;
|
|
@@ -2212,10 +2411,11 @@ export async function handleSendMessage(
|
|
|
2212
2411
|
);
|
|
2213
2412
|
});
|
|
2214
2413
|
|
|
2215
|
-
return
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2414
|
+
return {
|
|
2415
|
+
accepted: true,
|
|
2416
|
+
messageId,
|
|
2417
|
+
conversationId: mapping.conversationId,
|
|
2418
|
+
};
|
|
2219
2419
|
}
|
|
2220
2420
|
|
|
2221
2421
|
function escapeXmlContent(text: string): string {
|
|
@@ -2251,11 +2451,15 @@ async function generateLlmSuggestion(
|
|
|
2251
2451
|
`Write the user's next reply, focusing on the LAST question or call-to-action in the assistant message. Keep it short (under 15 words), casual, and in the user's voice. Respond in this exact format:\n\n` +
|
|
2252
2452
|
`<reply>YOUR_REPLY_HERE</reply>`;
|
|
2253
2453
|
|
|
2454
|
+
// Single user message only — no assistant-role prefill. Anthropic
|
|
2455
|
+
// rejects assistant prefill whenever the request triggers extended
|
|
2456
|
+
// thinking (e.g. Opus 4.x at `effort: "xhigh"`), and the call-site
|
|
2457
|
+
// config is user-controlled, so we can't statically guarantee a
|
|
2458
|
+
// prefill-safe model. Keep `stop_sequences: ["</reply>"]` as an
|
|
2459
|
+
// early-termination hint; the parser below handles both tagged and
|
|
2460
|
+
// untagged responses so untagged "casual answer" replies still work.
|
|
2254
2461
|
const response = await provider.sendMessage(
|
|
2255
|
-
[
|
|
2256
|
-
{ role: "user", content: [{ type: "text", text: userPrompt }] },
|
|
2257
|
-
{ role: "assistant", content: [{ type: "text", text: "<reply>" }] },
|
|
2258
|
-
],
|
|
2462
|
+
[{ role: "user", content: [{ type: "text", text: userPrompt }] }],
|
|
2259
2463
|
[], // no tools
|
|
2260
2464
|
systemPrompt,
|
|
2261
2465
|
{
|
|
@@ -2270,7 +2474,12 @@ async function generateLlmSuggestion(
|
|
|
2270
2474
|
|
|
2271
2475
|
const textBlock = response.content.find((b) => b.type === "text");
|
|
2272
2476
|
const raw = textBlock && "text" in textBlock ? textBlock.text : "";
|
|
2273
|
-
|
|
2477
|
+
// Prefer the content inside <reply>…</reply> when the model honors the
|
|
2478
|
+
// tag format. If the response has no tags, fall back to the raw text —
|
|
2479
|
+
// a plain "Sure, tomorrow works" without tags is still a valid chip.
|
|
2480
|
+
const tagMatch = raw.match(/<reply>([\s\S]*?)(?:<\/reply>|$)/i);
|
|
2481
|
+
const extracted = tagMatch ? tagMatch[1] : raw;
|
|
2482
|
+
const stripped = extracted
|
|
2274
2483
|
.replace(/<\/?reply>/gi, "")
|
|
2275
2484
|
.replace(/^["'`]+|["'`]+$/g, "")
|
|
2276
2485
|
.trim();
|
|
@@ -2293,54 +2502,39 @@ async function generateLlmSuggestion(
|
|
|
2293
2502
|
}
|
|
2294
2503
|
|
|
2295
2504
|
export async function handleGetSuggestion(
|
|
2296
|
-
|
|
2505
|
+
{ queryParams }: RouteHandlerArgs,
|
|
2297
2506
|
deps: {
|
|
2298
2507
|
suggestionCache: Map<string, string>;
|
|
2299
2508
|
suggestionInFlight: Map<string, Promise<string | null>>;
|
|
2300
2509
|
},
|
|
2301
|
-
): Promise<
|
|
2302
|
-
const
|
|
2510
|
+
): Promise<Record<string, unknown>> {
|
|
2511
|
+
const noSuggestion = {
|
|
2512
|
+
suggestion: null,
|
|
2513
|
+
messageId: null,
|
|
2514
|
+
source: "none" as const,
|
|
2515
|
+
};
|
|
2516
|
+
|
|
2517
|
+
const conversationKey = queryParams?.conversationKey;
|
|
2303
2518
|
if (!conversationKey) {
|
|
2304
|
-
|
|
2305
|
-
"BAD_REQUEST",
|
|
2306
|
-
"conversationKey query parameter is required",
|
|
2307
|
-
400,
|
|
2308
|
-
);
|
|
2519
|
+
throw new BadRequestError("conversationKey query parameter is required");
|
|
2309
2520
|
}
|
|
2310
2521
|
|
|
2311
2522
|
const mapping = getConversationByKey(conversationKey);
|
|
2312
|
-
if (!mapping)
|
|
2313
|
-
return Response.json({
|
|
2314
|
-
suggestion: null,
|
|
2315
|
-
messageId: null,
|
|
2316
|
-
source: "none" as const,
|
|
2317
|
-
});
|
|
2318
|
-
}
|
|
2523
|
+
if (!mapping) return noSuggestion;
|
|
2319
2524
|
|
|
2320
2525
|
const rawMessages = getMessages(mapping.conversationId);
|
|
2321
|
-
if (rawMessages.length === 0)
|
|
2322
|
-
return Response.json({
|
|
2323
|
-
suggestion: null,
|
|
2324
|
-
messageId: null,
|
|
2325
|
-
source: "none" as const,
|
|
2326
|
-
});
|
|
2327
|
-
}
|
|
2526
|
+
if (rawMessages.length === 0) return noSuggestion;
|
|
2328
2527
|
|
|
2329
2528
|
// Staleness check: compare requested messageId against the latest
|
|
2330
2529
|
// assistant message BEFORE filtering by text content. This ensures
|
|
2331
2530
|
// that a newer tool-only assistant turn (empty text) still causes
|
|
2332
2531
|
// older messageId requests to be correctly marked as stale.
|
|
2333
|
-
const requestedMessageId =
|
|
2532
|
+
const requestedMessageId = queryParams?.messageId;
|
|
2334
2533
|
if (requestedMessageId) {
|
|
2335
2534
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
2336
2535
|
if (rawMessages[i].role === "assistant") {
|
|
2337
2536
|
if (rawMessages[i].id !== requestedMessageId) {
|
|
2338
|
-
return
|
|
2339
|
-
suggestion: null,
|
|
2340
|
-
messageId: null,
|
|
2341
|
-
source: "none" as const,
|
|
2342
|
-
stale: true,
|
|
2343
|
-
});
|
|
2537
|
+
return { ...noSuggestion, stale: true };
|
|
2344
2538
|
}
|
|
2345
2539
|
break;
|
|
2346
2540
|
}
|
|
@@ -2368,22 +2562,13 @@ export async function handleGetSuggestion(
|
|
|
2368
2562
|
// If a messageId was requested and the first text-bearing assistant
|
|
2369
2563
|
// message is a *different* message, the request is stale.
|
|
2370
2564
|
if (requestedMessageId && msg.id !== requestedMessageId) {
|
|
2371
|
-
return
|
|
2372
|
-
suggestion: null,
|
|
2373
|
-
messageId: null,
|
|
2374
|
-
source: "none" as const,
|
|
2375
|
-
stale: true,
|
|
2376
|
-
});
|
|
2565
|
+
return { ...noSuggestion, stale: true };
|
|
2377
2566
|
}
|
|
2378
2567
|
|
|
2379
2568
|
// Return cached suggestion if we already generated one for this message
|
|
2380
2569
|
const cached = suggestionCache.get(msg.id);
|
|
2381
2570
|
if (cached !== undefined) {
|
|
2382
|
-
return
|
|
2383
|
-
suggestion: cached,
|
|
2384
|
-
messageId: msg.id,
|
|
2385
|
-
source: "llm" as const,
|
|
2386
|
-
});
|
|
2571
|
+
return { suggestion: cached, messageId: msg.id, source: "llm" as const };
|
|
2387
2572
|
}
|
|
2388
2573
|
|
|
2389
2574
|
// Find the most recent user message preceding this assistant turn so the
|
|
@@ -2427,11 +2612,11 @@ export async function handleGetSuggestion(
|
|
|
2427
2612
|
}
|
|
2428
2613
|
suggestionCache.set(msg.id, llmSuggestion);
|
|
2429
2614
|
|
|
2430
|
-
return
|
|
2615
|
+
return {
|
|
2431
2616
|
suggestion: llmSuggestion,
|
|
2432
2617
|
messageId: msg.id,
|
|
2433
2618
|
source: "llm" as const,
|
|
2434
|
-
}
|
|
2619
|
+
};
|
|
2435
2620
|
}
|
|
2436
2621
|
} catch (err) {
|
|
2437
2622
|
suggestionInFlight.delete(msg.id);
|
|
@@ -2447,18 +2632,10 @@ export async function handleGetSuggestion(
|
|
|
2447
2632
|
);
|
|
2448
2633
|
}
|
|
2449
2634
|
|
|
2450
|
-
return
|
|
2451
|
-
suggestion: null,
|
|
2452
|
-
messageId: null,
|
|
2453
|
-
source: "none" as const,
|
|
2454
|
-
});
|
|
2635
|
+
return noSuggestion;
|
|
2455
2636
|
}
|
|
2456
2637
|
|
|
2457
|
-
return
|
|
2458
|
-
suggestion: null,
|
|
2459
|
-
messageId: null,
|
|
2460
|
-
source: "none" as const,
|
|
2461
|
-
});
|
|
2638
|
+
return noSuggestion;
|
|
2462
2639
|
}
|
|
2463
2640
|
|
|
2464
2641
|
/**
|
|
@@ -2467,19 +2644,17 @@ export async function handleGetSuggestion(
|
|
|
2467
2644
|
* Full-text search across all conversations (message content + titles).
|
|
2468
2645
|
* Returns ranked results grouped by conversation, each with matching message excerpts.
|
|
2469
2646
|
*/
|
|
2470
|
-
function handleSearchConversations(
|
|
2471
|
-
|
|
2647
|
+
function handleSearchConversations({
|
|
2648
|
+
queryParams,
|
|
2649
|
+
}: RouteHandlerArgs): Record<string, unknown> {
|
|
2650
|
+
const query = queryParams?.q ?? "";
|
|
2472
2651
|
if (!query.trim()) {
|
|
2473
|
-
|
|
2652
|
+
throw new BadRequestError("q query parameter is required");
|
|
2474
2653
|
}
|
|
2475
2654
|
|
|
2476
|
-
const limit =
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
const maxMessagesPerConversation = url.searchParams.has(
|
|
2480
|
-
"maxMessagesPerConversation",
|
|
2481
|
-
)
|
|
2482
|
-
? Number(url.searchParams.get("maxMessagesPerConversation"))
|
|
2655
|
+
const limit = queryParams?.limit ? Number(queryParams.limit) : undefined;
|
|
2656
|
+
const maxMessagesPerConversation = queryParams?.maxMessagesPerConversation
|
|
2657
|
+
? Number(queryParams.maxMessagesPerConversation)
|
|
2483
2658
|
: undefined;
|
|
2484
2659
|
|
|
2485
2660
|
const results = searchConversations(query, {
|
|
@@ -2490,105 +2665,125 @@ function handleSearchConversations(url: URL): Response {
|
|
|
2490
2665
|
: {}),
|
|
2491
2666
|
});
|
|
2492
2667
|
|
|
2493
|
-
return
|
|
2668
|
+
return { query, results };
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// ---------------------------------------------------------------------------
|
|
2672
|
+
// Module-level state
|
|
2673
|
+
// ---------------------------------------------------------------------------
|
|
2674
|
+
|
|
2675
|
+
const suggestionCache = new Map<string, string>();
|
|
2676
|
+
const suggestionInFlight = new Map<string, Promise<string | null>>();
|
|
2677
|
+
|
|
2678
|
+
function resolveAttachments(attachmentIds: string[]) {
|
|
2679
|
+
const resolved = getAttachmentsByIds(attachmentIds, {
|
|
2680
|
+
hydrateFileData: true,
|
|
2681
|
+
});
|
|
2682
|
+
const sourcePaths = getSourcePathsForAttachments(attachmentIds);
|
|
2683
|
+
return resolved.map((a) => ({
|
|
2684
|
+
id: a.id,
|
|
2685
|
+
filename: a.originalFilename,
|
|
2686
|
+
mimeType: a.mimeType,
|
|
2687
|
+
data: a.dataBase64,
|
|
2688
|
+
...(sourcePaths.has(a.id) ? { filePath: sourcePaths.get(a.id) } : {}),
|
|
2689
|
+
}));
|
|
2494
2690
|
}
|
|
2495
2691
|
|
|
2496
2692
|
// ---------------------------------------------------------------------------
|
|
2497
2693
|
// Route definitions
|
|
2498
2694
|
// ---------------------------------------------------------------------------
|
|
2499
2695
|
|
|
2500
|
-
export
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
{
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
"
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
.describe("Whether older messages exist beyond this page"),
|
|
2522
|
-
oldestTimestamp: z
|
|
2523
|
-
.number()
|
|
2524
|
-
.optional()
|
|
2525
|
-
.describe(
|
|
2526
|
-
"Timestamp of the oldest message in this page (ms since epoch)",
|
|
2527
|
-
),
|
|
2528
|
-
oldestMessageId: z
|
|
2529
|
-
.string()
|
|
2530
|
-
.optional()
|
|
2531
|
-
.describe("ID of the oldest message in this page"),
|
|
2532
|
-
}),
|
|
2533
|
-
handler: ({ url }) => handleListMessages(url, deps.interfacesDir),
|
|
2534
|
-
},
|
|
2535
|
-
{
|
|
2536
|
-
endpoint: "messages",
|
|
2537
|
-
method: "POST",
|
|
2538
|
-
summary: "Send a message",
|
|
2539
|
-
description:
|
|
2540
|
-
"Send a user message to a conversation and trigger the assistant response.",
|
|
2541
|
-
tags: ["messages"],
|
|
2542
|
-
requestBody: z.object({
|
|
2543
|
-
conversationKey: z.string().optional(),
|
|
2544
|
-
content: z.string().describe("Message text content"),
|
|
2545
|
-
attachments: z
|
|
2546
|
-
.array(z.unknown())
|
|
2547
|
-
.describe("Optional file attachments")
|
|
2548
|
-
.optional(),
|
|
2549
|
-
conversationType: z.string().optional(),
|
|
2550
|
-
slashCommand: z.string().optional(),
|
|
2551
|
-
}),
|
|
2552
|
-
handler: async ({ req, authContext }) =>
|
|
2553
|
-
handleSendMessage(
|
|
2554
|
-
req,
|
|
2555
|
-
{
|
|
2556
|
-
sendMessageDeps: deps.sendMessageDeps,
|
|
2557
|
-
approvalConversationGenerator: deps.approvalConversationGenerator,
|
|
2558
|
-
heartbeatService: deps.getHeartbeatService?.(),
|
|
2559
|
-
},
|
|
2560
|
-
authContext,
|
|
2696
|
+
export const ROUTES: RouteDefinition[] = [
|
|
2697
|
+
{
|
|
2698
|
+
operationId: "messages_get",
|
|
2699
|
+
endpoint: "messages",
|
|
2700
|
+
method: "GET",
|
|
2701
|
+
summary: "List messages",
|
|
2702
|
+
description:
|
|
2703
|
+
"Return messages for a conversation, including attachments and interface file metadata.",
|
|
2704
|
+
tags: ["messages"],
|
|
2705
|
+
responseBody: z.object({
|
|
2706
|
+
messages: z.array(z.unknown()).describe("Array of message objects"),
|
|
2707
|
+
hasMore: z
|
|
2708
|
+
.boolean()
|
|
2709
|
+
.optional()
|
|
2710
|
+
.describe("Whether older messages exist beyond this page"),
|
|
2711
|
+
oldestTimestamp: z
|
|
2712
|
+
.number()
|
|
2713
|
+
.nullable()
|
|
2714
|
+
.optional()
|
|
2715
|
+
.describe(
|
|
2716
|
+
"Timestamp of the oldest message in this page (ms since epoch). Null when page=latest is used on an empty conversation.",
|
|
2561
2717
|
),
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2718
|
+
oldestMessageId: z
|
|
2719
|
+
.string()
|
|
2720
|
+
.nullable()
|
|
2721
|
+
.optional()
|
|
2722
|
+
.describe("ID of the oldest message in this page"),
|
|
2723
|
+
}),
|
|
2724
|
+
handler: (args) => handleListMessages(args, getInterfacesDir()),
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
operationId: "messages_post",
|
|
2728
|
+
endpoint: "messages",
|
|
2729
|
+
method: "POST",
|
|
2730
|
+
summary: "Send a message",
|
|
2731
|
+
description:
|
|
2732
|
+
"Send a user message to a conversation and trigger the assistant response.",
|
|
2733
|
+
tags: ["messages"],
|
|
2734
|
+
responseStatus: "202",
|
|
2735
|
+
requestBody: z.object({
|
|
2736
|
+
conversationKey: z.string().optional(),
|
|
2737
|
+
content: z.string().describe("Message text content"),
|
|
2738
|
+
attachments: z
|
|
2739
|
+
.array(z.unknown())
|
|
2740
|
+
.describe("Optional file attachments")
|
|
2741
|
+
.optional(),
|
|
2742
|
+
conversationType: z.string().optional(),
|
|
2743
|
+
slashCommand: z.string().optional(),
|
|
2744
|
+
inferenceProfile: z.string().nullable().optional(),
|
|
2745
|
+
riskThreshold: z.enum(VALID_RISK_THRESHOLDS).optional(),
|
|
2746
|
+
}),
|
|
2747
|
+
handler: async (args) =>
|
|
2748
|
+
handleSendMessage(args, {
|
|
2749
|
+
sendMessageDeps: {
|
|
2750
|
+
getOrCreateConversation: getOrCreateConversationInstance,
|
|
2751
|
+
assistantEventHub,
|
|
2752
|
+
resolveAttachments,
|
|
2753
|
+
},
|
|
2754
|
+
approvalConversationGenerator: createApprovalConversationGenerator(),
|
|
2572
2755
|
}),
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2756
|
+
},
|
|
2757
|
+
{
|
|
2758
|
+
operationId: "search_get",
|
|
2759
|
+
endpoint: "search",
|
|
2760
|
+
method: "GET",
|
|
2761
|
+
summary: "Search conversations",
|
|
2762
|
+
description: "Full-text search across all conversations.",
|
|
2763
|
+
tags: ["conversations"],
|
|
2764
|
+
responseBody: z.object({
|
|
2765
|
+
query: z.string(),
|
|
2766
|
+
results: z.array(z.unknown()),
|
|
2767
|
+
}),
|
|
2768
|
+
handler: handleSearchConversations,
|
|
2769
|
+
},
|
|
2770
|
+
{
|
|
2771
|
+
operationId: "suggestion_get",
|
|
2772
|
+
endpoint: "suggestion",
|
|
2773
|
+
method: "GET",
|
|
2774
|
+
summary: "Get reply suggestion",
|
|
2775
|
+
description:
|
|
2776
|
+
"Return an LLM-generated follow-up suggestion for the most recent assistant message.",
|
|
2777
|
+
tags: ["messages"],
|
|
2778
|
+
responseBody: z.object({
|
|
2779
|
+
suggestion: z.string(),
|
|
2780
|
+
messageId: z.string(),
|
|
2781
|
+
source: z.string(),
|
|
2782
|
+
}),
|
|
2783
|
+
handler: async (args) =>
|
|
2784
|
+
handleGetSuggestion(args, {
|
|
2785
|
+
suggestionCache,
|
|
2786
|
+
suggestionInFlight,
|
|
2586
2787
|
}),
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
suggestionCache: deps.suggestionCache,
|
|
2590
|
-
suggestionInFlight: deps.suggestionInFlight,
|
|
2591
|
-
}),
|
|
2592
|
-
},
|
|
2593
|
-
];
|
|
2594
|
-
}
|
|
2788
|
+
},
|
|
2789
|
+
];
|