@vellumai/assistant 0.6.6 → 0.7.1
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 +20 -0
- package/ARCHITECTURE.md +46 -38
- package/Dockerfile +27 -6
- package/README.md +9 -11
- package/__tests__/permissions/gateway-threshold-reader.test.ts +83 -149
- package/bun.lock +309 -119
- package/docs/architecture/memory.md +1 -90
- package/docs/architecture/security.md +28 -41
- package/docs/credential-execution-service.md +7 -5
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/bun.lock +25 -0
- package/knip.json +9 -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/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 +887 -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 +86 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1342 -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 +325 -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/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +3136 -650
- package/package.json +15 -7
- package/scripts/check-circular-deps.ts +80 -0
- package/scripts/generate-openapi.ts +29 -107
- package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +27 -27
- 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 +283 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
- package/src/__tests__/anthropic-provider.test.ts +183 -28
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/app-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +3 -370
- 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 +36 -464
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +107 -92
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- 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 +8 -20
- package/src/__tests__/background-shell-bash.test.ts +227 -0
- package/src/__tests__/background-shell-host-bash.test.ts +465 -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__/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-site-routing-provider.test.ts +193 -0
- 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-files.test.ts +0 -26
- package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +88 -344
- package/src/__tests__/channel-approval.test.ts +9 -7
- package/src/__tests__/channel-approvals.test.ts +34 -197
- package/src/__tests__/channel-delivery-store.test.ts +11 -10
- package/src/__tests__/channel-guardian.test.ts +114 -171
- 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 +272 -3933
- package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
- package/src/__tests__/cli.test.ts +1 -38
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -1
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
- package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +0 -1
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +36 -269
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contact-store-user-file.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +56 -29
- package/src/__tests__/contacts-write.test.ts +8 -125
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- 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 +430 -0
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +493 -0
- package/src/__tests__/context-search-types.test.ts +95 -0
- package/src/__tests__/context-search-workspace-source.test.ts +532 -0
- package/src/__tests__/context-window-manager.test.ts +71 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +633 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +117 -31
- package/src/__tests__/conversation-agent-loop.test.ts +1004 -15
- package/src/__tests__/conversation-analysis-routes.test.ts +68 -88
- 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 +15 -5
- package/src/__tests__/conversation-clear-safety.test.ts +53 -95
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -330
- 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 +4 -3
- package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +205 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +4 -81
- package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +4 -5
- 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 +0 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
- package/src/__tests__/conversation-process-callsite.test.ts +79 -3
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
- package/src/__tests__/conversation-queue.test.ts +4 -41
- package/src/__tests__/conversation-routes-disk-view.test.ts +55 -188
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +64 -71
- package/src/__tests__/conversation-routes-slash-commands.test.ts +144 -64
- package/src/__tests__/conversation-runtime-assembly.test.ts +295 -84
- package/src/__tests__/conversation-slash-commands.test.ts +30 -47
- package/src/__tests__/conversation-slash-queue.test.ts +2 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
- package/src/__tests__/conversation-speed-override.test.ts +0 -4
- package/src/__tests__/conversation-starter-routes.test.ts +254 -55
- package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +2 -375
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -47
- 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 +255 -4
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
- 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-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +15 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/credentials-cli.test.ts +45 -21
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +26 -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-connection-isolation.test.ts +125 -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-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/delete-propagation.test.ts +3 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +38 -104
- package/src/__tests__/dm-backfill.test.ts +3 -2
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/edit-propagation.test.ts +5 -7
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +3 -3
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/empty-response-pipeline.test.ts +1 -1
- package/src/__tests__/events-client-registration.test.ts +441 -0
- package/src/__tests__/file-write-tool.test.ts +2 -4
- package/src/__tests__/filing-service.test.ts +197 -19
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- 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__/get-skill-detail-audit.test.ts +3 -8
- 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 +3 -2
- 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 +16 -17
- 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 +41 -92
- package/src/__tests__/guardian-routing-state.test.ts +15 -23
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +274 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -87
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +325 -25
- package/src/__tests__/helpers/call-route-handler.ts +72 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -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 +1 -1
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +38 -498
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +35 -95
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +68 -153
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +35 -31
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-proxy-interface.test.ts +3 -3
- package/src/__tests__/host-shell-tool.test.ts +35 -72
- package/src/__tests__/host-transfer-pending-interactions.test.ts +144 -0
- package/src/__tests__/host-transfer-proxy.test.ts +723 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +18 -15
- package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +25 -21
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -208
- package/src/__tests__/install-skill-routing.test.ts +2 -14
- 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 +7 -8
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-normalization.test.ts +69 -4
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- 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 +279 -0
- package/src/__tests__/llm-schema.test.ts +57 -1
- package/src/__tests__/llm-usage-store.test.ts +271 -5
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/log-export-workspace.test.ts +28 -17
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -3
- package/src/__tests__/mcp-client-auth.test.ts +2 -3
- 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 +6 -8
- package/src/__tests__/memory-upsert-concurrency.test.ts +2 -1
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +209 -302
- package/src/__tests__/migration-export-http.test.ts +50 -43
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +531 -0
- package/src/__tests__/migration-import-commit-http.test.ts +82 -37
- package/src/__tests__/migration-import-from-gcs.test.ts +574 -0
- package/src/__tests__/migration-import-from-url.test.ts +34 -27
- package/src/__tests__/migration-import-preflight-http.test.ts +108 -108
- package/src/__tests__/migration-jobs-status.test.ts +164 -0
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +149 -159
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/mock-gateway-ipc.ts +32 -62
- package/src/__tests__/model-intents.test.ts +15 -2
- package/src/__tests__/nl-approval-parser.test.ts +13 -17
- package/src/__tests__/non-member-access-request.test.ts +14 -6
- package/src/__tests__/notification-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +76 -122
- package/src/__tests__/oauth-cli.test.ts +14 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
- package/src/__tests__/oauth-providers-routes.test.ts +78 -101
- package/src/__tests__/oauth-store.test.ts +22 -1
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- 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 +4 -9
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persistence-pipeline.test.ts +3 -2
- package/src/__tests__/pipeline-runner.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +44 -28
- package/src/__tests__/platform.test.ts +11 -63
- 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 +51 -5
- package/src/__tests__/plugin-registry.test.ts +30 -0
- package/src/__tests__/plugin-route-contribution.test.ts +17 -11
- package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
- package/src/__tests__/plugin-types.test.ts +1 -1
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +218 -5
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/profiler-routes.test.ts +112 -177
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +273 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/proxy-approval-callback.test.ts +6 -554
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +12 -8
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +64 -83
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/registry.test.ts +1 -0
- package/src/__tests__/relay-server.test.ts +37 -17
- package/src/__tests__/require-fresh-approval.test.ts +24 -182
- 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 +15 -17
- package/src/__tests__/runtime-events-sse.test.ts +16 -33
- package/src/__tests__/schedule-routes.test.ts +226 -129
- 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 +2 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
- 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__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +36 -23
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +51 -103
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +36 -38
- 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 +36 -69
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- 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__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -32
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +12 -64
- 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-notifications.test.ts +57 -47
- package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +83 -109
- 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 +55 -62
- package/src/__tests__/system-prompt.test.ts +115 -13
- 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 +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +3 -401
- package/src/__tests__/test-preload.ts +0 -11
- package/src/__tests__/thread-backfill.test.ts +947 -32
- package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
- 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 -39
- package/src/__tests__/tool-error-pipeline.test.ts +6 -6
- package/src/__tests__/tool-execute-pipeline.test.ts +6 -14
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +69 -16
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +31 -62
- package/src/__tests__/tool-executor.test.ts +336 -1654
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- 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 +5 -151
- package/src/__tests__/trusted-contact-multichannel.test.ts +5 -6
- package/src/__tests__/trusted-contact-verification.test.ts +3 -2
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
- package/src/__tests__/twilio-routes.test.ts +25 -66
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +223 -90
- package/src/__tests__/user-plugin-loader.test.ts +54 -12
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +51 -139
- package/src/__tests__/verification-control-plane-policy.test.ts +97 -19
- 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-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-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -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 +252 -0
- 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/index.ts +0 -15
- package/src/acp/resolve-agent.test.ts +291 -0
- package/src/acp/resolve-agent.ts +176 -0
- package/src/acp/session-manager.ts +193 -31
- package/src/acp/types.ts +2 -50
- package/src/agent/loop.ts +53 -15
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +5 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +11 -12
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +38 -104
- 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 +36 -10
- package/src/backup/__tests__/paths.test.ts +5 -4
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +37 -12
- package/src/backup/paths.ts +11 -24
- 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/browser-session/events.ts +0 -9
- 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-store.ts +2 -34
- package/src/calls/guardian-action-sweep.ts +9 -25
- package/src/calls/guardian-dispatch.ts +1 -20
- package/src/calls/guardian-question-copy.ts +0 -108
- 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 -42
- package/src/calls/relay-setup-router.ts +2 -2
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/twilio-rest.ts +1 -39
- 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 +141 -77
- package/src/channels/__tests__/types.test.ts +25 -3
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +25 -44
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +12 -10
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +3 -14
- package/src/cli/commands/__tests__/browser.test.ts +36 -31
- package/src/cli/commands/__tests__/cache.test.ts +175 -23
- package/src/cli/commands/__tests__/memory-v2.test.ts +382 -0
- package/src/cli/commands/__tests__/task.test.ts +36 -35
- package/src/cli/commands/__tests__/trust.test.ts +236 -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 +18 -48
- package/src/cli/commands/browser.ts +52 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +157 -84
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/clients.ts +74 -17
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +241 -86
- package/src/cli/commands/conversations-defer.ts +364 -0
- package/src/cli/commands/conversations-import.ts +2 -3
- package/src/cli/commands/conversations.ts +63 -53
- 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 +1 -1
- package/src/cli/commands/keys.ts +5 -2
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory-v2.ts +315 -0
- package/src/cli/commands/memory.ts +8 -8
- package/src/cli/commands/notifications.ts +21 -20
- 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__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/pending.ts +102 -0
- 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 +264 -116
- package/src/cli/commands/task.ts +12 -10
- package/src/cli/commands/trust.ts +105 -167
- package/src/cli/commands/ui.ts +3 -3
- package/src/cli/commands/usage.ts +29 -15
- 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 +41 -189
- package/src/cli/lib/ipc-params.ts +22 -0
- package/src/cli/program.ts +6 -0
- package/src/cli.ts +1 -82
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -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/acp/tools/acp-list-agents.ts +12 -0
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
- 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/TOOLS.json +14 -4
- 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/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/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 -6
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +10 -22
- package/src/config/feature-flag-registry.json +38 -46
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +90 -36
- package/src/config/loader.ts +9 -12
- package/src/config/schema.ts +5 -228
- package/src/config/schemas/__tests__/filing.test.ts +58 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +187 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/filing.ts +12 -0
- package/src/config/schemas/host-browser.ts +2 -2
- package/src/config/schemas/inference.ts +1 -3
- package/src/config/schemas/ingress.ts +2 -2
- package/src/config/schemas/llm.ts +82 -12
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory-v2.ts +185 -0
- package/src/config/schemas/memory.ts +2 -0
- package/src/config/schemas/security.ts +1 -102
- package/src/config/schemas/services.ts +52 -13
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +1 -91
- package/src/config/types.ts +3 -47
- package/src/contacts/contact-store.ts +2 -19
- package/src/contacts/contacts-write.ts +1 -143
- package/src/contacts/types.ts +8 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +1 -1
- package/src/context/window-manager.ts +45 -6
- 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-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +22 -17
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +76 -83
- package/src/daemon/__tests__/daemon-skill-host.test.ts +265 -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 -54
- package/src/daemon/connection-policy.ts +1 -40
- package/src/daemon/conversation-agent-loop-handlers.ts +89 -9
- package/src/daemon/conversation-agent-loop.ts +440 -88
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +9 -9
- package/src/daemon/conversation-launch.ts +21 -136
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +2 -1
- package/src/daemon/conversation-notifiers.ts +1 -1
- package/src/daemon/conversation-process.ts +90 -174
- package/src/daemon/conversation-runtime-assembly.ts +245 -164
- package/src/daemon/conversation-slash.ts +50 -164
- package/src/daemon/conversation-store.ts +344 -0
- package/src/daemon/conversation-surfaces.ts +27 -32
- package/src/daemon/conversation-tool-setup.ts +23 -202
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +129 -381
- package/src/daemon/daemon-control.ts +4 -72
- package/src/daemon/daemon-skill-host.ts +259 -0
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/external-plugins-bootstrap.ts +67 -13
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +14 -14
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/config-ingress.ts +27 -166
- package/src/daemon/handlers/config-model.test.ts +17 -0
- package/src/daemon/handlers/config-model.ts +8 -53
- package/src/daemon/handlers/config-telegram.ts +6 -53
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +32 -345
- package/src/daemon/handlers/recording.ts +27 -159
- package/src/daemon/handlers/shared.ts +50 -99
- package/src/daemon/handlers/skills.ts +55 -114
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +538 -0
- package/src/daemon/lifecycle.ts +71 -272
- 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/conversations.ts +23 -2
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +42 -0
- package/src/daemon/message-types/integrations.ts +6 -0
- package/src/daemon/message-types/messages.ts +24 -23
- 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 +1 -3
- 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 +479 -0
- package/src/daemon/providers-setup.ts +14 -6
- package/src/daemon/server.ts +58 -1702
- package/src/daemon/shutdown-handlers.ts +3 -3
- package/src/daemon/startup-error.ts +1 -1
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +45 -0
- package/src/daemon/wake-target-adapter.ts +218 -0
- package/src/email/feature-gate.ts +1 -1
- package/src/events/domain-events.ts +1 -16
- package/src/events/tool-audit-listener.ts +5 -9
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +1 -21
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +207 -55
- package/src/followups/followup-store.ts +3 -71
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +93 -21
- package/src/heartbeat/heartbeat-service.ts +55 -16
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/__tests__/rollup-producer.test.ts +67 -2
- package/src/home/assistant-feed-authoring.ts +8 -1
- package/src/home/feed-types.ts +1 -1
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +17 -4
- 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 +72 -58
- 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 +253 -0
- package/src/ipc/__tests__/skill-server.test.ts +182 -0
- package/src/ipc/__tests__/socket-path.test.ts +69 -23
- 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 +443 -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 -123
- package/src/ipc/ipc-framing.ts +281 -0
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +171 -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 +123 -0
- package/src/ipc/skill-ipc-types.ts +54 -0
- package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +388 -0
- package/src/ipc/skill-routes/__tests__/identity.test.ts +62 -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 +120 -0
- package/src/ipc/skill-routes/identity.ts +21 -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 +738 -0
- package/src/ipc/skill-socket-path.ts +20 -0
- package/src/ipc/socket-cleanup.ts +92 -0
- package/src/ipc/socket-path.ts +63 -32
- 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 +413 -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 +515 -0
- package/src/mcp/client.ts +2 -2
- package/src/mcp/manager.ts +0 -5
- package/src/media/types.ts +4 -4
- 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__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/admin.ts +65 -7
- package/src/memory/app-git-service.ts +0 -46
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +20 -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-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +95 -0
- package/src/memory/context-search/sources/pkb.ts +477 -0
- package/src/memory/context-search/sources/workspace.ts +1256 -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 +86 -119
- package/src/memory/conversation-directories.ts +1 -11
- package/src/memory/conversation-disk-view.ts +1 -5
- 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 +13 -26
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- 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 +2 -1
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +28 -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-backend.ts +3 -21
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +408 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
- package/src/memory/graph/bootstrap.test.ts +2 -7
- package/src/memory/graph/bootstrap.ts +2 -1
- 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 +184 -12
- package/src/memory/graph/decay.ts +1 -1
- package/src/memory/graph/extraction.ts +53 -21
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +94 -2
- package/src/memory/graph/graph-search.ts +22 -7
- package/src/memory/graph/image-ref-utils.ts +1 -1
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/graph/retriever.test.ts +158 -4
- package/src/memory/graph/retriever.ts +17 -5
- 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 -84
- package/src/memory/guardian-approvals.ts +1 -49
- package/src/memory/guardian-rate-limits.ts +1 -1
- package/src/memory/indexer.ts +44 -32
- 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 +54 -63
- 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 -9
- 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 +9 -2
- package/src/memory/jobs-worker.ts +56 -17
- package/src/memory/lifecycle-events-store.ts +1 -1
- package/src/memory/llm-request-log-store.ts +1 -42
- package/src/memory/llm-usage-store.ts +130 -44
- package/src/memory/media-store.ts +1 -1
- package/src/memory/memory-recall-log-store.ts +1 -1
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- 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/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/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +24 -0
- package/src/memory/migrations/registry.ts +31 -0
- package/src/memory/pkb/pkb-index.test.ts +4 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
- package/src/memory/pkb/pkb-search.test.ts +83 -3
- package/src/memory/pkb/pkb-search.ts +27 -14
- package/src/memory/published-pages-store.ts +1 -1
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/acp.ts +30 -0
- package/src/memory/schema/conversations.ts +8 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +26 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- package/src/memory/scoped-approval-grants.ts +2 -1
- package/src/memory/search/semantic.ts +7 -18
- package/src/memory/shared-app-links-store.ts +2 -1
- package/src/memory/tool-usage-store.ts +3 -1
- package/src/memory/trace-event-store.ts +2 -1
- package/src/memory/turn-events-store.ts +1 -1
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
- package/src/memory/v2/__tests__/activation.test.ts +1155 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +483 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +412 -0
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +1161 -0
- package/src/memory/v2/__tests__/migration.test.ts +840 -0
- package/src/memory/v2/__tests__/page-store.test.ts +517 -0
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -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 +463 -0
- package/src/memory/v2/__tests__/static-context.test.ts +153 -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 +561 -0
- package/src/memory/v2/backfill-jobs.ts +357 -0
- package/src/memory/v2/consolidation-job.ts +306 -0
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +431 -0
- package/src/memory/v2/migration.ts +647 -0
- package/src/memory/v2/now-text.ts +37 -0
- package/src/memory/v2/page-store.ts +382 -0
- package/src/memory/v2/prompts/consolidation.ts +261 -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 +176 -0
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/sweep-job.ts +298 -0
- package/src/memory/v2/types.ts +106 -0
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/index.ts +262 -0
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/api.ts +242 -0
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +13 -3
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/send.ts +383 -0
- package/src/messaging/providers/slack/types.ts +1 -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-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -1
- 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/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +0 -9
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +6 -5
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +8 -5
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -23
- package/src/permissions/approval-policy.test.ts +149 -132
- package/src/permissions/approval-policy.ts +65 -91
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +270 -460
- package/src/permissions/gateway-threshold-reader.ts +31 -47
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +13 -11
- package/src/permissions/risk-types.ts +24 -210
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +49 -46
- package/src/permissions/workspace-policy.ts +1 -8
- package/src/platform/sync-identity.ts +0 -8
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/injectors.ts +87 -23
- package/src/plugins/defaults/llm-call.ts +6 -9
- package/src/plugins/defaults/memory-retrieval.ts +1 -6
- package/src/plugins/defaults/overflow-reduce.ts +12 -7
- package/src/plugins/defaults/token-estimate.ts +2 -3
- package/src/plugins/registry.ts +61 -1
- package/src/plugins/types.ts +14 -7
- package/src/plugins/user-loader.ts +36 -10
- package/src/prompts/persona-resolver.ts +2 -4
- package/src/prompts/system-prompt.ts +34 -31
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
- package/src/providers/__tests__/retry-callsite.test.ts +141 -7
- package/src/providers/anthropic/client.ts +143 -52
- package/src/providers/call-site-routing.ts +49 -6
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/gemini/client.ts +113 -23
- package/src/providers/managed-proxy/context.ts +0 -17
- package/src/providers/model-catalog.ts +188 -27
- package/src/providers/model-intents.ts +7 -8
- package/src/providers/openai/chat-completions-provider.ts +43 -7
- package/src/providers/openai/responses-provider.ts +46 -5
- package/src/providers/openrouter/client.ts +4 -5
- package/src/providers/provider-env-vars.ts +4 -12
- package/src/providers/provider-send-message.ts +61 -13
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +15 -10
- package/src/providers/retry.ts +148 -31
- 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.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +35 -10
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +16 -11
- package/src/runtime/__tests__/agent-wake.test.ts +122 -9
- 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 +211 -68
- package/src/runtime/approval-conversation-turn.ts +2 -15
- package/src/runtime/approval-message-composer.ts +11 -60
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +16 -69
- 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/middleware.ts +5 -5
- package/src/runtime/auth/route-policy.ts +205 -12
- package/src/runtime/auth/token-service.ts +1 -111
- package/src/runtime/capability-tokens.ts +89 -313
- package/src/runtime/channel-approval-types.ts +1 -6
- package/src/runtime/channel-approvals.ts +13 -81
- 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/channel-verification-service.ts +3 -5
- 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 +1 -32
- package/src/runtime/http-router.ts +54 -8
- package/src/runtime/http-server.ts +362 -1187
- package/src/runtime/http-types.ts +20 -98
- package/src/runtime/interactive-ui-types.ts +145 -0
- package/src/runtime/interactive-ui.ts +37 -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/auth.ts +0 -20
- 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__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +18 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/job-registry.ts +281 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -80
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +8 -8
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -16
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/nl-approval-parser.ts +16 -21
- package/src/runtime/pending-interactions.ts +42 -16
- package/src/runtime/routes/__tests__/acp-routes.test.ts +394 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +232 -339
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- 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/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/access-request-decision.ts +25 -50
- package/src/runtime/routes/acp-routes.test.ts +368 -0
- package/src/runtime/routes/acp-routes.ts +392 -170
- package/src/runtime/routes/app-management-routes.ts +475 -662
- package/src/runtime/routes/app-routes.ts +192 -177
- package/src/runtime/routes/approval-routes.ts +163 -440
- 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 +81 -76
- 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 +127 -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-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +79 -120
- package/src/runtime/routes/channel-route-definitions.ts +62 -0
- package/src/runtime/routes/channel-route-shared.ts +15 -45
- package/src/runtime/routes/channel-verification-routes.ts +207 -187
- package/src/runtime/routes/client-routes.ts +81 -0
- package/src/runtime/routes/consolidation-routes.ts +115 -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 +248 -0
- package/src/runtime/routes/conversation-management-routes.ts +591 -717
- package/src/runtime/routes/conversation-query-routes.ts +621 -459
- package/src/runtime/routes/conversation-routes.ts +396 -792
- package/src/runtime/routes/conversation-starter-routes.ts +137 -108
- 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 +163 -117
- package/src/runtime/routes/errors.ts +132 -0
- package/src/runtime/routes/events-routes.ts +126 -119
- package/src/runtime/routes/filing-routes.ts +80 -76
- 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 +100 -171
- 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 +45 -54
- package/src/runtime/routes/host-browser-routes.ts +44 -99
- package/src/runtime/routes/host-cu-routes.ts +80 -71
- package/src/runtime/routes/host-file-routes.ts +53 -62
- package/src/runtime/routes/host-transfer-routes.ts +216 -0
- package/src/runtime/routes/http-adapter.ts +172 -0
- package/src/runtime/routes/identity-routes.ts +161 -85
- package/src/runtime/routes/inbound-conversation.ts +11 -18
- package/src/runtime/routes/inbound-message-handler.ts +639 -232
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +81 -226
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -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/index.ts +201 -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 +50 -71
- 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-call-sites-routes.ts +22 -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 +152 -175
- package/src/runtime/routes/memory-item-routes.ts +243 -323
- package/src/runtime/routes/memory-v2-routes.ts +188 -0
- package/src/runtime/routes/migration-rollback-routes.ts +167 -212
- package/src/runtime/routes/migration-routes.ts +1037 -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 +60 -120
- package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
- package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
- package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
- package/src/runtime/routes/playground/force-compact.ts +41 -54
- package/src/runtime/routes/playground/guard.ts +18 -19
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +15 -27
- package/src/runtime/routes/playground/inject-failures.ts +48 -64
- package/src/runtime/routes/playground/reset-circuit.ts +31 -57
- package/src/runtime/routes/playground/seed-conversation.ts +66 -92
- package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
- package/src/runtime/routes/playground/state.ts +23 -24
- 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 +189 -270
- package/src/runtime/routes/rename-conversation-routes.ts +85 -0
- package/src/runtime/routes/schedule-routes.ts +239 -246
- package/src/runtime/routes/secret-routes.ts +305 -282
- package/src/runtime/routes/secrets-deps.ts +24 -0
- package/src/runtime/routes/settings-routes.ts +370 -449
- package/src/runtime/routes/skills-routes.ts +417 -471
- 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 +275 -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 +61 -244
- 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 +150 -198
- package/src/runtime/routes/usage-routes.ts +222 -171
- package/src/runtime/routes/user-routes.ts +88 -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 +419 -437
- 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 +82 -120
- package/src/runtime/services/analyze-conversation.ts +18 -55
- package/src/runtime/services/conversation-serializer.ts +179 -0
- package/src/runtime/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +14 -50
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +64 -18
- package/src/schedule/scheduler.ts +101 -0
- 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/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- 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/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/event-stream.ts +1 -1
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-cache.ts +7 -0
- package/src/skills/catalog-files.ts +0 -5
- package/src/skills/catalog-install.ts +29 -18
- package/src/skills/category-inference.ts +0 -11
- package/src/skills/clawhub.ts +4 -4
- package/src/skills/inline-command-runner.ts +1 -7
- 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 +94 -107
- 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 +2 -29
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- 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 +378 -0
- package/src/tools/acp/spawn.ts +142 -62
- package/src/tools/acp/steer.test.ts +100 -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 +44 -127
- package/src/tools/browser/browser-execution.ts +38 -127
- package/src/tools/browser/browser-manager.ts +1 -8
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- 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/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- 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 +53 -45
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +271 -0
- package/src/tools/host-filesystem/transfer.ts +235 -0
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +192 -13
- 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/index.ts +1 -10
- package/src/tools/permission-checker.ts +84 -220
- package/src/tools/policy-context.ts +1 -8
- package/src/tools/registry.ts +16 -1
- 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/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/subagent/spawn.ts +35 -11
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/terminal/shell.ts +142 -88
- package/src/tools/tool-approval-handler.ts +4 -70
- package/src/tools/tool-input-summary.ts +10 -0
- package/src/tools/types.ts +136 -183
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/debounce.ts +0 -21
- package/src/util/errors.ts +0 -8
- package/src/util/json.ts +13 -0
- package/src/util/log-redact.ts +0 -1
- package/src/util/logger.ts +3 -3
- package/src/util/platform.ts +85 -124
- package/src/util/pricing.ts +158 -8
- package/src/watcher/engine.ts +42 -20
- package/src/watcher/watcher-store.ts +2 -1
- package/src/work-items/work-item-runner.ts +15 -42
- 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 +10 -1
- 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/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- 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 +37 -0
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
- package/src/workspace/migrations/registry.ts +26 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +4 -4
- 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__/config-watcher-feature-flags.test.ts +0 -211
- 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__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- 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 -488
- 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__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -74
- package/src/__tests__/secret-scanner-executor.test.ts +0 -451
- package/src/__tests__/shell-identity.test.ts +0 -236
- 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__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -354
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- 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/db.ts +0 -1
- 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/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- package/src/daemon/external-skills-bootstrap.ts +0 -41
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/daemon/message-types/trust.ts +0 -71
- package/src/daemon/pairing-store.ts +0 -229
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -63
- package/src/ipc/routes/browser.ts +0 -97
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/get-contact.ts +0 -16
- package/src/ipc/routes/index.ts +0 -35
- package/src/ipc/routes/list-clients.ts +0 -31
- package/src/ipc/routes/merge-contacts.ts +0 -17
- package/src/ipc/routes/notification.ts +0 -133
- package/src/ipc/routes/rename-conversation.ts +0 -59
- package/src/ipc/routes/search-contacts.ts +0 -19
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/upsert-contact.ts +0 -25
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/permissions/arg-parser.test.ts +0 -161
- package/src/permissions/arg-parser.ts +0 -141
- package/src/permissions/bash-risk-classifier.test.ts +0 -1620
- package/src/permissions/bash-risk-classifier.ts +0 -950
- package/src/permissions/command-registry.test.ts +0 -774
- package/src/permissions/command-registry.ts +0 -1005
- package/src/permissions/defaults.ts +0 -314
- 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/schedule-risk-classifier.test.ts +0 -129
- package/src/permissions/schedule-risk-classifier.ts +0 -85
- package/src/permissions/shell-identity.ts +0 -297
- 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/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -293
- 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/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -261
- package/src/runtime/conversation-approval-overrides.ts +0 -86
- package/src/runtime/routes/browser-extension-pair-routes.ts +0 -575
- 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/inbound-stages/verification-intercept.ts +0 -336
- package/src/runtime/routes/invite-routes.ts +0 -280
- package/src/runtime/routes/pairing-routes.ts +0 -431
- package/src/runtime/routes/playground/deps.ts +0 -56
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/secret-detection-handler.ts +0 -359
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/parser.ts +0 -623
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
- 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
|
@@ -12,9 +12,14 @@ import {
|
|
|
12
12
|
parseInterfaceId,
|
|
13
13
|
} from "../../channels/types.js";
|
|
14
14
|
import { touchContactInteraction } from "../../contacts/contacts-write.js";
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
import {
|
|
16
|
+
createApprovalConversationGenerator,
|
|
17
|
+
createApprovalCopyGenerator,
|
|
18
|
+
} from "../../daemon/approval-generators.js";
|
|
19
|
+
import { processMessage } from "../../daemon/process-message.js";
|
|
20
|
+
import type { TrustContext } from "../../daemon/trust-context.js";
|
|
21
|
+
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
22
|
+
import { getAttachmentsByIds } from "../../memory/attachments-store.js";
|
|
18
23
|
import {
|
|
19
24
|
recordConversationSeenSignal,
|
|
20
25
|
type SignalType,
|
|
@@ -26,18 +31,27 @@ import {
|
|
|
26
31
|
selectSlackMetaCandidateMetadata,
|
|
27
32
|
updateMessageMetadata,
|
|
28
33
|
} from "../../memory/conversation-crud.js";
|
|
29
|
-
import
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
import {
|
|
35
|
+
clearPendingVerificationReply,
|
|
36
|
+
getPendingVerificationReply,
|
|
37
|
+
} from "../../memory/delivery-channels.js";
|
|
38
|
+
import {
|
|
39
|
+
findMessageBySourceId,
|
|
40
|
+
linkMessage,
|
|
41
|
+
recordInbound,
|
|
42
|
+
} from "../../memory/delivery-crud.js";
|
|
43
|
+
import { markProcessed } from "../../memory/delivery-status.js";
|
|
44
|
+
import { upsertBinding } from "../../memory/external-conversation-store.js";
|
|
33
45
|
import type { Message as ProviderMessage } from "../../messaging/provider-types.js";
|
|
34
46
|
import {
|
|
35
47
|
backfillDm,
|
|
36
|
-
|
|
48
|
+
backfillThreadWindowPage,
|
|
49
|
+
type SlackBackfillWindowPage,
|
|
37
50
|
} from "../../messaging/providers/slack/backfill.js";
|
|
38
51
|
import {
|
|
39
52
|
mergeSlackMetadata,
|
|
40
53
|
readSlackMetadata,
|
|
54
|
+
type SlackFileMetadata,
|
|
41
55
|
type SlackMessageMetadata,
|
|
42
56
|
writeSlackMetadata,
|
|
43
57
|
} from "../../messaging/providers/slack/message-metadata.js";
|
|
@@ -45,18 +59,10 @@ import { wrapUntrustedContent } from "../../security/untrusted-content.js";
|
|
|
45
59
|
import { canonicalizeInboundIdentity } from "../../util/canonicalize-identity.js";
|
|
46
60
|
import { getLogger } from "../../util/logger.js";
|
|
47
61
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
48
|
-
import { mintDaemonDeliveryToken } from "../auth/token-service.js";
|
|
49
62
|
import { deliverChannelReply } from "../gateway-client.js";
|
|
50
|
-
import { httpError } from "../http-errors.js";
|
|
51
|
-
import type {
|
|
52
|
-
ApprovalConversationGenerator,
|
|
53
|
-
ApprovalCopyGenerator,
|
|
54
|
-
GuardianActionCopyGenerator,
|
|
55
|
-
GuardianFollowUpConversationGenerator,
|
|
56
|
-
MessageProcessor,
|
|
57
|
-
} from "../http-types.js";
|
|
58
63
|
import { resolveTrustContext } from "../trust-context-resolver.js";
|
|
59
64
|
import { canonicalChannelAssistantId } from "./channel-route-shared.js";
|
|
65
|
+
import { BadRequestError } from "./errors.js";
|
|
60
66
|
import { handleApprovalInterception } from "./guardian-approval-interception.js";
|
|
61
67
|
import { enforceIngressAcl } from "./inbound-stages/acl-enforcement.js";
|
|
62
68
|
import { processChannelMessageInBackground } from "./inbound-stages/background-dispatch.js";
|
|
@@ -67,7 +73,7 @@ import { handleGuardianActivationIntercept } from "./inbound-stages/guardian-act
|
|
|
67
73
|
import { handleGuardianReplyIntercept } from "./inbound-stages/guardian-reply-intercept.js";
|
|
68
74
|
import { runSecretIngressCheck } from "./inbound-stages/secret-ingress-check.js";
|
|
69
75
|
import { tryTranscribeAudioAttachments } from "./inbound-stages/transcribe-audio.js";
|
|
70
|
-
import {
|
|
76
|
+
import type { RouteHandlerArgs } from "./types.js";
|
|
71
77
|
|
|
72
78
|
const log = getLogger("runtime-http");
|
|
73
79
|
|
|
@@ -93,28 +99,19 @@ export function _setDeleteLookupConfigForTests(
|
|
|
93
99
|
deleteLookupDelayMs = delayMs;
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
export async function handleChannelInbound(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
assistantId: string = DAEMON_INTERNAL_ASSISTANT_ID,
|
|
100
|
-
approvalCopyGenerator?: ApprovalCopyGenerator,
|
|
101
|
-
approvalConversationGenerator?: ApprovalConversationGenerator,
|
|
102
|
-
_guardianActionCopyGenerator?: GuardianActionCopyGenerator,
|
|
103
|
-
_guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator,
|
|
104
|
-
heartbeatService?: HeartbeatService,
|
|
105
|
-
): Promise<Response> {
|
|
102
|
+
export async function handleChannelInbound({
|
|
103
|
+
body: rawBody = {},
|
|
104
|
+
}: RouteHandlerArgs) {
|
|
106
105
|
// Gateway-origin proof is enforced by route-policy middleware (svc_gateway
|
|
107
106
|
// principal type required) before this handler runs. The exchange JWT
|
|
108
107
|
// itself proves gateway origin.
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// a single token from request start.
|
|
115
|
-
const mintBearerToken = (): string => mintDaemonDeliveryToken();
|
|
109
|
+
const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
110
|
+
const approvalCopyGenerator = createApprovalCopyGenerator();
|
|
111
|
+
const approvalConversationGenerator = createApprovalConversationGenerator();
|
|
112
|
+
const heartbeatService = HeartbeatService.getInstance();
|
|
116
113
|
|
|
117
|
-
const body =
|
|
114
|
+
const body = rawBody as {
|
|
118
115
|
sourceChannel?: string;
|
|
119
116
|
interface?: string;
|
|
120
117
|
conversationExternalId?: string;
|
|
@@ -141,53 +138,49 @@ export async function handleChannelInbound(
|
|
|
141
138
|
} = body;
|
|
142
139
|
|
|
143
140
|
if (!body.sourceChannel || typeof body.sourceChannel !== "string") {
|
|
144
|
-
|
|
141
|
+
throw new BadRequestError("sourceChannel is required");
|
|
145
142
|
}
|
|
146
143
|
// Validate and narrow to canonical ChannelId at the boundary — the gateway
|
|
147
144
|
// only sends well-known channel strings, so an unknown value is rejected.
|
|
148
145
|
if (!isChannelId(body.sourceChannel)) {
|
|
149
|
-
|
|
150
|
-
"BAD_REQUEST",
|
|
146
|
+
throw new BadRequestError(
|
|
151
147
|
`Invalid sourceChannel: ${
|
|
152
148
|
body.sourceChannel
|
|
153
149
|
}. Valid values: ${CHANNEL_IDS.join(", ")}`,
|
|
154
|
-
400,
|
|
155
150
|
);
|
|
156
151
|
}
|
|
157
152
|
|
|
158
153
|
const sourceChannel = body.sourceChannel;
|
|
159
154
|
|
|
160
155
|
if (!body.interface || typeof body.interface !== "string") {
|
|
161
|
-
|
|
156
|
+
throw new BadRequestError("interface is required");
|
|
162
157
|
}
|
|
163
158
|
const sourceInterface = parseInterfaceId(body.interface);
|
|
164
159
|
if (!sourceInterface) {
|
|
165
|
-
|
|
166
|
-
"BAD_REQUEST",
|
|
160
|
+
throw new BadRequestError(
|
|
167
161
|
`Invalid interface: ${body.interface}. Valid values: ${INTERFACE_IDS.join(
|
|
168
162
|
", ",
|
|
169
163
|
)}`,
|
|
170
|
-
400,
|
|
171
164
|
);
|
|
172
165
|
}
|
|
173
166
|
|
|
174
167
|
if (!conversationExternalId || typeof conversationExternalId !== "string") {
|
|
175
|
-
|
|
168
|
+
throw new BadRequestError("conversationExternalId is required");
|
|
176
169
|
}
|
|
177
170
|
if (
|
|
178
171
|
!body.actorExternalId ||
|
|
179
172
|
typeof body.actorExternalId !== "string" ||
|
|
180
173
|
!body.actorExternalId.trim()
|
|
181
174
|
) {
|
|
182
|
-
|
|
175
|
+
throw new BadRequestError("actorExternalId is required");
|
|
183
176
|
}
|
|
184
177
|
if (!externalMessageId || typeof externalMessageId !== "string") {
|
|
185
|
-
|
|
178
|
+
throw new BadRequestError("externalMessageId is required");
|
|
186
179
|
}
|
|
187
180
|
|
|
188
181
|
// Reject non-string content regardless of whether attachments are present.
|
|
189
182
|
if (content != null && typeof content !== "string") {
|
|
190
|
-
|
|
183
|
+
throw new BadRequestError("content must be a string");
|
|
191
184
|
}
|
|
192
185
|
|
|
193
186
|
let trimmedContent = typeof content === "string" ? content.trim() : "";
|
|
@@ -203,11 +196,7 @@ export async function handleChannelInbound(
|
|
|
203
196
|
!isEdit &&
|
|
204
197
|
!hasCallbackData
|
|
205
198
|
) {
|
|
206
|
-
|
|
207
|
-
"BAD_REQUEST",
|
|
208
|
-
"content or attachmentIds is required",
|
|
209
|
-
400,
|
|
210
|
-
);
|
|
199
|
+
throw new BadRequestError("content or attachmentIds is required");
|
|
211
200
|
}
|
|
212
201
|
|
|
213
202
|
// Canonicalize the assistant ID so all DB-facing operations use the
|
|
@@ -253,7 +242,6 @@ export async function handleChannelInbound(
|
|
|
253
242
|
actorUsername: body.actorUsername,
|
|
254
243
|
sourceMetadata: body.sourceMetadata,
|
|
255
244
|
replyCallbackUrl: body.replyCallbackUrl,
|
|
256
|
-
mintBearerToken,
|
|
257
245
|
assistantId,
|
|
258
246
|
externalMessageId,
|
|
259
247
|
});
|
|
@@ -272,12 +260,11 @@ export async function handleChannelInbound(
|
|
|
272
260
|
actorDisplayName: body.actorDisplayName,
|
|
273
261
|
actorUsername: body.actorUsername,
|
|
274
262
|
replyCallbackUrl: body.replyCallbackUrl,
|
|
275
|
-
mintBearerToken,
|
|
276
263
|
assistantId,
|
|
277
264
|
externalMessageId,
|
|
278
265
|
});
|
|
279
266
|
if (aclResult.earlyResponse) return aclResult.earlyResponse;
|
|
280
|
-
const { resolvedMember
|
|
267
|
+
const { resolvedMember } = aclResult;
|
|
281
268
|
|
|
282
269
|
// ── Slack delete propagation ──
|
|
283
270
|
// Slack message_deleted events are forwarded by the gateway with the
|
|
@@ -300,7 +287,7 @@ export async function handleChannelInbound(
|
|
|
300
287
|
{ conversationExternalId },
|
|
301
288
|
"Slack message_deleted event missing sourceMetadata.messageId; ignoring",
|
|
302
289
|
);
|
|
303
|
-
return
|
|
290
|
+
return { accepted: true, deleted: false };
|
|
304
291
|
}
|
|
305
292
|
|
|
306
293
|
// Look up the stored message via the existing channel-event lookup.
|
|
@@ -314,7 +301,7 @@ export async function handleChannelInbound(
|
|
|
314
301
|
// that window is silently dropped and the deletion signal is lost.
|
|
315
302
|
let original: { messageId: string; conversationId: string } | null = null;
|
|
316
303
|
for (let attempt = 0; attempt <= deleteLookupRetries; attempt++) {
|
|
317
|
-
original =
|
|
304
|
+
original = findMessageBySourceId(
|
|
318
305
|
sourceChannel,
|
|
319
306
|
conversationExternalId,
|
|
320
307
|
deletedMessageTs,
|
|
@@ -341,7 +328,7 @@ export async function handleChannelInbound(
|
|
|
341
328
|
{ conversationExternalId, deletedMessageTs },
|
|
342
329
|
"No stored message found for Slack delete after retries; ignoring",
|
|
343
330
|
);
|
|
344
|
-
return
|
|
331
|
+
return { accepted: true, deleted: false };
|
|
345
332
|
}
|
|
346
333
|
|
|
347
334
|
// Merge deletedAt into the existing slackMeta sub-key. If the row has
|
|
@@ -359,7 +346,7 @@ export async function handleChannelInbound(
|
|
|
359
346
|
},
|
|
360
347
|
"Stored Slack message has no metadata; skipping delete marker",
|
|
361
348
|
);
|
|
362
|
-
return
|
|
349
|
+
return { accepted: true, deleted: false };
|
|
363
350
|
}
|
|
364
351
|
|
|
365
352
|
let parentMetadata: Record<string, unknown>;
|
|
@@ -379,7 +366,7 @@ export async function handleChannelInbound(
|
|
|
379
366
|
},
|
|
380
367
|
"Failed to parse stored metadata; skipping delete marker",
|
|
381
368
|
);
|
|
382
|
-
return
|
|
369
|
+
return { accepted: true, deleted: false };
|
|
383
370
|
}
|
|
384
371
|
|
|
385
372
|
const existingSlackMeta =
|
|
@@ -396,7 +383,7 @@ export async function handleChannelInbound(
|
|
|
396
383
|
},
|
|
397
384
|
"Stored Slack message has no slackMeta; skipping delete marker",
|
|
398
385
|
);
|
|
399
|
-
return
|
|
386
|
+
return { accepted: true, deleted: false };
|
|
400
387
|
}
|
|
401
388
|
|
|
402
389
|
const updatedSlackMeta = mergeSlackMetadata(existingSlackMeta, {
|
|
@@ -418,21 +405,20 @@ export async function handleChannelInbound(
|
|
|
418
405
|
"Marked Slack message as deleted",
|
|
419
406
|
);
|
|
420
407
|
|
|
421
|
-
return
|
|
408
|
+
return {
|
|
422
409
|
accepted: true,
|
|
423
410
|
deleted: true,
|
|
424
411
|
messageId: original.messageId,
|
|
425
|
-
}
|
|
412
|
+
};
|
|
426
413
|
}
|
|
427
414
|
|
|
428
415
|
if (hasAttachments) {
|
|
429
|
-
const resolved =
|
|
416
|
+
const resolved = getAttachmentsByIds(attachmentIds);
|
|
430
417
|
if (resolved.length !== attachmentIds.length) {
|
|
431
418
|
const resolvedIds = new Set(resolved.map((a) => a.id));
|
|
432
419
|
const missing = attachmentIds.filter((id) => !resolvedIds.has(id));
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
{ status: 400 },
|
|
420
|
+
throw new BadRequestError(
|
|
421
|
+
`Attachment IDs not found: ${missing.join(", ")}`,
|
|
436
422
|
);
|
|
437
423
|
}
|
|
438
424
|
}
|
|
@@ -466,11 +452,7 @@ export async function handleChannelInbound(
|
|
|
466
452
|
: undefined;
|
|
467
453
|
|
|
468
454
|
if (isEdit && !sourceMessageId) {
|
|
469
|
-
|
|
470
|
-
"BAD_REQUEST",
|
|
471
|
-
"sourceMetadata.messageId is required for edits",
|
|
472
|
-
400,
|
|
473
|
-
);
|
|
455
|
+
throw new BadRequestError("sourceMetadata.messageId is required for edits");
|
|
474
456
|
}
|
|
475
457
|
|
|
476
458
|
// ── Edit path: update existing message content, no new agent loop ──
|
|
@@ -488,7 +470,7 @@ export async function handleChannelInbound(
|
|
|
488
470
|
}
|
|
489
471
|
|
|
490
472
|
// ── New message path ──
|
|
491
|
-
const result =
|
|
473
|
+
const result = recordInbound(
|
|
492
474
|
sourceChannel,
|
|
493
475
|
conversationExternalId,
|
|
494
476
|
externalMessageId,
|
|
@@ -502,21 +484,15 @@ export async function handleChannelInbound(
|
|
|
502
484
|
// gateway retries (duplicates) re-attempt delivery here. On success the
|
|
503
485
|
// pending marker is cleared so further duplicates short-circuit normally.
|
|
504
486
|
if (result.duplicate && replyCallbackUrl) {
|
|
505
|
-
const pendingReply =
|
|
506
|
-
result.eventId,
|
|
507
|
-
);
|
|
487
|
+
const pendingReply = getPendingVerificationReply(result.eventId);
|
|
508
488
|
if (pendingReply) {
|
|
509
489
|
try {
|
|
510
|
-
await deliverChannelReply(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
},
|
|
517
|
-
mintBearerToken(),
|
|
518
|
-
);
|
|
519
|
-
deliveryChannels.clearPendingVerificationReply(result.eventId);
|
|
490
|
+
await deliverChannelReply(replyCallbackUrl, {
|
|
491
|
+
chatId: pendingReply.chatId,
|
|
492
|
+
text: pendingReply.text,
|
|
493
|
+
assistantId: pendingReply.assistantId,
|
|
494
|
+
});
|
|
495
|
+
clearPendingVerificationReply(result.eventId);
|
|
520
496
|
log.info(
|
|
521
497
|
{ eventId: result.eventId },
|
|
522
498
|
"Retried pending verification reply: delivered",
|
|
@@ -527,11 +503,11 @@ export async function handleChannelInbound(
|
|
|
527
503
|
"Retry of pending verification reply failed; will retry on next duplicate",
|
|
528
504
|
);
|
|
529
505
|
}
|
|
530
|
-
return
|
|
506
|
+
return {
|
|
531
507
|
accepted: true,
|
|
532
508
|
duplicate: true,
|
|
533
509
|
eventId: result.eventId,
|
|
534
|
-
}
|
|
510
|
+
};
|
|
535
511
|
}
|
|
536
512
|
}
|
|
537
513
|
|
|
@@ -546,7 +522,7 @@ export async function handleChannelInbound(
|
|
|
546
522
|
// self so assistant-scoped legacy routes do not overwrite each other's
|
|
547
523
|
// channel binding metadata for the same chat.
|
|
548
524
|
if (canonicalAssistantId === DAEMON_INTERNAL_ASSISTANT_ID) {
|
|
549
|
-
|
|
525
|
+
upsertBinding({
|
|
550
526
|
conversationId: result.conversationId,
|
|
551
527
|
sourceChannel,
|
|
552
528
|
externalChatId: conversationExternalId,
|
|
@@ -568,10 +544,10 @@ export async function handleChannelInbound(
|
|
|
568
544
|
// guardian approval reactions have no transcript representation.
|
|
569
545
|
// 2. All other reactions (non-guardian, no pending approval, stale,
|
|
570
546
|
// and any `reaction_removed:` event regardless of actor) fall
|
|
571
|
-
// through to `persistSlackReactionAsMessage` so
|
|
572
|
-
//
|
|
573
|
-
//
|
|
574
|
-
//
|
|
547
|
+
// through to `persistSlackReactionAsMessage` so Slack transcript
|
|
548
|
+
// rendering can surface them inline. Reactions never trigger an
|
|
549
|
+
// agent response, so we short-circuit before escalation and
|
|
550
|
+
// agent-loop dispatch in both cases.
|
|
575
551
|
if (isSlackReactionEvent(body)) {
|
|
576
552
|
// Approval interception runs only for reactions (added) — `reaction_removed`
|
|
577
553
|
// never expresses an approval intent, so un-reacting is left as a pure
|
|
@@ -601,7 +577,6 @@ export async function handleChannelInbound(
|
|
|
601
577
|
sourceChannel,
|
|
602
578
|
actorExternalId: canonicalSenderId ?? rawSenderId,
|
|
603
579
|
replyCallbackUrl,
|
|
604
|
-
bearerToken: mintBearerToken(),
|
|
605
580
|
trustCtx: trustCtxForReaction,
|
|
606
581
|
assistantId: canonicalAssistantId,
|
|
607
582
|
approvalCopyGenerator,
|
|
@@ -614,12 +589,12 @@ export async function handleChannelInbound(
|
|
|
614
589
|
// transcript line. All other interception outcomes (stale_ignored,
|
|
615
590
|
// non-guardian, no pending approval) fall through to persistence.
|
|
616
591
|
if (reactionApprovalResult.type === "guardian_decision_applied") {
|
|
617
|
-
return
|
|
592
|
+
return {
|
|
618
593
|
accepted: true,
|
|
619
594
|
duplicate: false,
|
|
620
595
|
eventId: result.eventId,
|
|
621
596
|
approval: reactionApprovalResult.type,
|
|
622
|
-
}
|
|
597
|
+
};
|
|
623
598
|
}
|
|
624
599
|
}
|
|
625
600
|
|
|
@@ -632,11 +607,11 @@ export async function handleChannelInbound(
|
|
|
632
607
|
{ conversationId: result.conversationId, eventId: result.eventId },
|
|
633
608
|
"Skipping reaction persistence: missing sourceMetadata.messageId",
|
|
634
609
|
);
|
|
635
|
-
return
|
|
610
|
+
return {
|
|
636
611
|
accepted: result.accepted,
|
|
637
612
|
duplicate: result.duplicate,
|
|
638
613
|
eventId: result.eventId,
|
|
639
|
-
}
|
|
614
|
+
};
|
|
640
615
|
}
|
|
641
616
|
|
|
642
617
|
const threadTs =
|
|
@@ -662,11 +637,11 @@ export async function handleChannelInbound(
|
|
|
662
637
|
);
|
|
663
638
|
}
|
|
664
639
|
|
|
665
|
-
return
|
|
640
|
+
return {
|
|
666
641
|
accepted: result.accepted,
|
|
667
642
|
duplicate: result.duplicate,
|
|
668
643
|
eventId: result.eventId,
|
|
669
|
-
}
|
|
644
|
+
};
|
|
670
645
|
}
|
|
671
646
|
|
|
672
647
|
// ── Ingress escalation ──
|
|
@@ -698,6 +673,7 @@ export async function handleChannelInbound(
|
|
|
698
673
|
typeof hint === "string" && hint.trim().length > 0,
|
|
699
674
|
)
|
|
700
675
|
: [];
|
|
676
|
+
let slackRuntimeContextNotice: string | undefined;
|
|
701
677
|
|
|
702
678
|
// Inject channel-scoped permission hints for Slack channel messages
|
|
703
679
|
if (sourceChannel === "slack") {
|
|
@@ -762,25 +738,6 @@ export async function handleChannelInbound(
|
|
|
762
738
|
});
|
|
763
739
|
if (bootstrapResponse) return bootstrapResponse;
|
|
764
740
|
|
|
765
|
-
// ── Guardian verification code intercept (deterministic) ──
|
|
766
|
-
const verificationResponse = await handleVerificationIntercept({
|
|
767
|
-
isDuplicate: result.duplicate,
|
|
768
|
-
guardianVerifyCode,
|
|
769
|
-
rawSenderId,
|
|
770
|
-
canonicalSenderId,
|
|
771
|
-
canonicalAssistantId,
|
|
772
|
-
sourceChannel,
|
|
773
|
-
conversationExternalId,
|
|
774
|
-
conversationId: result.conversationId,
|
|
775
|
-
eventId: result.eventId,
|
|
776
|
-
replyCallbackUrl,
|
|
777
|
-
mintBearerToken,
|
|
778
|
-
assistantId,
|
|
779
|
-
actorDisplayName: body.actorDisplayName,
|
|
780
|
-
actorUsername: body.actorUsername,
|
|
781
|
-
});
|
|
782
|
-
if (verificationResponse) return verificationResponse;
|
|
783
|
-
|
|
784
741
|
// Legacy voice guardian action interception removed — all guardian reply
|
|
785
742
|
// routing now flows through the canonical router below (routeGuardianReply),
|
|
786
743
|
// which handles request code matching, callback parsing, and NL classification
|
|
@@ -812,7 +769,6 @@ export async function handleChannelInbound(
|
|
|
812
769
|
conversationId: result.conversationId,
|
|
813
770
|
eventId: result.eventId,
|
|
814
771
|
replyCallbackUrl,
|
|
815
|
-
mintBearerToken,
|
|
816
772
|
trustClass: trustCtx.trustClass,
|
|
817
773
|
guardianPrincipalId: trustCtx.guardianPrincipalId,
|
|
818
774
|
approvalConversationGenerator,
|
|
@@ -846,7 +802,6 @@ export async function handleChannelInbound(
|
|
|
846
802
|
sourceChannel,
|
|
847
803
|
actorExternalId: canonicalSenderId ?? rawSenderId,
|
|
848
804
|
replyCallbackUrl,
|
|
849
|
-
bearerToken: mintBearerToken(),
|
|
850
805
|
trustCtx,
|
|
851
806
|
assistantId: canonicalAssistantId,
|
|
852
807
|
approvalCopyGenerator,
|
|
@@ -893,12 +848,12 @@ export async function handleChannelInbound(
|
|
|
893
848
|
}
|
|
894
849
|
}
|
|
895
850
|
|
|
896
|
-
return
|
|
851
|
+
return {
|
|
897
852
|
accepted: true,
|
|
898
853
|
duplicate: false,
|
|
899
854
|
eventId: result.eventId,
|
|
900
855
|
approval: approvalResult.type,
|
|
901
|
-
}
|
|
856
|
+
};
|
|
902
857
|
}
|
|
903
858
|
|
|
904
859
|
// When a callback payload was not handled by approval interception, it's
|
|
@@ -940,16 +895,12 @@ export async function handleChannelInbound(
|
|
|
940
895
|
// and deliver an ephemeral error so the user gets visible feedback
|
|
941
896
|
// instead of a silent no-op (JARVIS-299).
|
|
942
897
|
if (sourceChannel === "slack" && replyCallbackUrl && approvalMessageTs) {
|
|
943
|
-
deliverChannelReply(
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
assistantId: canonicalAssistantId,
|
|
950
|
-
},
|
|
951
|
-
mintBearerToken(),
|
|
952
|
-
).catch((err) => {
|
|
898
|
+
deliverChannelReply(replyCallbackUrl, {
|
|
899
|
+
chatId: conversationExternalId,
|
|
900
|
+
text: "This approval request has been resolved.",
|
|
901
|
+
messageTs: approvalMessageTs,
|
|
902
|
+
assistantId: canonicalAssistantId,
|
|
903
|
+
}).catch((err) => {
|
|
953
904
|
log.error(
|
|
954
905
|
{ err, conversationId: result.conversationId },
|
|
955
906
|
"Failed to edit stale Slack approval message",
|
|
@@ -957,18 +908,18 @@ export async function handleChannelInbound(
|
|
|
957
908
|
});
|
|
958
909
|
}
|
|
959
910
|
|
|
960
|
-
return
|
|
911
|
+
return {
|
|
961
912
|
accepted: true,
|
|
962
913
|
duplicate: false,
|
|
963
914
|
eventId: result.eventId,
|
|
964
915
|
approval: "stale_ignored",
|
|
965
|
-
}
|
|
916
|
+
};
|
|
966
917
|
}
|
|
967
918
|
}
|
|
968
919
|
|
|
969
920
|
// For new (non-duplicate) messages, run the secret ingress check
|
|
970
921
|
// synchronously, then fire off the agent loop in the background.
|
|
971
|
-
if (!result.duplicate
|
|
922
|
+
if (!result.duplicate) {
|
|
972
923
|
const ingressResult = runSecretIngressCheck({
|
|
973
924
|
eventId: result.eventId,
|
|
974
925
|
sourceChannel,
|
|
@@ -989,7 +940,7 @@ export async function handleChannelInbound(
|
|
|
989
940
|
|
|
990
941
|
if (ingressResult.blocked) {
|
|
991
942
|
// Intentional block — mark the event as processed (not failed/dead-lettered).
|
|
992
|
-
|
|
943
|
+
markProcessed(result.eventId);
|
|
993
944
|
log.info(
|
|
994
945
|
{
|
|
995
946
|
eventId: result.eventId,
|
|
@@ -1067,25 +1018,27 @@ export async function handleChannelInbound(
|
|
|
1067
1018
|
});
|
|
1068
1019
|
}
|
|
1069
1020
|
|
|
1070
|
-
// ── Thread
|
|
1071
|
-
// When a Slack reply arrives
|
|
1072
|
-
//
|
|
1073
|
-
//
|
|
1074
|
-
//
|
|
1075
|
-
//
|
|
1076
|
-
//
|
|
1077
|
-
//
|
|
1078
|
-
//
|
|
1079
|
-
//
|
|
1080
|
-
// swallowed inside the helper so they never block dispatch.
|
|
1021
|
+
// ── Thread gap/delta backfill ──
|
|
1022
|
+
// When a Slack thread reply arrives, compare the stored thread state
|
|
1023
|
+
// with the inbound message's ts and fetch only the bounded unseen
|
|
1024
|
+
// window. Initial late-join turns hydrate the earliest thread messages
|
|
1025
|
+
// plus a recent window adjacent to the inbound reply; later turns use
|
|
1026
|
+
// a delta window after the latest stored thread ts and before the
|
|
1027
|
+
// inbound ts. Awaited (mirrors the DM cold-start path above) so the
|
|
1028
|
+
// agent loop dispatched immediately afterwards observes hydrated
|
|
1029
|
+
// context. A late-join notice is added only to the current turn's
|
|
1030
|
+
// runtime context, not persisted as durable Slack metadata. Failures
|
|
1031
|
+
// are swallowed inside the helper so they never block dispatch.
|
|
1081
1032
|
if (slackThreadTs) {
|
|
1082
|
-
await triggerSlackThreadBackfillIfNeeded({
|
|
1033
|
+
const backfillResult = await triggerSlackThreadBackfillIfNeeded({
|
|
1083
1034
|
conversationId: result.conversationId,
|
|
1084
1035
|
channelId: conversationExternalId,
|
|
1085
1036
|
threadTs: slackThreadTs,
|
|
1086
1037
|
excludeChannelTs: slackInbound?.channelTs,
|
|
1087
1038
|
account: slackAccount,
|
|
1088
1039
|
});
|
|
1040
|
+
const lateJoinNotice = buildSlackLateJoinNotice(backfillResult);
|
|
1041
|
+
if (lateJoinNotice) slackRuntimeContextNotice = lateJoinNotice;
|
|
1089
1042
|
}
|
|
1090
1043
|
|
|
1091
1044
|
// Wrap non-guardian inbound content in external_content boundaries so
|
|
@@ -1113,11 +1066,11 @@ export async function handleChannelInbound(
|
|
|
1113
1066
|
externalChatId: conversationExternalId,
|
|
1114
1067
|
trustCtx,
|
|
1115
1068
|
metadataHints,
|
|
1069
|
+
slackRuntimeContextNotice,
|
|
1116
1070
|
metadataUxBrief,
|
|
1117
1071
|
commandIntent,
|
|
1118
1072
|
sourceLanguageCode,
|
|
1119
1073
|
replyCallbackUrl,
|
|
1120
|
-
mintBearerToken,
|
|
1121
1074
|
assistantId: canonicalAssistantId,
|
|
1122
1075
|
approvalCopyGenerator,
|
|
1123
1076
|
chatType: sourceChatType,
|
|
@@ -1126,11 +1079,11 @@ export async function handleChannelInbound(
|
|
|
1126
1079
|
}
|
|
1127
1080
|
}
|
|
1128
1081
|
|
|
1129
|
-
return
|
|
1082
|
+
return {
|
|
1130
1083
|
accepted: result.accepted,
|
|
1131
1084
|
duplicate: result.duplicate,
|
|
1132
1085
|
eventId: result.eventId,
|
|
1133
|
-
}
|
|
1086
|
+
};
|
|
1134
1087
|
}
|
|
1135
1088
|
|
|
1136
1089
|
/**
|
|
@@ -1229,8 +1182,8 @@ async function persistSlackReactionAsMessage(params: {
|
|
|
1229
1182
|
},
|
|
1230
1183
|
};
|
|
1231
1184
|
|
|
1232
|
-
// Sentinel content —
|
|
1233
|
-
// reaction line; the literal text is never displayed to the model.
|
|
1185
|
+
// Sentinel content — Slack transcript renderers read `slackMeta` to format
|
|
1186
|
+
// the reaction line; the literal text is never displayed to the model.
|
|
1234
1187
|
const persisted = await addMessage(
|
|
1235
1188
|
params.conversationId,
|
|
1236
1189
|
"user",
|
|
@@ -1238,8 +1191,8 @@ async function persistSlackReactionAsMessage(params: {
|
|
|
1238
1191
|
{ slackMeta: writeSlackMetadata(slackMeta) },
|
|
1239
1192
|
{ skipIndexing: true },
|
|
1240
1193
|
);
|
|
1241
|
-
|
|
1242
|
-
|
|
1194
|
+
linkMessage(params.eventId, persisted.id);
|
|
1195
|
+
markProcessed(params.eventId);
|
|
1243
1196
|
}
|
|
1244
1197
|
|
|
1245
1198
|
/**
|
|
@@ -1309,19 +1262,7 @@ function countSlackMetaMessages(conversationId: string): number {
|
|
|
1309
1262
|
);
|
|
1310
1263
|
if (candidates.length === 0) return count;
|
|
1311
1264
|
for (const raw of candidates) {
|
|
1312
|
-
|
|
1313
|
-
try {
|
|
1314
|
-
const parsed = JSON.parse(raw) as unknown;
|
|
1315
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1316
|
-
parent = parsed as Record<string, unknown>;
|
|
1317
|
-
}
|
|
1318
|
-
} catch {
|
|
1319
|
-
continue;
|
|
1320
|
-
}
|
|
1321
|
-
if (!parent) continue;
|
|
1322
|
-
const inner = parent.slackMeta;
|
|
1323
|
-
if (typeof inner !== "string") continue;
|
|
1324
|
-
if (readSlackMetadata(inner)) {
|
|
1265
|
+
if (readSlackMetadataFromMessageMetadata(raw)) {
|
|
1325
1266
|
count++;
|
|
1326
1267
|
if (count >= SLACK_DM_BACKFILL_WARM_THRESHOLD) return count;
|
|
1327
1268
|
}
|
|
@@ -1332,44 +1273,110 @@ function countSlackMetaMessages(conversationId: string): number {
|
|
|
1332
1273
|
return count;
|
|
1333
1274
|
}
|
|
1334
1275
|
|
|
1276
|
+
function readSlackMetadataFromMessageMetadata(
|
|
1277
|
+
metadata: string | null | undefined,
|
|
1278
|
+
): SlackMessageMetadata | null {
|
|
1279
|
+
if (!metadata) return null;
|
|
1280
|
+
let parent: Record<string, unknown> | null = null;
|
|
1281
|
+
try {
|
|
1282
|
+
const parsed = JSON.parse(metadata) as unknown;
|
|
1283
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1284
|
+
parent = parsed as Record<string, unknown>;
|
|
1285
|
+
}
|
|
1286
|
+
} catch {
|
|
1287
|
+
return null;
|
|
1288
|
+
}
|
|
1289
|
+
if (!parent) return null;
|
|
1290
|
+
const raw = parent.slackMeta;
|
|
1291
|
+
if (typeof raw !== "string") return null;
|
|
1292
|
+
return readSlackMetadata(raw);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1335
1295
|
/**
|
|
1336
1296
|
* Build the set of `slackMeta.channelTs` values already stored on a
|
|
1337
|
-
* conversation. Used by both DM cold-start backfill and thread
|
|
1297
|
+
* conversation. Used by both DM cold-start backfill and thread gap/delta
|
|
1338
1298
|
* backfill to dedupe rows so a partial prior backfill (or a single message
|
|
1339
1299
|
* that was already persisted via the live ingress path) does not double-write.
|
|
1340
1300
|
*/
|
|
1341
1301
|
function readStoredSlackChannelTs(conversationId: string): Set<string> {
|
|
1342
1302
|
const seen = new Set<string>();
|
|
1343
1303
|
for (const row of getMessages(conversationId)) {
|
|
1344
|
-
|
|
1345
|
-
let parent: Record<string, unknown> | null = null;
|
|
1346
|
-
try {
|
|
1347
|
-
const parsed = JSON.parse(row.metadata) as unknown;
|
|
1348
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1349
|
-
parent = parsed as Record<string, unknown>;
|
|
1350
|
-
}
|
|
1351
|
-
} catch {
|
|
1352
|
-
continue;
|
|
1353
|
-
}
|
|
1354
|
-
if (!parent) continue;
|
|
1355
|
-
const raw = parent.slackMeta;
|
|
1356
|
-
if (typeof raw !== "string") continue;
|
|
1357
|
-
const meta = readSlackMetadata(raw);
|
|
1304
|
+
const meta = readSlackMetadataFromMessageMetadata(row.metadata);
|
|
1358
1305
|
// Only message rows represent stored Slack messages. Reaction rows carry
|
|
1359
1306
|
// `channelTs` equal to the target message's ts, so including them would
|
|
1360
|
-
// make a reaction on a thread parent wrongly short-circuit
|
|
1307
|
+
// make a reaction on a thread parent wrongly short-circuit thread
|
|
1361
1308
|
// backfill (the parent itself may still be unseen).
|
|
1362
1309
|
if (meta && meta.eventKind === "message") seen.add(meta.channelTs);
|
|
1363
1310
|
}
|
|
1364
1311
|
return seen;
|
|
1365
1312
|
}
|
|
1366
1313
|
|
|
1314
|
+
interface ParsedSlackTimestamp {
|
|
1315
|
+
seconds: bigint;
|
|
1316
|
+
micros: bigint;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function parseSlackTimestamp(
|
|
1320
|
+
ts: string | undefined,
|
|
1321
|
+
): ParsedSlackTimestamp | null {
|
|
1322
|
+
if (!ts) return null;
|
|
1323
|
+
const match = /^(\d+)\.(\d{1,6})$/.exec(ts);
|
|
1324
|
+
if (!match) return null;
|
|
1325
|
+
const micros = BigInt(match[2]);
|
|
1326
|
+
if (micros > 999_999n) return null;
|
|
1327
|
+
return {
|
|
1328
|
+
seconds: BigInt(match[1]),
|
|
1329
|
+
micros,
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
function compareSlackTimestamps(left: string, right: string): number | null {
|
|
1334
|
+
const parsedLeft = parseSlackTimestamp(left);
|
|
1335
|
+
const parsedRight = parseSlackTimestamp(right);
|
|
1336
|
+
if (!parsedLeft || !parsedRight) return null;
|
|
1337
|
+
if (parsedLeft.seconds < parsedRight.seconds) return -1;
|
|
1338
|
+
if (parsedLeft.seconds > parsedRight.seconds) return 1;
|
|
1339
|
+
if (parsedLeft.micros < parsedRight.micros) return -1;
|
|
1340
|
+
if (parsedLeft.micros > parsedRight.micros) return 1;
|
|
1341
|
+
return 0;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
interface StoredSlackThreadState {
|
|
1345
|
+
storedChannelTs: Set<string>;
|
|
1346
|
+
latestStoredThreadTs: string | undefined;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
function readStoredSlackThreadState(
|
|
1350
|
+
conversationId: string,
|
|
1351
|
+
threadTs: string,
|
|
1352
|
+
): StoredSlackThreadState {
|
|
1353
|
+
const storedChannelTs = new Set<string>();
|
|
1354
|
+
let latestStoredThreadTs: string | undefined;
|
|
1355
|
+
|
|
1356
|
+
for (const row of getMessages(conversationId)) {
|
|
1357
|
+
const meta = readSlackMetadataFromMessageMetadata(row.metadata);
|
|
1358
|
+
if (!meta || meta.eventKind !== "message") continue;
|
|
1359
|
+
if (meta.channelTs !== threadTs && meta.threadTs !== threadTs) continue;
|
|
1360
|
+
|
|
1361
|
+
storedChannelTs.add(meta.channelTs);
|
|
1362
|
+
if (!parseSlackTimestamp(meta.channelTs)) continue;
|
|
1363
|
+
if (
|
|
1364
|
+
latestStoredThreadTs === undefined ||
|
|
1365
|
+
compareSlackTimestamps(meta.channelTs, latestStoredThreadTs) === 1
|
|
1366
|
+
) {
|
|
1367
|
+
latestStoredThreadTs = meta.channelTs;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
return { storedChannelTs, latestStoredThreadTs };
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1367
1374
|
/**
|
|
1368
1375
|
* Persist a single backfilled Slack message as a `messages` row with a
|
|
1369
1376
|
* `slackMeta` envelope.
|
|
1370
1377
|
*
|
|
1371
1378
|
* Shared insertion point for any path that hydrates Slack history lazily
|
|
1372
|
-
* (DM cold-start backfill, thread
|
|
1379
|
+
* (DM cold-start backfill, thread gap/delta backfill, etc.). Role is derived
|
|
1373
1380
|
* from `message.metadata.isBot` — bot-authored rows map to `"assistant"` so
|
|
1374
1381
|
* our own prior replies (and any other bot traffic) are not rehydrated as
|
|
1375
1382
|
* user turns, which would otherwise corrupt speaker attribution and make
|
|
@@ -1383,6 +1390,7 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1383
1390
|
message: ProviderMessage;
|
|
1384
1391
|
}): Promise<void> {
|
|
1385
1392
|
const { message } = params;
|
|
1393
|
+
const slackFiles = readSlackFilesFromProviderMetadata(message.metadata);
|
|
1386
1394
|
const slackMeta: SlackMessageMetadata = {
|
|
1387
1395
|
source: "slack",
|
|
1388
1396
|
channelId: params.channelId,
|
|
@@ -1390,6 +1398,7 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1390
1398
|
eventKind: "message",
|
|
1391
1399
|
...(message.threadId ? { threadTs: message.threadId } : {}),
|
|
1392
1400
|
...(message.sender?.name ? { displayName: message.sender.name } : {}),
|
|
1401
|
+
...(slackFiles.length > 0 ? { slackFiles } : {}),
|
|
1393
1402
|
};
|
|
1394
1403
|
const role = message.metadata?.isBot === true ? "assistant" : "user";
|
|
1395
1404
|
await addMessage(params.conversationId, role, message.text ?? "", {
|
|
@@ -1397,6 +1406,32 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1397
1406
|
});
|
|
1398
1407
|
}
|
|
1399
1408
|
|
|
1409
|
+
function readSlackFilesFromProviderMetadata(
|
|
1410
|
+
metadata: Record<string, unknown> | undefined,
|
|
1411
|
+
): SlackFileMetadata[] {
|
|
1412
|
+
const raw = metadata?.slackFiles;
|
|
1413
|
+
if (!Array.isArray(raw)) return [];
|
|
1414
|
+
const files: SlackFileMetadata[] = [];
|
|
1415
|
+
for (const item of raw) {
|
|
1416
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) {
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
const record = item as Record<string, unknown>;
|
|
1420
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
1421
|
+
if (!name) continue;
|
|
1422
|
+
files.push({
|
|
1423
|
+
...(typeof record.id === "string" && record.id.length > 0
|
|
1424
|
+
? { id: record.id }
|
|
1425
|
+
: {}),
|
|
1426
|
+
name,
|
|
1427
|
+
...(typeof record.mimetype === "string" && record.mimetype.length > 0
|
|
1428
|
+
? { mimetype: record.mimetype }
|
|
1429
|
+
: {}),
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
return files;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1400
1435
|
/**
|
|
1401
1436
|
* In-memory map of in-flight DM cold-start backfills keyed by conversationId.
|
|
1402
1437
|
* Concurrent inbound DMs to the same cold conversation share a single
|
|
@@ -1539,13 +1574,11 @@ async function runBackfillSlackDmIfCold(params: {
|
|
|
1539
1574
|
// ---------------------------------------------------------------------------
|
|
1540
1575
|
|
|
1541
1576
|
/**
|
|
1542
|
-
* In-memory TTL cache keyed by
|
|
1543
|
-
*
|
|
1544
|
-
* thread
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1547
|
-
* backfill becomes a cheap "are the parents already stored?" DB lookup
|
|
1548
|
-
* that short-circuits before the Slack API is touched.
|
|
1577
|
+
* In-memory TTL cache keyed by
|
|
1578
|
+
* `<conversationId>:<threadTs>:<lowerBoundTs>:<upperBoundTs>`. Tracks recent
|
|
1579
|
+
* thread-backfill windows so repeated triggers for the same Slack gap do not
|
|
1580
|
+
* re-fetch identical rows while later replies in the same thread can still
|
|
1581
|
+
* request newer unseen windows.
|
|
1549
1582
|
*
|
|
1550
1583
|
* Exported only for tests; production callers should use
|
|
1551
1584
|
* {@link triggerSlackThreadBackfillIfNeeded}.
|
|
@@ -1554,6 +1587,39 @@ export const _backfillTriggerCache = new Map<string, number>();
|
|
|
1554
1587
|
|
|
1555
1588
|
const BACKFILL_TRIGGER_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
1556
1589
|
const BACKFILL_TRIGGER_CACHE_MAX = 1_000;
|
|
1590
|
+
const SLACK_THREAD_INITIAL_EARLY_LIMIT = 25;
|
|
1591
|
+
const SLACK_THREAD_INITIAL_RECENT_LIMIT = 50;
|
|
1592
|
+
const SLACK_THREAD_INITIAL_RECENT_MAX_PAGES = 5;
|
|
1593
|
+
const SLACK_THREAD_DELTA_LIMIT = 50;
|
|
1594
|
+
const SLACK_THREAD_UPPER_ADJACENT_MAX_ATTEMPTS = 5;
|
|
1595
|
+
const MICROS_PER_SECOND = 1_000_000n;
|
|
1596
|
+
const SLACK_UPPER_ADJACENT_EXPANDING_WINDOWS_MICROS = [
|
|
1597
|
+
5n * 60n * MICROS_PER_SECOND,
|
|
1598
|
+
60n * 60n * MICROS_PER_SECOND,
|
|
1599
|
+
24n * 60n * 60n * MICROS_PER_SECOND,
|
|
1600
|
+
7n * 24n * 60n * 60n * MICROS_PER_SECOND,
|
|
1601
|
+
30n * 24n * 60n * 60n * MICROS_PER_SECOND,
|
|
1602
|
+
];
|
|
1603
|
+
const SLACK_UPPER_ADJACENT_SHRINKING_WINDOWS_MICROS = [
|
|
1604
|
+
60n * MICROS_PER_SECOND,
|
|
1605
|
+
10n * MICROS_PER_SECOND,
|
|
1606
|
+
MICROS_PER_SECOND,
|
|
1607
|
+
100_000n,
|
|
1608
|
+
1_000n,
|
|
1609
|
+
];
|
|
1610
|
+
|
|
1611
|
+
export interface SlackThreadBackfillResult {
|
|
1612
|
+
fetched: number;
|
|
1613
|
+
persisted: number;
|
|
1614
|
+
reason?: SlackBackfillReason;
|
|
1615
|
+
omittedMiddle: boolean;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
type SlackBackfillReason = "thread_late_join" | "thread_delta";
|
|
1619
|
+
|
|
1620
|
+
function emptySlackThreadBackfillResult(): SlackThreadBackfillResult {
|
|
1621
|
+
return { fetched: 0, persisted: 0, omittedMiddle: false };
|
|
1622
|
+
}
|
|
1557
1623
|
|
|
1558
1624
|
function pruneBackfillCacheIfNeeded(): void {
|
|
1559
1625
|
if (_backfillTriggerCache.size < BACKFILL_TRIGGER_CACHE_MAX) return;
|
|
@@ -1588,23 +1654,315 @@ function isBackfillRecentlyTriggered(cacheKey: string): boolean {
|
|
|
1588
1654
|
return true;
|
|
1589
1655
|
}
|
|
1590
1656
|
|
|
1657
|
+
interface SlackInitialThreadWindowsResult {
|
|
1658
|
+
messages: ProviderMessage[];
|
|
1659
|
+
omittedMiddle: boolean;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
interface SlackUpperAdjacentWindowResult {
|
|
1663
|
+
messages: ProviderMessage[];
|
|
1664
|
+
omittedEarlierContent: boolean;
|
|
1665
|
+
truncatedBeforeUpperBound: boolean;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
function slackPageHasMore(page: SlackBackfillWindowPage): boolean {
|
|
1669
|
+
return page.hasMore || page.nextCursor !== undefined;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
function minSlackMessageTs(messages: ProviderMessage[]): string | undefined {
|
|
1673
|
+
return sortSlackProviderMessages(messages)[0]?.id;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
function maxSlackMessageTs(messages: ProviderMessage[]): string | undefined {
|
|
1677
|
+
const sorted = sortSlackProviderMessages(messages);
|
|
1678
|
+
return sorted[sorted.length - 1]?.id;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
function slackTimestampToMicros(ts: string | undefined): bigint | null {
|
|
1682
|
+
const parsed = parseSlackTimestamp(ts);
|
|
1683
|
+
if (!parsed) return null;
|
|
1684
|
+
return parsed.seconds * MICROS_PER_SECOND + parsed.micros;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
function slackTimestampFromMicros(totalMicros: bigint): string | undefined {
|
|
1688
|
+
if (totalMicros < 0n) return undefined;
|
|
1689
|
+
const seconds = totalMicros / MICROS_PER_SECOND;
|
|
1690
|
+
const micros = totalMicros % MICROS_PER_SECOND;
|
|
1691
|
+
return `${seconds.toString()}.${micros.toString().padStart(6, "0")}`;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
function didInitialWindowsLeaveGap(params: {
|
|
1695
|
+
early: SlackBackfillWindowPage;
|
|
1696
|
+
recent: SlackBackfillWindowPage;
|
|
1697
|
+
recentScanTruncated: boolean;
|
|
1698
|
+
}): boolean {
|
|
1699
|
+
if (params.recentScanTruncated) return true;
|
|
1700
|
+
if (!slackPageHasMore(params.early)) return false;
|
|
1701
|
+
const earlyMax = maxSlackMessageTs(params.early.messages);
|
|
1702
|
+
const recentMin = minSlackMessageTs(params.recent.messages);
|
|
1703
|
+
if (!earlyMax || !recentMin) return false;
|
|
1704
|
+
const compared = compareSlackTimestamps(earlyMax, recentMin);
|
|
1705
|
+
return compared !== null && compared < 0;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
async function fetchSlackThreadUpperAdjacentWindow(params: {
|
|
1709
|
+
channelId: string;
|
|
1710
|
+
threadTs: string;
|
|
1711
|
+
upperBoundTs: string;
|
|
1712
|
+
lowerBoundTs?: string;
|
|
1713
|
+
limit: number;
|
|
1714
|
+
account?: string;
|
|
1715
|
+
maxAttempts?: number;
|
|
1716
|
+
}): Promise<SlackUpperAdjacentWindowResult> {
|
|
1717
|
+
// Slack returns bounded conversations.replies pages earliest-first. To keep
|
|
1718
|
+
// the context closest to the inbound mention, narrow by timestamp instead
|
|
1719
|
+
// of cursoring forward from the oldest page in the bounded range.
|
|
1720
|
+
const upperMicros = slackTimestampToMicros(params.upperBoundTs);
|
|
1721
|
+
if (upperMicros === null) {
|
|
1722
|
+
const page = await backfillThreadWindowPage(
|
|
1723
|
+
params.channelId,
|
|
1724
|
+
params.threadTs,
|
|
1725
|
+
{
|
|
1726
|
+
limit: params.limit,
|
|
1727
|
+
account: params.account,
|
|
1728
|
+
before: params.upperBoundTs,
|
|
1729
|
+
...(params.lowerBoundTs !== undefined
|
|
1730
|
+
? { after: params.lowerBoundTs }
|
|
1731
|
+
: {}),
|
|
1732
|
+
},
|
|
1733
|
+
);
|
|
1734
|
+
return {
|
|
1735
|
+
messages: page.messages,
|
|
1736
|
+
omittedEarlierContent: slackPageHasMore(page),
|
|
1737
|
+
truncatedBeforeUpperBound: slackPageHasMore(page),
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
const lowerMicros = slackTimestampToMicros(params.lowerBoundTs);
|
|
1742
|
+
const maxAttempts =
|
|
1743
|
+
params.maxAttempts ?? SLACK_THREAD_UPPER_ADJACENT_MAX_ATTEMPTS;
|
|
1744
|
+
let attempts = 0;
|
|
1745
|
+
let safePage: SlackBackfillWindowPage | undefined;
|
|
1746
|
+
let safeAfterTs: string | undefined;
|
|
1747
|
+
let truncatedBeforeUpperBound = false;
|
|
1748
|
+
|
|
1749
|
+
const fetchWindow = async (
|
|
1750
|
+
windowMicros: bigint,
|
|
1751
|
+
): Promise<{
|
|
1752
|
+
page: SlackBackfillWindowPage;
|
|
1753
|
+
after?: string;
|
|
1754
|
+
reachedLowerBound: boolean;
|
|
1755
|
+
}> => {
|
|
1756
|
+
let candidateMicros = upperMicros - windowMicros;
|
|
1757
|
+
let reachedLowerBound = false;
|
|
1758
|
+
if (lowerMicros !== null && candidateMicros <= lowerMicros) {
|
|
1759
|
+
candidateMicros = lowerMicros;
|
|
1760
|
+
reachedLowerBound = true;
|
|
1761
|
+
}
|
|
1762
|
+
const after = reachedLowerBound
|
|
1763
|
+
? params.lowerBoundTs
|
|
1764
|
+
: slackTimestampFromMicros(candidateMicros);
|
|
1765
|
+
const page = await backfillThreadWindowPage(
|
|
1766
|
+
params.channelId,
|
|
1767
|
+
params.threadTs,
|
|
1768
|
+
{
|
|
1769
|
+
limit: params.limit,
|
|
1770
|
+
account: params.account,
|
|
1771
|
+
before: params.upperBoundTs,
|
|
1772
|
+
...(after !== undefined ? { after } : {}),
|
|
1773
|
+
},
|
|
1774
|
+
);
|
|
1775
|
+
attempts++;
|
|
1776
|
+
return { page, after, reachedLowerBound };
|
|
1777
|
+
};
|
|
1778
|
+
|
|
1779
|
+
const considerWindow = async (windowMicros: bigint): Promise<boolean> => {
|
|
1780
|
+
const { page, after, reachedLowerBound } = await fetchWindow(windowMicros);
|
|
1781
|
+
if (slackPageHasMore(page)) {
|
|
1782
|
+
truncatedBeforeUpperBound = true;
|
|
1783
|
+
return false;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
safePage = page;
|
|
1787
|
+
safeAfterTs = after;
|
|
1788
|
+
return page.messages.length < params.limit && !reachedLowerBound;
|
|
1789
|
+
};
|
|
1790
|
+
|
|
1791
|
+
for (const windowMicros of SLACK_UPPER_ADJACENT_EXPANDING_WINDOWS_MICROS) {
|
|
1792
|
+
if (attempts >= maxAttempts) break;
|
|
1793
|
+
const shouldExpand = await considerWindow(windowMicros);
|
|
1794
|
+
if (!shouldExpand) break;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
if (truncatedBeforeUpperBound && !safePage && attempts < maxAttempts) {
|
|
1798
|
+
for (const windowMicros of SLACK_UPPER_ADJACENT_SHRINKING_WINDOWS_MICROS) {
|
|
1799
|
+
if (attempts >= maxAttempts) break;
|
|
1800
|
+
await considerWindow(windowMicros);
|
|
1801
|
+
if (safePage) break;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
if (!safePage) {
|
|
1806
|
+
const after = slackTimestampFromMicros(upperMicros - 2n);
|
|
1807
|
+
const page = await backfillThreadWindowPage(
|
|
1808
|
+
params.channelId,
|
|
1809
|
+
params.threadTs,
|
|
1810
|
+
{
|
|
1811
|
+
limit: params.limit,
|
|
1812
|
+
account: params.account,
|
|
1813
|
+
before: params.upperBoundTs,
|
|
1814
|
+
...(after !== undefined ? { after } : {}),
|
|
1815
|
+
},
|
|
1816
|
+
);
|
|
1817
|
+
safePage = page;
|
|
1818
|
+
safeAfterTs = after;
|
|
1819
|
+
truncatedBeforeUpperBound =
|
|
1820
|
+
truncatedBeforeUpperBound || slackPageHasMore(page);
|
|
1821
|
+
}
|
|
1822
|
+
if (!safePage) {
|
|
1823
|
+
return {
|
|
1824
|
+
messages: [],
|
|
1825
|
+
omittedEarlierContent: true,
|
|
1826
|
+
truncatedBeforeUpperBound: true,
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
let omittedEarlierContent = truncatedBeforeUpperBound;
|
|
1831
|
+
if (
|
|
1832
|
+
!omittedEarlierContent &&
|
|
1833
|
+
params.lowerBoundTs !== undefined &&
|
|
1834
|
+
safeAfterTs !== undefined &&
|
|
1835
|
+
compareSlackTimestamps(params.lowerBoundTs, safeAfterTs) === -1
|
|
1836
|
+
) {
|
|
1837
|
+
const coverageProbe = await backfillThreadWindowPage(
|
|
1838
|
+
params.channelId,
|
|
1839
|
+
params.threadTs,
|
|
1840
|
+
{
|
|
1841
|
+
limit: 1,
|
|
1842
|
+
account: params.account,
|
|
1843
|
+
after: params.lowerBoundTs,
|
|
1844
|
+
before: safeAfterTs,
|
|
1845
|
+
},
|
|
1846
|
+
);
|
|
1847
|
+
omittedEarlierContent =
|
|
1848
|
+
coverageProbe.messages.length > 0 || slackPageHasMore(coverageProbe);
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
return {
|
|
1852
|
+
messages: safePage.messages,
|
|
1853
|
+
omittedEarlierContent,
|
|
1854
|
+
truncatedBeforeUpperBound,
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
async function fetchInitialSlackThreadWindows(params: {
|
|
1859
|
+
channelId: string;
|
|
1860
|
+
threadTs: string;
|
|
1861
|
+
upperBoundTs?: string;
|
|
1862
|
+
account?: string;
|
|
1863
|
+
}): Promise<SlackInitialThreadWindowsResult> {
|
|
1864
|
+
if (!params.upperBoundTs) {
|
|
1865
|
+
const early = await backfillThreadWindowPage(
|
|
1866
|
+
params.channelId,
|
|
1867
|
+
params.threadTs,
|
|
1868
|
+
{
|
|
1869
|
+
limit: SLACK_THREAD_INITIAL_EARLY_LIMIT,
|
|
1870
|
+
account: params.account,
|
|
1871
|
+
},
|
|
1872
|
+
);
|
|
1873
|
+
return {
|
|
1874
|
+
messages: sortSlackProviderMessages(
|
|
1875
|
+
dedupeSlackProviderMessages(early.messages),
|
|
1876
|
+
),
|
|
1877
|
+
omittedMiddle: slackPageHasMore(early),
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
const [early, recentResult] = await Promise.all([
|
|
1881
|
+
backfillThreadWindowPage(params.channelId, params.threadTs, {
|
|
1882
|
+
limit: SLACK_THREAD_INITIAL_EARLY_LIMIT,
|
|
1883
|
+
account: params.account,
|
|
1884
|
+
}),
|
|
1885
|
+
fetchSlackThreadUpperAdjacentWindow({
|
|
1886
|
+
channelId: params.channelId,
|
|
1887
|
+
threadTs: params.threadTs,
|
|
1888
|
+
account: params.account,
|
|
1889
|
+
upperBoundTs: params.upperBoundTs,
|
|
1890
|
+
limit: SLACK_THREAD_INITIAL_RECENT_LIMIT,
|
|
1891
|
+
maxAttempts: SLACK_THREAD_INITIAL_RECENT_MAX_PAGES,
|
|
1892
|
+
}),
|
|
1893
|
+
]);
|
|
1894
|
+
const recent: SlackBackfillWindowPage = {
|
|
1895
|
+
messages: recentResult.messages,
|
|
1896
|
+
hasMore: recentResult.truncatedBeforeUpperBound,
|
|
1897
|
+
};
|
|
1898
|
+
return {
|
|
1899
|
+
messages: sortSlackProviderMessages(
|
|
1900
|
+
dedupeSlackProviderMessages([...early.messages, ...recent.messages]),
|
|
1901
|
+
),
|
|
1902
|
+
omittedMiddle:
|
|
1903
|
+
recentResult.omittedEarlierContent ||
|
|
1904
|
+
didInitialWindowsLeaveGap({
|
|
1905
|
+
early,
|
|
1906
|
+
recent,
|
|
1907
|
+
recentScanTruncated: recentResult.truncatedBeforeUpperBound,
|
|
1908
|
+
}),
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
function dedupeSlackProviderMessages(
|
|
1913
|
+
messages: ProviderMessage[],
|
|
1914
|
+
): ProviderMessage[] {
|
|
1915
|
+
const byTs = new Map<string, ProviderMessage>();
|
|
1916
|
+
for (const message of messages) {
|
|
1917
|
+
if (!message.id || byTs.has(message.id)) continue;
|
|
1918
|
+
byTs.set(message.id, message);
|
|
1919
|
+
}
|
|
1920
|
+
return [...byTs.values()];
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
function sortSlackProviderMessages(
|
|
1924
|
+
messages: ProviderMessage[],
|
|
1925
|
+
): ProviderMessage[] {
|
|
1926
|
+
return [...messages].sort((left, right) => {
|
|
1927
|
+
const compared = compareSlackTimestamps(left.id, right.id);
|
|
1928
|
+
if (compared !== null) return compared;
|
|
1929
|
+
return left.id.localeCompare(right.id);
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
function buildSlackLateJoinNotice(
|
|
1934
|
+
result: SlackThreadBackfillResult,
|
|
1935
|
+
): string | null {
|
|
1936
|
+
if (result.reason !== "thread_late_join" || result.persisted === 0) {
|
|
1937
|
+
return null;
|
|
1938
|
+
}
|
|
1939
|
+
const omitted = result.omittedMiddle
|
|
1940
|
+
? " Some middle thread messages were intentionally omitted from this turn's hydrated context to keep latency bounded."
|
|
1941
|
+
: "";
|
|
1942
|
+
return `Slack context note: this turn joined an existing thread. ${result.persisted} earlier thread message${result.persisted === 1 ? " was" : "s were"} backfilled before the current message.${omitted}`;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1591
1945
|
/**
|
|
1592
|
-
* Lazily backfill
|
|
1946
|
+
* Lazily backfill Slack thread gaps for an inbound thread reply.
|
|
1593
1947
|
*
|
|
1594
|
-
* When a reply arrives for a thread
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
1599
|
-
* appears in the conversation.
|
|
1948
|
+
* When a reply arrives for a thread with unseen Slack history, the assistant
|
|
1949
|
+
* fetches bounded `conversations.replies` pages via
|
|
1950
|
+
* {@link backfillThreadWindowPage}, persists each unseen message as a
|
|
1951
|
+
* `messages` row with a `slackMeta` envelope, and skips duplicates whose `ts`
|
|
1952
|
+
* already appears in the conversation.
|
|
1600
1953
|
*
|
|
1601
1954
|
* Behavior contracts:
|
|
1602
|
-
* - **
|
|
1603
|
-
*
|
|
1604
|
-
*
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1955
|
+
* - **Thread-state gap detection.** Looks up stored Slack message rows for
|
|
1956
|
+
* the same thread, excluding reactions, then fetches only the unseen
|
|
1957
|
+
* `(latestStoredThreadTs, excludeChannelTs)` window when the inbound Slack
|
|
1958
|
+
* timestamp is newer than local state.
|
|
1959
|
+
* - **Upper-bound windows.** Initial late-join backfill combines an early
|
|
1960
|
+
* thread page with a recent page adjacent to the inbound ts; delta backfill
|
|
1961
|
+
* fetches the page nearest the inbound upper bound so the current turn sees
|
|
1962
|
+
* the most relevant context while keeping latency bounded.
|
|
1963
|
+
* - **Exact-window TTL cache.** A 10-minute in-memory cache prevents repeated
|
|
1964
|
+
* fetches for the same exact lower/upper bounded window, without
|
|
1965
|
+
* suppressing later unseen windows in the same thread.
|
|
1608
1966
|
* - **Failure-tolerant.** Any error (Slack API failure, DB error, malformed
|
|
1609
1967
|
* payload) is logged at `warn` and swallowed — the inbound turn must
|
|
1610
1968
|
* never block on backfill.
|
|
@@ -1619,65 +1977,106 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
|
|
|
1619
1977
|
* `conversations.replies` returns it in the thread window. Necessary
|
|
1620
1978
|
* because thread backfill runs concurrently with
|
|
1621
1979
|
* `processChannelMessageInBackground`, so the inbound row may not yet be
|
|
1622
|
-
* in the DB when
|
|
1980
|
+
* in the DB when the thread-state scan snapshots the conversation.
|
|
1623
1981
|
*/
|
|
1624
1982
|
excludeChannelTs?: string;
|
|
1625
1983
|
/**
|
|
1626
1984
|
* OAuth account identifier used to disambiguate which Slack workspace the
|
|
1627
1985
|
* backfill should read from in multi-account setups. Passed through to
|
|
1628
|
-
* `
|
|
1629
|
-
* resolver falls back to the default-active
|
|
1986
|
+
* `backfillThreadWindowPage` page requests and then `resolveConnection`.
|
|
1987
|
+
* Best-effort: if omitted, the resolver falls back to the default-active
|
|
1988
|
+
* connection.
|
|
1630
1989
|
*/
|
|
1631
1990
|
account?: string;
|
|
1632
|
-
}): Promise<
|
|
1991
|
+
}): Promise<SlackThreadBackfillResult> {
|
|
1633
1992
|
const { conversationId, channelId, threadTs, excludeChannelTs, account } =
|
|
1634
1993
|
params;
|
|
1635
|
-
const cacheKey = `${conversationId}:${threadTs}`;
|
|
1636
1994
|
|
|
1637
1995
|
try {
|
|
1638
|
-
|
|
1639
|
-
|
|
1996
|
+
const upperBoundTs = parseSlackTimestamp(excludeChannelTs)
|
|
1997
|
+
? excludeChannelTs
|
|
1998
|
+
: undefined;
|
|
1999
|
+
const threadState = readStoredSlackThreadState(conversationId, threadTs);
|
|
2000
|
+
const lowerBoundTs = threadState.latestStoredThreadTs;
|
|
2001
|
+
|
|
2002
|
+
// Pre-seed only after computing lowerBoundTs. The current inbound row
|
|
2003
|
+
// may not have reached the DB yet, and treating it as stored state would
|
|
2004
|
+
// hide the gap we need to fetch.
|
|
2005
|
+
if (excludeChannelTs) threadState.storedChannelTs.add(excludeChannelTs);
|
|
2006
|
+
|
|
2007
|
+
if (upperBoundTs && lowerBoundTs) {
|
|
2008
|
+
const lowerVsUpper = compareSlackTimestamps(lowerBoundTs, upperBoundTs);
|
|
2009
|
+
if (lowerVsUpper !== null && lowerVsUpper >= 0) {
|
|
2010
|
+
return emptySlackThreadBackfillResult();
|
|
2011
|
+
}
|
|
2012
|
+
} else if (!upperBoundTs && lowerBoundTs) {
|
|
2013
|
+
return emptySlackThreadBackfillResult();
|
|
1640
2014
|
}
|
|
1641
2015
|
|
|
1642
|
-
const
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
_backfillTriggerCache.set(cacheKey, Date.now());
|
|
1648
|
-
pruneBackfillCacheIfNeeded();
|
|
1649
|
-
return;
|
|
2016
|
+
const cacheKey = `${conversationId}:${threadTs}:${
|
|
2017
|
+
lowerBoundTs ?? "none"
|
|
2018
|
+
}:${upperBoundTs ?? "unbounded"}`;
|
|
2019
|
+
if (isBackfillRecentlyTriggered(cacheKey)) {
|
|
2020
|
+
return emptySlackThreadBackfillResult();
|
|
1650
2021
|
}
|
|
1651
2022
|
|
|
1652
2023
|
// Mark the trigger before issuing the network call. Doing this first
|
|
1653
|
-
// means a second concurrent
|
|
1654
|
-
// immediately even while the first call is still awaiting the Slack
|
|
1655
|
-
//
|
|
1656
|
-
//
|
|
1657
|
-
//
|
|
2024
|
+
// means a second concurrent request for the same window short-circuits
|
|
2025
|
+
// immediately even while the first call is still awaiting the Slack API.
|
|
2026
|
+
// The cost is a slightly larger window where a transient Slack failure
|
|
2027
|
+
// suppresses a retry, which the next reply outside the TTL (or a daemon
|
|
2028
|
+
// restart) will re-attempt anyway.
|
|
1658
2029
|
_backfillTriggerCache.set(cacheKey, Date.now());
|
|
1659
2030
|
pruneBackfillCacheIfNeeded();
|
|
1660
2031
|
|
|
1661
|
-
const
|
|
2032
|
+
const isInitialLateJoin =
|
|
2033
|
+
lowerBoundTs === undefined &&
|
|
2034
|
+
threadState.storedChannelTs.size === (excludeChannelTs ? 1 : 0);
|
|
2035
|
+
const reason: SlackBackfillReason = isInitialLateJoin
|
|
2036
|
+
? "thread_late_join"
|
|
2037
|
+
: "thread_delta";
|
|
2038
|
+
let omittedMiddle = false;
|
|
2039
|
+
let fetched: ProviderMessage[];
|
|
2040
|
+
if (isInitialLateJoin) {
|
|
2041
|
+
const initial = await fetchInitialSlackThreadWindows({
|
|
2042
|
+
channelId,
|
|
2043
|
+
threadTs,
|
|
2044
|
+
upperBoundTs,
|
|
2045
|
+
account,
|
|
2046
|
+
});
|
|
2047
|
+
fetched = initial.messages;
|
|
2048
|
+
omittedMiddle = initial.omittedMiddle;
|
|
2049
|
+
} else {
|
|
2050
|
+
const window = await fetchSlackThreadUpperAdjacentWindow({
|
|
2051
|
+
channelId,
|
|
2052
|
+
threadTs,
|
|
2053
|
+
limit: SLACK_THREAD_DELTA_LIMIT,
|
|
2054
|
+
account,
|
|
2055
|
+
...(lowerBoundTs !== undefined ? { lowerBoundTs } : {}),
|
|
2056
|
+
upperBoundTs: upperBoundTs ?? threadTs,
|
|
2057
|
+
});
|
|
2058
|
+
fetched = window.messages;
|
|
2059
|
+
omittedMiddle = window.omittedEarlierContent;
|
|
2060
|
+
}
|
|
1662
2061
|
if (fetched.length === 0) {
|
|
1663
2062
|
log.debug(
|
|
1664
2063
|
{ conversationId, channelId, threadTs },
|
|
1665
2064
|
"Slack thread backfill returned no messages",
|
|
1666
2065
|
);
|
|
1667
|
-
return;
|
|
2066
|
+
return emptySlackThreadBackfillResult();
|
|
1668
2067
|
}
|
|
1669
2068
|
|
|
1670
2069
|
let persisted = 0;
|
|
1671
2070
|
for (const message of fetched) {
|
|
1672
2071
|
if (!message.id) continue;
|
|
1673
|
-
if (storedChannelTs.has(message.id)) continue;
|
|
2072
|
+
if (threadState.storedChannelTs.has(message.id)) continue;
|
|
1674
2073
|
try {
|
|
1675
2074
|
await persistBackfilledSlackMessage({
|
|
1676
2075
|
conversationId,
|
|
1677
2076
|
channelId,
|
|
1678
2077
|
message,
|
|
1679
2078
|
});
|
|
1680
|
-
storedChannelTs.add(message.id);
|
|
2079
|
+
threadState.storedChannelTs.add(message.id);
|
|
1681
2080
|
persisted++;
|
|
1682
2081
|
} catch (err) {
|
|
1683
2082
|
log.warn(
|
|
@@ -1694,15 +2093,22 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
|
|
|
1694
2093
|
threadTs,
|
|
1695
2094
|
persisted,
|
|
1696
2095
|
fetched: fetched.length,
|
|
2096
|
+
omittedMiddle,
|
|
1697
2097
|
},
|
|
1698
|
-
"Slack thread backfill persisted
|
|
2098
|
+
"Slack thread backfill persisted thread messages",
|
|
1699
2099
|
);
|
|
2100
|
+
return {
|
|
2101
|
+
fetched: fetched.length,
|
|
2102
|
+
persisted,
|
|
2103
|
+
reason,
|
|
2104
|
+
omittedMiddle,
|
|
2105
|
+
};
|
|
1700
2106
|
} catch (err) {
|
|
1701
2107
|
// `channel_not_found` almost always means the resolved connection is
|
|
1702
2108
|
// pointing at the wrong Slack workspace (a real config bug), so log it
|
|
1703
2109
|
// at ERROR to match backfill's rethrow contract. Other failures
|
|
1704
2110
|
// (timeout, auth, ratelimited, …) stay at WARN — they're expected
|
|
1705
|
-
// transient blips and dispatch proceeds without the
|
|
2111
|
+
// transient blips and dispatch proceeds without the backfilled thread rows.
|
|
1706
2112
|
const channelNotFound =
|
|
1707
2113
|
err instanceof Error && /channel_not_found/i.test(err.message);
|
|
1708
2114
|
const payload = { err, conversationId, channelId, threadTs, account };
|
|
@@ -1714,5 +2120,6 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
|
|
|
1714
2120
|
} else {
|
|
1715
2121
|
log.warn(payload, "Slack thread backfill failed; proceeding without it");
|
|
1716
2122
|
}
|
|
2123
|
+
return emptySlackThreadBackfillResult();
|
|
1717
2124
|
}
|
|
1718
2125
|
}
|