@vellumai/assistant 0.6.2 → 0.6.4
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/ARCHITECTURE.md +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +41 -49
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +1111 -86
- package/package.json +40 -42
- package/scripts/generate-openapi.ts +0 -2
- package/scripts/test.sh +73 -18
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +240 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +1000 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +1248 -224
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +99 -3
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +290 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +12 -4
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +946 -62
- package/src/__tests__/conversation-routes-disk-view.test.ts +275 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +324 -46
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +6 -3
- package/src/__tests__/credential-vault-unit.test.ts +383 -7
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +42 -18
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +222 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +386 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +2 -0
- package/src/__tests__/gemini-provider.test.ts +66 -2
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +738 -359
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +528 -49
- package/src/__tests__/headless-browser-read-tools.test.ts +274 -100
- package/src/__tests__/headless-browser-snapshot.test.ts +250 -77
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +145 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +596 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +423 -0
- package/src/__tests__/host-cu-proxy.test.ts +166 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +67 -8
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +109 -7
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +18 -12
- package/src/__tests__/oauth-cli.test.ts +709 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +118 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +147 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +52 -14
- package/src/__tests__/oauth-store.test.ts +1465 -176
- package/src/__tests__/oauth2-gateway-transport.test.ts +460 -26
- package/src/__tests__/onboarding-template-contract.test.ts +81 -70
- package/src/__tests__/openai-provider.test.ts +178 -2
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +32 -3
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +343 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +8 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +801 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +738 -0
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +576 -16
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +184 -27
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +25 -5
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +55 -9
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +69 -3
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +3 -4
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +273 -16
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +56 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +32 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +330 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +117 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +215 -36
- package/src/cli/commands/oauth/shared.ts +7 -6
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +254 -0
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +141 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +5 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +54 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +9 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +38 -0
- package/src/config/env.ts +49 -4
- package/src/config/feature-flag-registry.json +85 -14
- package/src/config/loader.ts +82 -13
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +81 -15
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +112 -0
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +52 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -1
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +177 -0
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +61 -10
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +195 -0
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +23 -2
- package/src/daemon/conversation-agent-loop.ts +153 -42
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +622 -13
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +128 -36
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +131 -40
- package/src/daemon/conversation-tool-setup.ts +99 -8
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +292 -16
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -141
- package/src/daemon/handlers/shared.ts +80 -0
- package/src/daemon/handlers/skills.ts +483 -44
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +192 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +179 -28
- package/src/daemon/message-protocol.ts +13 -0
- package/src/daemon/message-types/conversations.ts +89 -14
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +19 -5
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +26 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +439 -14
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +30 -20
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/mcp/client.ts +59 -24
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +31 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +122 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +67 -40
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +137 -60
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/oauth.ts +21 -13
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +25 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +26 -9
- package/src/oauth/byo-connection.ts +10 -8
- package/src/oauth/connect-orchestrator.ts +25 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +22 -18
- package/src/oauth/connection.ts +3 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +223 -100
- package/src/oauth/platform-connection.test.ts +101 -3
- package/src/oauth/platform-connection.ts +56 -35
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +133 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +76 -38
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -60
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +10 -1
- package/src/runtime/AGENTS.md +65 -0
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +48 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +33 -9
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +368 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +815 -75
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +198 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +7 -0
- package/src/runtime/migrations/migration-wizard.ts +23 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +96 -1
- package/src/runtime/migrations/vbundle-importer.ts +89 -5
- package/src/runtime/pending-interactions.ts +18 -13
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +556 -0
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -141
- package/src/runtime/routes/conversation-management-routes.ts +223 -0
- package/src/runtime/routes/conversation-routes.ts +598 -103
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +268 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +262 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +122 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +31 -102
- package/src/runtime/routes/skills-routes.ts +128 -9
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +38 -9
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +57 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +68 -29
- package/src/security/secure-keys.ts +143 -27
- package/src/security/token-manager.ts +31 -10
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +554 -0
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +169 -40
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +1787 -342
- package/src/tools/browser/browser-manager.ts +81 -12
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +1263 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +359 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1993 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +1007 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +744 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +868 -0
- package/src/tools/browser/cdp-client/errors.ts +49 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +148 -0
- package/src/tools/browser/cdp-client/factory.ts +914 -0
- package/src/tools/browser/cdp-client/index.ts +28 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +120 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +15 -0
- package/src/tools/terminal/shell.ts +36 -20
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +19 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +63 -24
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +31 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/cli/commands/browser-relay.ts +0 -536
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guard test that verifies the Slack adapter routes reads and writes through
|
|
3
|
+
* the correct cached auth.
|
|
4
|
+
*
|
|
5
|
+
* Covers the bot-token-only case (reads and writes both use the bot token),
|
|
6
|
+
* the dual-token case (bot + user): reads MUST use the user token while
|
|
7
|
+
* content-creating writes (postMessage) MUST stay on the bot token so posts
|
|
8
|
+
* come from the bot identity, and the runtime fallback when a stored user
|
|
9
|
+
* token is rejected with an auth error.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
13
|
+
|
|
14
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
15
|
+
import { credentialKey } from "../../../../security/credential-key.js";
|
|
16
|
+
|
|
17
|
+
// ── Module mocks ────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
const getSecureKeyAsyncMock = mock(
|
|
20
|
+
async (_key: string): Promise<string | null> => null,
|
|
21
|
+
);
|
|
22
|
+
mock.module("../../../../security/secure-keys.js", () => ({
|
|
23
|
+
getSecureKeyAsync: getSecureKeyAsyncMock,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
// OAuth helpers are exercised only when no bot_token is cached. The adapter
|
|
27
|
+
// imports them at module load — route them through a stub that signals any
|
|
28
|
+
// OAuth fallback with a distinctive error so tests can assert on it.
|
|
29
|
+
const OAUTH_FALLBACK_SENTINEL = "OAUTH_FALLBACK_NOT_STUBBED";
|
|
30
|
+
mock.module("../../../../oauth/connection-resolver.js", () => ({
|
|
31
|
+
resolveOAuthConnection: async (): Promise<OAuthConnection> => {
|
|
32
|
+
throw new Error(OAUTH_FALLBACK_SENTINEL);
|
|
33
|
+
},
|
|
34
|
+
}));
|
|
35
|
+
mock.module("../../../../oauth/oauth-store.js", () => ({
|
|
36
|
+
isProviderConnected: async () => false,
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
// Stub contact DB access so the adapter doesn't touch SQLite during the test.
|
|
40
|
+
mock.module("../../../../contacts/contact-store.js", () => ({
|
|
41
|
+
findContactChannel: () => undefined,
|
|
42
|
+
}));
|
|
43
|
+
mock.module("../../../../contacts/contacts-write.js", () => ({
|
|
44
|
+
upsertContactChannel: () => {},
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
import { slackProvider } from "../adapter.js";
|
|
48
|
+
|
|
49
|
+
// ── fetch capture ───────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
type CapturedRequest = {
|
|
52
|
+
url: string;
|
|
53
|
+
method: string;
|
|
54
|
+
authorization: string | null;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const captured: CapturedRequest[] = [];
|
|
58
|
+
const originalFetch = globalThis.fetch;
|
|
59
|
+
|
|
60
|
+
function installFetchStub() {
|
|
61
|
+
globalThis.fetch = (async (
|
|
62
|
+
input: RequestInfo | URL,
|
|
63
|
+
init?: RequestInit,
|
|
64
|
+
): Promise<Response> => {
|
|
65
|
+
const url =
|
|
66
|
+
typeof input === "string"
|
|
67
|
+
? input
|
|
68
|
+
: input instanceof URL
|
|
69
|
+
? input.toString()
|
|
70
|
+
: input.url;
|
|
71
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
72
|
+
const headers = new Headers(init?.headers ?? {});
|
|
73
|
+
captured.push({
|
|
74
|
+
url,
|
|
75
|
+
method,
|
|
76
|
+
authorization: headers.get("authorization"),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Craft a minimal OK Slack API envelope per endpoint so the adapter's
|
|
80
|
+
// post-call mapping doesn't throw.
|
|
81
|
+
const body = fakeSlackResponse(url);
|
|
82
|
+
return new Response(JSON.stringify(body), {
|
|
83
|
+
status: 200,
|
|
84
|
+
headers: { "Content-Type": "application/json" },
|
|
85
|
+
});
|
|
86
|
+
}) as typeof fetch;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function fakeSlackResponse(url: string): Record<string, unknown> {
|
|
90
|
+
if (url.includes("/conversations.list")) {
|
|
91
|
+
return { ok: true, channels: [], response_metadata: { next_cursor: "" } };
|
|
92
|
+
}
|
|
93
|
+
if (url.includes("/conversations.history")) {
|
|
94
|
+
return { ok: true, messages: [], has_more: false };
|
|
95
|
+
}
|
|
96
|
+
if (url.includes("/conversations.mark")) {
|
|
97
|
+
return { ok: true };
|
|
98
|
+
}
|
|
99
|
+
if (url.includes("/chat.postMessage")) {
|
|
100
|
+
return { ok: true, ts: "1700000000.000100", channel: "C123" };
|
|
101
|
+
}
|
|
102
|
+
// Default envelope for any other method the adapter might call.
|
|
103
|
+
return { ok: true };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── Test setup ──────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
const BOT_TOKEN = "xoxb-BOT";
|
|
109
|
+
const USER_TOKEN = "xoxp-USER";
|
|
110
|
+
|
|
111
|
+
describe("Slack adapter token routing", () => {
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
captured.length = 0;
|
|
114
|
+
getSecureKeyAsyncMock.mockReset();
|
|
115
|
+
getSecureKeyAsyncMock.mockImplementation(async (key: string) => {
|
|
116
|
+
if (key === credentialKey("slack_channel", "bot_token")) return BOT_TOKEN;
|
|
117
|
+
return null;
|
|
118
|
+
});
|
|
119
|
+
installFetchStub();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
afterEach(() => {
|
|
123
|
+
globalThis.fetch = originalFetch;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("bot-token only: reads and writes both authenticate with the bot token (regression guard for pre-user-token behavior)", async () => {
|
|
127
|
+
// With only a bot token stored, reads must fall back to the bot token
|
|
128
|
+
// so the adapter keeps working for installs that haven't re-consented
|
|
129
|
+
// the user scope. Writes stay on the bot token always.
|
|
130
|
+
const resolved = await slackProvider.resolveConnection!();
|
|
131
|
+
expect(resolved).toBeUndefined();
|
|
132
|
+
|
|
133
|
+
// Read path: listConversations → /conversations.list must use bot token.
|
|
134
|
+
await slackProvider.listConversations(undefined);
|
|
135
|
+
const readCall = captured.find((c) =>
|
|
136
|
+
c.url.includes("/conversations.list"),
|
|
137
|
+
);
|
|
138
|
+
expect(readCall).toBeDefined();
|
|
139
|
+
expect(readCall!.authorization).toBe(`Bearer ${BOT_TOKEN}`);
|
|
140
|
+
|
|
141
|
+
// Write path: sendMessage → /chat.postMessage must also use bot token.
|
|
142
|
+
await slackProvider.sendMessage(undefined, "C123", "hello");
|
|
143
|
+
const writeCall = captured.find((c) => c.url.includes("/chat.postMessage"));
|
|
144
|
+
expect(writeCall).toBeDefined();
|
|
145
|
+
expect(writeCall!.authorization).toBe(`Bearer ${BOT_TOKEN}`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("bot + user tokens: reads authenticate with the user token, writes with the bot token", async () => {
|
|
149
|
+
// With both tokens stored, reads MUST flip to the user token so the
|
|
150
|
+
// adapter can see channels the user is in but the bot isn't. Writes
|
|
151
|
+
// MUST stay on the bot token so posts come from the bot identity.
|
|
152
|
+
getSecureKeyAsyncMock.mockImplementation(async (key: string) => {
|
|
153
|
+
if (key === credentialKey("slack_channel", "bot_token")) return BOT_TOKEN;
|
|
154
|
+
if (key === credentialKey("slack_channel", "user_token"))
|
|
155
|
+
return USER_TOKEN;
|
|
156
|
+
return null;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const resolved = await slackProvider.resolveConnection!();
|
|
160
|
+
expect(resolved).toBeUndefined();
|
|
161
|
+
|
|
162
|
+
// Reads: listConversations → user token.
|
|
163
|
+
await slackProvider.listConversations(undefined);
|
|
164
|
+
const listCall = captured.find((c) =>
|
|
165
|
+
c.url.includes("/conversations.list"),
|
|
166
|
+
);
|
|
167
|
+
expect(listCall).toBeDefined();
|
|
168
|
+
expect(listCall!.authorization).toBe(`Bearer ${USER_TOKEN}`);
|
|
169
|
+
|
|
170
|
+
// Reads: getHistory → user token.
|
|
171
|
+
await slackProvider.getHistory(undefined, "C123");
|
|
172
|
+
const historyCall = captured.find((c) =>
|
|
173
|
+
c.url.includes("/conversations.history"),
|
|
174
|
+
);
|
|
175
|
+
expect(historyCall).toBeDefined();
|
|
176
|
+
expect(historyCall!.authorization).toBe(`Bearer ${USER_TOKEN}`);
|
|
177
|
+
|
|
178
|
+
// Writes: sendMessage → bot token.
|
|
179
|
+
await slackProvider.sendMessage(undefined, "C123", "hello");
|
|
180
|
+
const sendCall = captured.find((c) => c.url.includes("/chat.postMessage"));
|
|
181
|
+
expect(sendCall).toBeDefined();
|
|
182
|
+
expect(sendCall!.authorization).toBe(`Bearer ${BOT_TOKEN}`);
|
|
183
|
+
|
|
184
|
+
// markRead → user token. conversations.mark sets the read cursor for
|
|
185
|
+
// the authenticated identity, so it must use the same token whose unread
|
|
186
|
+
// counts the adapter exposes.
|
|
187
|
+
await slackProvider.markRead!(undefined, "C123", "1700000000.000100");
|
|
188
|
+
const markCall = captured.find((c) =>
|
|
189
|
+
c.url.includes("/conversations.mark"),
|
|
190
|
+
);
|
|
191
|
+
expect(markCall).toBeDefined();
|
|
192
|
+
expect(markCall!.authorization).toBe(`Bearer ${USER_TOKEN}`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("user token rejected: read calls fall back to bot token and stay on it", async () => {
|
|
196
|
+
// If the cached user token is revoked/expired, the next read returns
|
|
197
|
+
// invalid_auth (HTTP 200 with ok:false). The adapter must retry the call
|
|
198
|
+
// with the bot token and reset the read cache so subsequent reads in the
|
|
199
|
+
// same session don't re-hit the failure path.
|
|
200
|
+
getSecureKeyAsyncMock.mockImplementation(async (key: string) => {
|
|
201
|
+
if (key === credentialKey("slack_channel", "bot_token")) return BOT_TOKEN;
|
|
202
|
+
if (key === credentialKey("slack_channel", "user_token"))
|
|
203
|
+
return USER_TOKEN;
|
|
204
|
+
return null;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Replace the default fetch stub: first user-token call to history fails
|
|
208
|
+
// with invalid_auth; everything else succeeds.
|
|
209
|
+
let userTokenHistoryCalls = 0;
|
|
210
|
+
globalThis.fetch = (async (
|
|
211
|
+
input: RequestInfo | URL,
|
|
212
|
+
init?: RequestInit,
|
|
213
|
+
): Promise<Response> => {
|
|
214
|
+
const url =
|
|
215
|
+
typeof input === "string"
|
|
216
|
+
? input
|
|
217
|
+
: input instanceof URL
|
|
218
|
+
? input.toString()
|
|
219
|
+
: input.url;
|
|
220
|
+
const headers = new Headers(init?.headers ?? {});
|
|
221
|
+
const auth = headers.get("authorization");
|
|
222
|
+
captured.push({
|
|
223
|
+
url,
|
|
224
|
+
method: (init?.method ?? "GET").toUpperCase(),
|
|
225
|
+
authorization: auth,
|
|
226
|
+
});
|
|
227
|
+
if (
|
|
228
|
+
url.includes("/conversations.history") &&
|
|
229
|
+
auth === `Bearer ${USER_TOKEN}`
|
|
230
|
+
) {
|
|
231
|
+
userTokenHistoryCalls += 1;
|
|
232
|
+
return new Response(
|
|
233
|
+
JSON.stringify({ ok: false, error: "invalid_auth" }),
|
|
234
|
+
{ status: 200, headers: { "Content-Type": "application/json" } },
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
return new Response(JSON.stringify(fakeSlackResponse(url)), {
|
|
238
|
+
status: 200,
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
});
|
|
241
|
+
}) as typeof fetch;
|
|
242
|
+
|
|
243
|
+
const resolved = await slackProvider.resolveConnection!();
|
|
244
|
+
expect(resolved).toBeUndefined();
|
|
245
|
+
|
|
246
|
+
// First read: tries user token, fails, retries with bot token.
|
|
247
|
+
await slackProvider.getHistory(undefined, "C123");
|
|
248
|
+
expect(userTokenHistoryCalls).toBe(1);
|
|
249
|
+
const historyCalls = captured.filter((c) =>
|
|
250
|
+
c.url.includes("/conversations.history"),
|
|
251
|
+
);
|
|
252
|
+
expect(historyCalls).toHaveLength(2);
|
|
253
|
+
expect(historyCalls[0].authorization).toBe(`Bearer ${USER_TOKEN}`);
|
|
254
|
+
expect(historyCalls[1].authorization).toBe(`Bearer ${BOT_TOKEN}`);
|
|
255
|
+
|
|
256
|
+
// Subsequent read: cache reset, only bot token is used (no retry needed).
|
|
257
|
+
captured.length = 0;
|
|
258
|
+
await slackProvider.getHistory(undefined, "C456");
|
|
259
|
+
const next = captured.filter((c) =>
|
|
260
|
+
c.url.includes("/conversations.history"),
|
|
261
|
+
);
|
|
262
|
+
expect(next).toHaveLength(1);
|
|
263
|
+
expect(next[0].authorization).toBe(`Bearer ${BOT_TOKEN}`);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("user-token only (no bot token): falls through to the OAuth path", async () => {
|
|
267
|
+
// Edge case: if only a user token is stored with no bot token, we do NOT
|
|
268
|
+
// have Socket Mode credentials, so resolveConnection() falls through to
|
|
269
|
+
// the legacy OAuth path. The mocked resolveOAuthConnection throws, which
|
|
270
|
+
// documents current behavior — user-token-only without an OAuth
|
|
271
|
+
// connection is not a supported install configuration.
|
|
272
|
+
getSecureKeyAsyncMock.mockImplementation(async (key: string) => {
|
|
273
|
+
if (key === credentialKey("slack_channel", "user_token"))
|
|
274
|
+
return USER_TOKEN;
|
|
275
|
+
return null;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
await expect(slackProvider.resolveConnection!()).rejects.toThrow(
|
|
279
|
+
OAUTH_FALLBACK_SENTINEL,
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
SendResult,
|
|
26
26
|
} from "../../provider-types.js";
|
|
27
27
|
import * as slack from "./client.js";
|
|
28
|
+
import { SlackApiError } from "./client.js";
|
|
28
29
|
import type {
|
|
29
30
|
SlackConversation,
|
|
30
31
|
SlackMessage,
|
|
@@ -35,27 +36,95 @@ import type {
|
|
|
35
36
|
const userNameCache = new Map<string, string>();
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
* Cached auth resolved during resolveConnection().
|
|
39
|
+
* Cached auth resolved during resolveConnection(), split by direction.
|
|
39
40
|
*
|
|
40
|
-
*
|
|
41
|
+
* Read and write auth are tracked separately so reads can use a user OAuth
|
|
42
|
+
* token (xoxp-) — giving visibility into channels the user is in but the
|
|
43
|
+
* bot isn't — while writes continue to use the bot token (xoxb-) so posts
|
|
44
|
+
* come from the bot identity. When no user_token is stored, reads fall
|
|
45
|
+
* back to the bot token. If a stored user_token is rejected at runtime
|
|
46
|
+
* (revoked/expired), the read cache is reset to the bot token for the rest
|
|
47
|
+
* of the session — see runReadWithFallback().
|
|
48
|
+
*
|
|
49
|
+
* For Socket Mode these hold a raw bot token string; for OAuth they hold the
|
|
41
50
|
* OAuthConnection. The Slack client functions accept both via their own
|
|
42
|
-
* OAuthConnection | string union, so we can pass
|
|
51
|
+
* OAuthConnection | string union, so we can pass the cached value through
|
|
52
|
+
* directly.
|
|
43
53
|
*/
|
|
44
|
-
let
|
|
54
|
+
let _cachedSlackWriteAuth: OAuthConnection | string | null = null;
|
|
55
|
+
let _cachedSlackReadAuth: OAuthConnection | string | null = null;
|
|
45
56
|
|
|
46
57
|
/**
|
|
47
58
|
* Get the Slack auth value to pass to Slack client functions.
|
|
48
59
|
* Prefers the explicit connection from the caller; falls back to the cached
|
|
49
|
-
*
|
|
60
|
+
* write auth. Callers that care about read vs write semantics should use
|
|
61
|
+
* getReadAuth() / getWriteAuth() directly.
|
|
50
62
|
*/
|
|
51
63
|
function getSlackAuth(connection?: OAuthConnection): OAuthConnection | string {
|
|
52
64
|
if (connection) return connection;
|
|
53
|
-
if (
|
|
65
|
+
if (_cachedSlackWriteAuth) return _cachedSlackWriteAuth;
|
|
66
|
+
if (_cachedSlackReadAuth) return _cachedSlackReadAuth;
|
|
54
67
|
throw new Error(
|
|
55
68
|
"Slack: no connection or cached token available. Was resolveConnection() called?",
|
|
56
69
|
);
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Resolve auth for read operations (listConversations, getHistory,
|
|
74
|
+
* conversation replies, search, users.info lookups).
|
|
75
|
+
*/
|
|
76
|
+
function getReadAuth(connection?: OAuthConnection): OAuthConnection | string {
|
|
77
|
+
if (connection) return connection;
|
|
78
|
+
if (_cachedSlackReadAuth) return _cachedSlackReadAuth;
|
|
79
|
+
return getSlackAuth(connection);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// SAFETY: content-creating writes (postMessage, updateMessage, deleteMessage,
|
|
83
|
+
// reactions) MUST use the bot token. Using the user token would post as the
|
|
84
|
+
// user, not as the bot. State-changing methods that target the authenticated
|
|
85
|
+
// identity's own state (e.g. conversations.mark) should use the read auth so
|
|
86
|
+
// the cursor matches the perspective the adapter exposes.
|
|
87
|
+
/**
|
|
88
|
+
* Resolve auth for content-creating write operations (postMessage and any
|
|
89
|
+
* future reactions, joins, leaves, updates, or deletes).
|
|
90
|
+
*/
|
|
91
|
+
function getWriteAuth(connection?: OAuthConnection): OAuthConnection | string {
|
|
92
|
+
if (connection) return connection;
|
|
93
|
+
if (_cachedSlackWriteAuth) return _cachedSlackWriteAuth;
|
|
94
|
+
return getSlackAuth(connection);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Run a read-path Slack call, falling back to the bot token if the cached
|
|
99
|
+
* user token is rejected with an auth error. On fallback, the read cache is
|
|
100
|
+
* reset to the bot token so subsequent reads in this session don't re-pay
|
|
101
|
+
* the round trip. Caller-supplied connections are passed through unchanged
|
|
102
|
+
* (no fallback) since the caller owns that auth.
|
|
103
|
+
*/
|
|
104
|
+
async function runReadWithFallback<T>(
|
|
105
|
+
connection: OAuthConnection | undefined,
|
|
106
|
+
call: (auth: OAuthConnection | string) => Promise<T>,
|
|
107
|
+
): Promise<T> {
|
|
108
|
+
if (connection) return call(connection);
|
|
109
|
+
const auth = getReadAuth(undefined);
|
|
110
|
+
const usingUserToken =
|
|
111
|
+
_cachedSlackWriteAuth !== null && _cachedSlackReadAuth !== _cachedSlackWriteAuth;
|
|
112
|
+
try {
|
|
113
|
+
return await call(auth);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (
|
|
116
|
+
usingUserToken &&
|
|
117
|
+
err instanceof SlackApiError &&
|
|
118
|
+
err.status === 401 &&
|
|
119
|
+
_cachedSlackWriteAuth
|
|
120
|
+
) {
|
|
121
|
+
_cachedSlackReadAuth = _cachedSlackWriteAuth;
|
|
122
|
+
return call(_cachedSlackWriteAuth);
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
59
128
|
async function resolveUserName(
|
|
60
129
|
auth: OAuthConnection | string,
|
|
61
130
|
userId: string,
|
|
@@ -165,7 +234,7 @@ export const slackProvider: MessagingProvider = {
|
|
|
165
234
|
id: "slack",
|
|
166
235
|
displayName: "Slack",
|
|
167
236
|
credentialService: "slack",
|
|
168
|
-
capabilities: new Set(["reactions", "threads", "leave_channel"]),
|
|
237
|
+
capabilities: new Set(["reactions", "threads", "join_channel", "leave_channel"]),
|
|
169
238
|
|
|
170
239
|
async isConnected(): Promise<boolean> {
|
|
171
240
|
// Socket Mode: check for bot token directly in credential store.
|
|
@@ -184,16 +253,26 @@ export const slackProvider: MessagingProvider = {
|
|
|
184
253
|
): Promise<OAuthConnection | undefined> {
|
|
185
254
|
// Socket Mode: cache the raw bot token for use in adapter methods.
|
|
186
255
|
// Token presence is sufficient — no connection row required.
|
|
256
|
+
//
|
|
257
|
+
// When a user_token is also stored, prefer it for reads so the adapter
|
|
258
|
+
// can see channels the user is in but the bot isn't (conversations.list,
|
|
259
|
+
// conversations.history, search.messages). Writes always stay on the
|
|
260
|
+
// bot token — see SAFETY note above getWriteAuth().
|
|
187
261
|
const botToken = await getSecureKeyAsync(
|
|
188
262
|
credentialKey("slack_channel", "bot_token"),
|
|
189
263
|
);
|
|
264
|
+
const userToken = await getSecureKeyAsync(
|
|
265
|
+
credentialKey("slack_channel", "user_token"),
|
|
266
|
+
);
|
|
190
267
|
if (botToken) {
|
|
191
|
-
|
|
268
|
+
_cachedSlackWriteAuth = botToken;
|
|
269
|
+
_cachedSlackReadAuth = userToken ?? botToken;
|
|
192
270
|
return undefined;
|
|
193
271
|
}
|
|
194
272
|
// Preserve existing OAuth path for backwards compat.
|
|
195
273
|
const conn = await resolveOAuthConnection("slack", { account });
|
|
196
|
-
|
|
274
|
+
_cachedSlackWriteAuth = conn;
|
|
275
|
+
_cachedSlackReadAuth = conn;
|
|
197
276
|
return conn;
|
|
198
277
|
},
|
|
199
278
|
|
|
@@ -212,7 +291,6 @@ export const slackProvider: MessagingProvider = {
|
|
|
212
291
|
connection: OAuthConnection | undefined,
|
|
213
292
|
options?: ListOptions,
|
|
214
293
|
): Promise<Conversation[]> {
|
|
215
|
-
const auth = getSlackAuth(connection);
|
|
216
294
|
const typeMap: Record<string, string> = {
|
|
217
295
|
channel: "public_channel,private_channel",
|
|
218
296
|
dm: "im",
|
|
@@ -228,16 +306,32 @@ export const slackProvider: MessagingProvider = {
|
|
|
228
306
|
|
|
229
307
|
const conversations: Conversation[] = [];
|
|
230
308
|
let cursor: string | undefined = options?.cursor;
|
|
309
|
+
let auth = getReadAuth(connection);
|
|
231
310
|
|
|
232
|
-
// Paginate through all results
|
|
311
|
+
// Paginate through all results. The first page is wrapped in
|
|
312
|
+
// runReadWithFallback so that a 401 on the user token retries with the
|
|
313
|
+
// bot token before we commit to the rest of the pagination.
|
|
314
|
+
let firstPage = true;
|
|
233
315
|
do {
|
|
234
|
-
const resp =
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
316
|
+
const resp = firstPage
|
|
317
|
+
? await runReadWithFallback(connection, async (a) => {
|
|
318
|
+
auth = a;
|
|
319
|
+
return slack.listConversations(
|
|
320
|
+
a,
|
|
321
|
+
types,
|
|
322
|
+
options?.excludeArchived ?? true,
|
|
323
|
+
options?.limit ?? 200,
|
|
324
|
+
cursor,
|
|
325
|
+
);
|
|
326
|
+
})
|
|
327
|
+
: await slack.listConversations(
|
|
328
|
+
auth,
|
|
329
|
+
types,
|
|
330
|
+
options?.excludeArchived ?? true,
|
|
331
|
+
options?.limit ?? 200,
|
|
332
|
+
cursor,
|
|
333
|
+
);
|
|
334
|
+
firstPage = false;
|
|
241
335
|
conversations.push(...resp.channels.map(mapConversation));
|
|
242
336
|
cursor = resp.response_metadata?.next_cursor || undefined;
|
|
243
337
|
} while (
|
|
@@ -280,14 +374,17 @@ export const slackProvider: MessagingProvider = {
|
|
|
280
374
|
conversationId: string,
|
|
281
375
|
options?: HistoryOptions,
|
|
282
376
|
): Promise<Message[]> {
|
|
283
|
-
|
|
284
|
-
const resp = await
|
|
285
|
-
auth
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
377
|
+
let auth: OAuthConnection | string = getReadAuth(connection);
|
|
378
|
+
const resp = await runReadWithFallback(connection, async (a) => {
|
|
379
|
+
auth = a;
|
|
380
|
+
return slack.conversationHistory(
|
|
381
|
+
a,
|
|
382
|
+
conversationId,
|
|
383
|
+
options?.limit ?? 50,
|
|
384
|
+
options?.before,
|
|
385
|
+
options?.after,
|
|
386
|
+
);
|
|
387
|
+
});
|
|
291
388
|
|
|
292
389
|
const messages: Message[] = [];
|
|
293
390
|
for (const msg of resp.messages) {
|
|
@@ -303,8 +400,9 @@ export const slackProvider: MessagingProvider = {
|
|
|
303
400
|
query: string,
|
|
304
401
|
options?: SearchOptions,
|
|
305
402
|
): Promise<SearchResult> {
|
|
306
|
-
const
|
|
307
|
-
|
|
403
|
+
const resp = await runReadWithFallback(connection, (auth) =>
|
|
404
|
+
slack.searchMessages(auth, query, options?.count ?? 20),
|
|
405
|
+
);
|
|
308
406
|
return {
|
|
309
407
|
total: resp.messages.total,
|
|
310
408
|
messages: resp.messages.matches.map(mapSearchMatch),
|
|
@@ -318,7 +416,7 @@ export const slackProvider: MessagingProvider = {
|
|
|
318
416
|
text: string,
|
|
319
417
|
options?: SendOptions,
|
|
320
418
|
): Promise<SendResult> {
|
|
321
|
-
const auth =
|
|
419
|
+
const auth = getWriteAuth(connection);
|
|
322
420
|
const resp = await slack.postMessage(
|
|
323
421
|
auth,
|
|
324
422
|
conversationId,
|
|
@@ -338,13 +436,16 @@ export const slackProvider: MessagingProvider = {
|
|
|
338
436
|
threadId: string,
|
|
339
437
|
options?: HistoryOptions,
|
|
340
438
|
): Promise<Message[]> {
|
|
341
|
-
|
|
342
|
-
const resp = await
|
|
343
|
-
auth
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
439
|
+
let auth: OAuthConnection | string = getReadAuth(connection);
|
|
440
|
+
const resp = await runReadWithFallback(connection, async (a) => {
|
|
441
|
+
auth = a;
|
|
442
|
+
return slack.conversationReplies(
|
|
443
|
+
a,
|
|
444
|
+
conversationId,
|
|
445
|
+
threadId,
|
|
446
|
+
options?.limit ?? 50,
|
|
447
|
+
);
|
|
448
|
+
});
|
|
348
449
|
const messages: Message[] = [];
|
|
349
450
|
for (const msg of resp.messages) {
|
|
350
451
|
const name = await resolveUserName(auth, msg.user ?? "");
|
|
@@ -358,9 +459,13 @@ export const slackProvider: MessagingProvider = {
|
|
|
358
459
|
conversationId: string,
|
|
359
460
|
messageId?: string,
|
|
360
461
|
): Promise<void> {
|
|
361
|
-
|
|
462
|
+
// conversations.mark sets the read cursor for the authenticated identity.
|
|
463
|
+
// It must use the same token as the read path so the cursor matches the
|
|
464
|
+
// perspective the adapter exposes (unread counts in listConversations).
|
|
362
465
|
// Slack's conversations.mark requires a timestamp — use the provided one or "now"
|
|
363
466
|
const ts = messageId ?? String(Date.now() / 1000);
|
|
364
|
-
await
|
|
467
|
+
await runReadWithFallback(connection, (auth) =>
|
|
468
|
+
slack.conversationMark(auth, conversationId, ts),
|
|
469
|
+
);
|
|
365
470
|
},
|
|
366
471
|
};
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
SlackChatUpdateResponse,
|
|
19
19
|
SlackConversationHistoryResponse,
|
|
20
20
|
SlackConversationInfoResponse,
|
|
21
|
+
SlackConversationJoinResponse,
|
|
21
22
|
SlackConversationLeaveResponse,
|
|
22
23
|
SlackConversationMarkResponse,
|
|
23
24
|
SlackConversationRepliesResponse,
|
|
@@ -517,6 +518,20 @@ export async function deleteMessage(
|
|
|
517
518
|
);
|
|
518
519
|
}
|
|
519
520
|
|
|
521
|
+
export async function joinConversation(
|
|
522
|
+
connectionOrToken: OAuthConnection | string,
|
|
523
|
+
channel: string,
|
|
524
|
+
): Promise<SlackConversationJoinResponse> {
|
|
525
|
+
return request<SlackConversationJoinResponse>(
|
|
526
|
+
connectionOrToken,
|
|
527
|
+
"conversations.join",
|
|
528
|
+
undefined,
|
|
529
|
+
{
|
|
530
|
+
channel,
|
|
531
|
+
},
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
520
535
|
export async function leaveConversation(
|
|
521
536
|
connectionOrToken: OAuthConnection | string,
|
|
522
537
|
channel: string,
|
|
@@ -530,3 +545,4 @@ export async function leaveConversation(
|
|
|
530
545
|
},
|
|
531
546
|
);
|
|
532
547
|
}
|
|
548
|
+
|
|
@@ -119,6 +119,10 @@ export interface SlackConversationsOpenResponse extends SlackApiResponse {
|
|
|
119
119
|
|
|
120
120
|
export type SlackReactionAddResponse = SlackApiResponse;
|
|
121
121
|
|
|
122
|
+
export type SlackConversationJoinResponse = SlackApiResponse & {
|
|
123
|
+
channel?: SlackConversation;
|
|
124
|
+
};
|
|
125
|
+
|
|
122
126
|
export type SlackConversationLeaveResponse = SlackApiResponse;
|
|
123
127
|
|
|
124
128
|
export interface SlackChatDeleteResponse extends SlackApiResponse {
|
|
@@ -61,9 +61,9 @@ const PROMPT_VERSION = "v4";
|
|
|
61
61
|
/**
|
|
62
62
|
* Maximum character budget for identity context injected into the notification
|
|
63
63
|
* decision prompt. We truncate to prevent oversized prompts when SOUL.md /
|
|
64
|
-
* IDENTITY.md /
|
|
65
|
-
* would cause the LLM call to fail and silently degrade to
|
|
66
|
-
* fallback for all notifications.
|
|
64
|
+
* IDENTITY.md / users/<slug>.md are large — exceeding the provider context
|
|
65
|
+
* window would cause the LLM call to fail and silently degrade to
|
|
66
|
+
* deterministic fallback for all notifications.
|
|
67
67
|
*/
|
|
68
68
|
const MAX_IDENTITY_CONTEXT_CHARS = 2000;
|
|
69
69
|
|
|
@@ -97,6 +97,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
|
97
97
|
id: "voice.response_ready",
|
|
98
98
|
description: "Voice response ready for playback",
|
|
99
99
|
},
|
|
100
|
+
{
|
|
101
|
+
id: "credential.health_alert",
|
|
102
|
+
description:
|
|
103
|
+
"OAuth credential health issue detected (expired, revoked, missing scopes)",
|
|
104
|
+
},
|
|
100
105
|
] as const;
|
|
101
106
|
|
|
102
107
|
export type NotificationSourceEventName =
|