@vellumai/assistant 0.6.3 → 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 +5 -13
- 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/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- 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__/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 +11 -0
- 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 +138 -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-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- 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 +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- 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 +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- 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-tool-setup-batch-authorized.test.ts +226 -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-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- 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__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- 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__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- 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 +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- 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__/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-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- 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__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- 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-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -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__/search-skills-unified.test.ts +118 -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 +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- 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 +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- 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 +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- 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__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- 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__/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/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- 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/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/types.ts +16 -0
- 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 +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- 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/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/references/CUSTOM_ROUTES.md +37 -1
- 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 +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- 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 +2 -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/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 +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- 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 +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -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 -0
- 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 +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- 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 +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- 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 +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- 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 +12 -3
- 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/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 +1 -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 +99 -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/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.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 +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- 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 +92 -56
- 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 +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- 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/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- 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 +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- 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 -61
- 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 +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -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/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- 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 +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- 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/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 +82 -23
- 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 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- 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 +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- 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/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- 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 +30 -2
- 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/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 +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- 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 +38 -14
- 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/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- 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__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- 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/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -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 +54 -10
- 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 +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- 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/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* sidecar and credential data.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
21
|
+
|
|
20
22
|
import type {
|
|
21
23
|
SecureKeyBackend,
|
|
22
24
|
SecureKeyDeleteResult,
|
|
@@ -75,6 +77,18 @@ let _lastReconnectAttempt = 0;
|
|
|
75
77
|
/** In-flight reconnection promise — concurrent callers share the same attempt. */
|
|
76
78
|
let _reconnectInFlight: Promise<boolean> | undefined;
|
|
77
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Per-async-context flag set while we are running the user-registered
|
|
82
|
+
* `_cesReconnect` callback. Reentrant credential reads from within the
|
|
83
|
+
* callback (on the same async call chain) must not `await`
|
|
84
|
+
* `_reconnectInFlight` — that would await the caller's own reconnect and
|
|
85
|
+
* deadlock until `CREDENTIAL_OP_TIMEOUT_MS` (45s) fires. Using
|
|
86
|
+
* AsyncLocalStorage (rather than a module-level boolean) scopes the guard
|
|
87
|
+
* to the actual reentrant stack, so unrelated concurrent callers keep
|
|
88
|
+
* sharing the in-flight reconnect promise normally.
|
|
89
|
+
*/
|
|
90
|
+
const _reconnectContext = new AsyncLocalStorage<true>();
|
|
91
|
+
|
|
78
92
|
/**
|
|
79
93
|
* Set to true when a ces-http operation returns an unreachable result.
|
|
80
94
|
* Triggers CES RPC reconnection on the next resolveBackendAsync() call so
|
|
@@ -240,6 +254,15 @@ function tryFailoverToCesHttpBackend(
|
|
|
240
254
|
async function attemptCesReconnection(): Promise<boolean> {
|
|
241
255
|
if (!_cesReconnect) return false;
|
|
242
256
|
|
|
257
|
+
// Reentrancy guard. A nested credential read from inside the reconnect
|
|
258
|
+
// callback must not `await` our own in-flight promise — that would
|
|
259
|
+
// deadlock on the 45-second credential-op timeout. Report the reconnect
|
|
260
|
+
// as failed so the caller sees "unreachable" and falls back (env vars,
|
|
261
|
+
// dead-backend response) without blocking. Concurrent callers on other
|
|
262
|
+
// async chains don't see the ALS store, so they still share the
|
|
263
|
+
// in-flight promise normally.
|
|
264
|
+
if (_reconnectContext.getStore()) return false;
|
|
265
|
+
|
|
243
266
|
// If a reconnection is already in flight, share it.
|
|
244
267
|
if (_reconnectInFlight) return _reconnectInFlight;
|
|
245
268
|
|
|
@@ -249,7 +272,7 @@ async function attemptCesReconnection(): Promise<boolean> {
|
|
|
249
272
|
_lastReconnectAttempt = Date.now();
|
|
250
273
|
log.warn("Credential backend unavailable — attempting CES reconnection");
|
|
251
274
|
|
|
252
|
-
_reconnectInFlight = (async () => {
|
|
275
|
+
_reconnectInFlight = _reconnectContext.run(true, async () => {
|
|
253
276
|
try {
|
|
254
277
|
const newClient = await _cesReconnect!();
|
|
255
278
|
if (newClient) {
|
|
@@ -262,7 +285,7 @@ async function attemptCesReconnection(): Promise<boolean> {
|
|
|
262
285
|
log.warn({ err }, "CES reconnection failed");
|
|
263
286
|
}
|
|
264
287
|
return false;
|
|
265
|
-
})
|
|
288
|
+
});
|
|
266
289
|
|
|
267
290
|
try {
|
|
268
291
|
return await _reconnectInFlight;
|
|
@@ -101,6 +101,7 @@ interface RefreshConfig {
|
|
|
101
101
|
secret?: string;
|
|
102
102
|
refreshToken?: string;
|
|
103
103
|
authMethod?: TokenEndpointAuthMethod;
|
|
104
|
+
tokenExchangeBodyFormat?: "form" | "json";
|
|
104
105
|
connId: string;
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -166,6 +167,10 @@ async function resolveRefreshConfig(
|
|
|
166
167
|
| TokenEndpointAuthMethod
|
|
167
168
|
| undefined;
|
|
168
169
|
|
|
170
|
+
const tokenExchangeBodyFormat =
|
|
171
|
+
(provider.tokenExchangeBodyFormat as "form" | "json" | undefined) ??
|
|
172
|
+
undefined;
|
|
173
|
+
|
|
169
174
|
return {
|
|
170
175
|
connId: conn.id,
|
|
171
176
|
tokenExchangeUrl,
|
|
@@ -173,6 +178,7 @@ async function resolveRefreshConfig(
|
|
|
173
178
|
secret,
|
|
174
179
|
refreshToken,
|
|
175
180
|
authMethod,
|
|
181
|
+
tokenExchangeBodyFormat,
|
|
176
182
|
};
|
|
177
183
|
}
|
|
178
184
|
|
|
@@ -192,6 +198,7 @@ async function doRefresh(service: string, connId: string): Promise<string> {
|
|
|
192
198
|
clientId: resolvedClientId,
|
|
193
199
|
secret,
|
|
194
200
|
authMethod,
|
|
201
|
+
tokenExchangeBodyFormat,
|
|
195
202
|
refreshToken,
|
|
196
203
|
} = refreshConfig;
|
|
197
204
|
|
|
@@ -222,6 +229,7 @@ async function doRefresh(service: string, connId: string): Promise<string> {
|
|
|
222
229
|
refreshToken,
|
|
223
230
|
secret,
|
|
224
231
|
authMethod,
|
|
232
|
+
tokenExchangeBodyFormat,
|
|
225
233
|
);
|
|
226
234
|
} catch (err) {
|
|
227
235
|
circuitBreaker.recordFailure(connId);
|
package/src/sequence/engine.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* sends through the messaging layer.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { emitFeedEvent } from "../home/emit-feed-event.js";
|
|
9
10
|
import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
|
|
10
11
|
import { getMessages } from "../memory/conversation-crud.js";
|
|
11
12
|
import type { ScheduleMessageProcessor } from "../schedule/scheduler.js";
|
|
@@ -200,6 +201,28 @@ async function processEnrollment(
|
|
|
200
201
|
recordSend(sequence.id);
|
|
201
202
|
recordEvent(sequence.id, enrollment.id, "send", step.index);
|
|
202
203
|
|
|
204
|
+
// Fire-and-forget home-feed activity log entry. Each (enrollment,
|
|
205
|
+
// step) pair is a distinct real signal (an email actually went
|
|
206
|
+
// out), so the dedupKey embeds both — repeat emits for the same
|
|
207
|
+
// step are impossible because the enrollment advances after this
|
|
208
|
+
// line, but if they did occur they'd land on the same entry.
|
|
209
|
+
void emitFeedEvent({
|
|
210
|
+
source: "assistant",
|
|
211
|
+
title: sequence.name,
|
|
212
|
+
summary: `Sent step ${step.index + 1} of ${sequence.steps.length} to ${enrollment.contactEmail}.`,
|
|
213
|
+
dedupKey: `sequence-step:${enrollment.id}:${step.index}`,
|
|
214
|
+
}).catch((err) => {
|
|
215
|
+
log.warn(
|
|
216
|
+
{
|
|
217
|
+
err,
|
|
218
|
+
sequenceId: sequence.id,
|
|
219
|
+
enrollmentId: enrollment.id,
|
|
220
|
+
step: step.index,
|
|
221
|
+
},
|
|
222
|
+
"Failed to emit sequence step feed event",
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
203
226
|
// Advance to the next step
|
|
204
227
|
const nextStepIndex = enrollment.currentStep + 1;
|
|
205
228
|
if (nextStepIndex >= sequence.steps.length) {
|
package/src/sequence/types.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface Sequence {
|
|
|
26
26
|
id: string;
|
|
27
27
|
name: string;
|
|
28
28
|
description: string | null;
|
|
29
|
-
channel: string; // messaging channel (gmail,
|
|
29
|
+
channel: string; // messaging channel (gmail, email, slack)
|
|
30
30
|
steps: SequenceStep[];
|
|
31
31
|
exitOnReply: boolean;
|
|
32
32
|
status: SequenceStatus;
|
|
@@ -29,14 +29,16 @@ import {
|
|
|
29
29
|
import { basename, join, posix, sep } from "node:path";
|
|
30
30
|
|
|
31
31
|
import { getPlatformBaseUrl } from "../config/env.js";
|
|
32
|
+
import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
|
|
32
33
|
import {
|
|
33
34
|
isTextMimeType as isTextMime,
|
|
34
35
|
MAX_INLINE_TEXT_SIZE,
|
|
35
36
|
} from "../runtime/routes/workspace-utils.js";
|
|
36
37
|
import { getLogger } from "../util/logger.js";
|
|
37
38
|
import { readPlatformToken } from "../util/platform.js";
|
|
38
|
-
import { getCatalog } from "./catalog-cache.js";
|
|
39
|
-
import { getRepoSkillsDir } from "./catalog-install.js";
|
|
39
|
+
import { getCachedCatalogSync, getCatalog } from "./catalog-cache.js";
|
|
40
|
+
import { type CatalogSkill, getRepoSkillsDir } from "./catalog-install.js";
|
|
41
|
+
import type { SkillFileProvider } from "./skill-file-provider.js";
|
|
40
42
|
|
|
41
43
|
const log = getLogger("catalog-files");
|
|
42
44
|
|
|
@@ -490,3 +492,63 @@ export async function readCatalogSkillFileContent(
|
|
|
490
492
|
content: response.content,
|
|
491
493
|
};
|
|
492
494
|
}
|
|
495
|
+
|
|
496
|
+
// ─── Catalog-to-slim conversion ──────────────────────────────────────────────
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Map a `CatalogSkill` (from the Vellum platform API) to a `SlimSkillResponse`
|
|
500
|
+
* shaped for the "available catalog skill" case. Shared between
|
|
501
|
+
* `listSkillsWithCatalog` (merging catalog entries into the installed list),
|
|
502
|
+
* `getSkillFiles` (catalog fallback for preview listings), and the
|
|
503
|
+
* `VellumCatalogProvider`. Keeping the mapping in one place avoids divergence
|
|
504
|
+
* between the list and detail paths.
|
|
505
|
+
*
|
|
506
|
+
* Extracted here (rather than in `daemon/handlers/skills.ts`) to avoid a
|
|
507
|
+
* circular import — catalog-files depends on `catalog-cache.ts`, which would
|
|
508
|
+
* otherwise be reachable via the handler module.
|
|
509
|
+
*/
|
|
510
|
+
export function catalogSkillToSlim(cs: CatalogSkill): SlimSkillResponse {
|
|
511
|
+
return {
|
|
512
|
+
id: cs.id,
|
|
513
|
+
name: cs.metadata?.vellum?.["display-name"] ?? cs.name,
|
|
514
|
+
description: cs.description,
|
|
515
|
+
emoji: cs.emoji,
|
|
516
|
+
kind: "catalog",
|
|
517
|
+
origin: "vellum",
|
|
518
|
+
status: "available",
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ─── Vellum Catalog Provider ─────────────────────────────────────────────────
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Create a `SkillFileProvider` that wraps the existing catalog-files functions
|
|
526
|
+
* for the Vellum first-party catalog. This is the first provider implementation
|
|
527
|
+
* in the unified file-preview chain.
|
|
528
|
+
*/
|
|
529
|
+
export function createVellumCatalogProvider(): SkillFileProvider {
|
|
530
|
+
return {
|
|
531
|
+
canHandle(skillId: string): boolean {
|
|
532
|
+
const cached = getCachedCatalogSync();
|
|
533
|
+
return cached.some((s) => s.id === skillId);
|
|
534
|
+
},
|
|
535
|
+
|
|
536
|
+
listFiles(skillId: string): Promise<SkillFileEntry[] | null> {
|
|
537
|
+
return readCatalogSkillFiles(skillId);
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
readFileContent(
|
|
541
|
+
skillId: string,
|
|
542
|
+
sanitizedPath: string,
|
|
543
|
+
): Promise<SkillFileEntry | null> {
|
|
544
|
+
return readCatalogSkillFileContent(skillId, sanitizedPath);
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
async toSlimSkill(skillId: string): Promise<SlimSkillResponse | null> {
|
|
548
|
+
const catalog = await getCatalog();
|
|
549
|
+
const cs = catalog.find((s) => s.id === skillId);
|
|
550
|
+
if (!cs) return null;
|
|
551
|
+
return catalogSkillToSlim(cs);
|
|
552
|
+
},
|
|
553
|
+
};
|
|
554
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill category inference — ports the Swift `inferCategory` logic from
|
|
3
|
+
* `ConstellationView.swift` to TypeScript for server-side use.
|
|
4
|
+
*
|
|
5
|
+
* Pure function with no side effects or external dependencies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type SkillCategory =
|
|
9
|
+
| "communication"
|
|
10
|
+
| "productivity"
|
|
11
|
+
| "development"
|
|
12
|
+
| "media"
|
|
13
|
+
| "automation"
|
|
14
|
+
| "webSocial"
|
|
15
|
+
| "knowledge"
|
|
16
|
+
| "integration";
|
|
17
|
+
|
|
18
|
+
export const SKILL_CATEGORIES: SkillCategory[] = [
|
|
19
|
+
"communication",
|
|
20
|
+
"productivity",
|
|
21
|
+
"development",
|
|
22
|
+
"automation",
|
|
23
|
+
"media",
|
|
24
|
+
"webSocial",
|
|
25
|
+
"knowledge",
|
|
26
|
+
"integration",
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const CATEGORY_KEYWORDS: [SkillCategory, string[]][] = [
|
|
30
|
+
[
|
|
31
|
+
"communication",
|
|
32
|
+
[
|
|
33
|
+
"email",
|
|
34
|
+
"message",
|
|
35
|
+
"messaging",
|
|
36
|
+
"chat",
|
|
37
|
+
"phone",
|
|
38
|
+
"phone call",
|
|
39
|
+
"voice call",
|
|
40
|
+
"video call",
|
|
41
|
+
"contact",
|
|
42
|
+
"notification",
|
|
43
|
+
"followup",
|
|
44
|
+
"slack",
|
|
45
|
+
"telegram",
|
|
46
|
+
],
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
"productivity",
|
|
50
|
+
[
|
|
51
|
+
"task",
|
|
52
|
+
"calendar",
|
|
53
|
+
"reminder",
|
|
54
|
+
"schedule",
|
|
55
|
+
"document",
|
|
56
|
+
"playbook",
|
|
57
|
+
"notion",
|
|
58
|
+
],
|
|
59
|
+
],
|
|
60
|
+
[
|
|
61
|
+
"development",
|
|
62
|
+
[
|
|
63
|
+
"code",
|
|
64
|
+
"app builder",
|
|
65
|
+
"github",
|
|
66
|
+
"developer",
|
|
67
|
+
"programming",
|
|
68
|
+
"debug",
|
|
69
|
+
"typescript",
|
|
70
|
+
"frontend",
|
|
71
|
+
"subagent",
|
|
72
|
+
"api mapping",
|
|
73
|
+
"cli discovery",
|
|
74
|
+
],
|
|
75
|
+
],
|
|
76
|
+
["automation", ["browser", "computer use", "macos", "watcher", "automat"]],
|
|
77
|
+
[
|
|
78
|
+
"media",
|
|
79
|
+
["image", "screen", "media", "transcri", "video", "audio", "recording"],
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"webSocial",
|
|
83
|
+
[
|
|
84
|
+
"x.com",
|
|
85
|
+
"twitter",
|
|
86
|
+
"public ingress",
|
|
87
|
+
"influencer",
|
|
88
|
+
"doordash",
|
|
89
|
+
"amazon",
|
|
90
|
+
"restaurant",
|
|
91
|
+
],
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
"knowledge",
|
|
95
|
+
[
|
|
96
|
+
"knowledge",
|
|
97
|
+
"weather",
|
|
98
|
+
"start the day",
|
|
99
|
+
"skills catalog",
|
|
100
|
+
"self upgrade",
|
|
101
|
+
"briefing",
|
|
102
|
+
],
|
|
103
|
+
],
|
|
104
|
+
["integration", ["oauth", "setup", "configure", "connect", "webhook"]],
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
export function inferCategory(
|
|
108
|
+
name: string,
|
|
109
|
+
description: string,
|
|
110
|
+
): SkillCategory {
|
|
111
|
+
const combined = `${name} ${description}`.toLowerCase();
|
|
112
|
+
|
|
113
|
+
for (const [category, keywords] of CATEGORY_KEYWORDS) {
|
|
114
|
+
for (const keyword of keywords) {
|
|
115
|
+
if (combined.includes(keyword)) {
|
|
116
|
+
return category;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return "knowledge";
|
|
122
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* clawhub-files — SkillFileProvider implementation for clawhub-origin skills.
|
|
3
|
+
*
|
|
4
|
+
* Backed by the `clawhub inspect` CLI. The initial `clawhubInspect` call
|
|
5
|
+
* fetches file metadata *and* SKILL.md content in a single round trip.
|
|
6
|
+
* Results are cached in memory (5-minute TTL) so that subsequent calls to
|
|
7
|
+
* `listFiles`, `readFileContent`, and `toSlimSkill` for the same slug
|
|
8
|
+
* reuse the inspect data without re-running the CLI.
|
|
9
|
+
*
|
|
10
|
+
* For non-SKILL.md files, `readFileContent` delegates to `clawhubInspectFile`
|
|
11
|
+
* which runs a second CLI call for the specific file.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { basename } from "node:path";
|
|
15
|
+
|
|
16
|
+
import type { SlimSkillResponse } from "../daemon/message-types/skills.js";
|
|
17
|
+
import { isTextMimeType as isTextMime } from "../runtime/routes/workspace-utils.js";
|
|
18
|
+
import { getLogger } from "../util/logger.js";
|
|
19
|
+
import type { SkillFileEntry } from "./catalog-files.js";
|
|
20
|
+
import {
|
|
21
|
+
clawhubInspect,
|
|
22
|
+
clawhubInspectFile,
|
|
23
|
+
type ClawhubInspectResult,
|
|
24
|
+
validateSlug,
|
|
25
|
+
} from "./clawhub.js";
|
|
26
|
+
import type { SkillFileProvider } from "./skill-file-provider.js";
|
|
27
|
+
|
|
28
|
+
const log = getLogger("clawhub-files");
|
|
29
|
+
|
|
30
|
+
// ─── Inspect cache ────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
33
|
+
|
|
34
|
+
interface CacheEntry {
|
|
35
|
+
data: ClawhubInspectResult;
|
|
36
|
+
expiresAt: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const inspectCache = new Map<string, CacheEntry>();
|
|
40
|
+
|
|
41
|
+
function getCached(slug: string): ClawhubInspectResult | null {
|
|
42
|
+
const entry = inspectCache.get(slug);
|
|
43
|
+
if (!entry) return null;
|
|
44
|
+
if (Date.now() > entry.expiresAt) {
|
|
45
|
+
inspectCache.delete(slug);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return entry.data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function setCache(slug: string, data: ClawhubInspectResult): void {
|
|
52
|
+
inspectCache.set(slug, { data, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Run `clawhubInspect` with caching. Returns the inspect result or `null`.
|
|
57
|
+
*/
|
|
58
|
+
async function inspectCached(
|
|
59
|
+
slug: string,
|
|
60
|
+
): Promise<ClawhubInspectResult | null> {
|
|
61
|
+
const cached = getCached(slug);
|
|
62
|
+
if (cached) return cached;
|
|
63
|
+
|
|
64
|
+
const result = await clawhubInspect(slug);
|
|
65
|
+
if (!result.data) {
|
|
66
|
+
log.warn({ slug, error: result.error }, "clawhub inspect failed");
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
setCache(slug, result.data);
|
|
70
|
+
return result.data;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Binary classification ───────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Classify a file as binary from its name and optional contentType field.
|
|
77
|
+
* If the contentType from the inspect result is present and recognised,
|
|
78
|
+
* prefer it; otherwise fall back to Bun's extension-based MIME detection
|
|
79
|
+
* (same strategy as `catalog-files.ts`).
|
|
80
|
+
*/
|
|
81
|
+
function classifyBinary(fileName: string, contentType?: string): boolean {
|
|
82
|
+
if (contentType) {
|
|
83
|
+
return !isTextMime(contentType, fileName);
|
|
84
|
+
}
|
|
85
|
+
const mime = Bun.file(fileName).type;
|
|
86
|
+
return !isTextMime(mime, fileName);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ─── Provider factory ─────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create a `SkillFileProvider` for clawhub-origin skills.
|
|
93
|
+
*
|
|
94
|
+
* `canHandle` returns `true` for slugs that pass clawhub's `validateSlug`
|
|
95
|
+
* regex AND do not look like a skills.sh slug (skills.sh slugs have three
|
|
96
|
+
* slash-separated segments: `owner/repo/skill`).
|
|
97
|
+
*/
|
|
98
|
+
export function createClawhubProvider(): SkillFileProvider {
|
|
99
|
+
return {
|
|
100
|
+
canHandle(skillId: string): boolean {
|
|
101
|
+
if (!validateSlug(skillId)) return false;
|
|
102
|
+
// skills.sh slugs have ≥ 3 segments (owner/repo/skill)
|
|
103
|
+
if (skillId.split("/").length >= 3) return false;
|
|
104
|
+
return true;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async listFiles(skillId: string): Promise<SkillFileEntry[] | null> {
|
|
108
|
+
const data = await inspectCached(skillId);
|
|
109
|
+
if (!data || !data.files) return null;
|
|
110
|
+
|
|
111
|
+
const entries: SkillFileEntry[] = data.files.map((f) => {
|
|
112
|
+
const name = basename(f.path);
|
|
113
|
+
const isBinary = classifyBinary(name, f.contentType);
|
|
114
|
+
return {
|
|
115
|
+
path: f.path,
|
|
116
|
+
name,
|
|
117
|
+
size: f.size,
|
|
118
|
+
mimeType: f.contentType ?? Bun.file(name).type,
|
|
119
|
+
isBinary,
|
|
120
|
+
content: null,
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
124
|
+
return entries;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
async readFileContent(
|
|
128
|
+
skillId: string,
|
|
129
|
+
sanitizedPath: string,
|
|
130
|
+
): Promise<SkillFileEntry | null> {
|
|
131
|
+
// If the requested path is SKILL.md and we have cached inspect data
|
|
132
|
+
// with skillMdContent, return it directly without a second CLI call.
|
|
133
|
+
const cached = getCached(skillId);
|
|
134
|
+
if (
|
|
135
|
+
cached &&
|
|
136
|
+
sanitizedPath === "SKILL.md" &&
|
|
137
|
+
cached.skillMdContent != null
|
|
138
|
+
) {
|
|
139
|
+
const name = "SKILL.md";
|
|
140
|
+
return {
|
|
141
|
+
path: sanitizedPath,
|
|
142
|
+
name,
|
|
143
|
+
size: cached.skillMdContent.length,
|
|
144
|
+
mimeType: "text/markdown",
|
|
145
|
+
isBinary: false,
|
|
146
|
+
content: cached.skillMdContent,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const name = basename(sanitizedPath);
|
|
151
|
+
const isBinary = classifyBinary(name);
|
|
152
|
+
|
|
153
|
+
// For non-SKILL.md files (or when SKILL.md isn't cached), run
|
|
154
|
+
// a dedicated inspect call for the specific file.
|
|
155
|
+
const content = await clawhubInspectFile(skillId, sanitizedPath);
|
|
156
|
+
|
|
157
|
+
// Binary files: return metadata with content: null (matching the
|
|
158
|
+
// contract followed by vellum and skills.sh providers). clawhubInspectFile
|
|
159
|
+
// returns null for binary files, which is expected.
|
|
160
|
+
if (isBinary) {
|
|
161
|
+
// Look up file metadata from cached inspect result if available.
|
|
162
|
+
const inspectData =
|
|
163
|
+
getCached(skillId) ?? (await inspectCached(skillId));
|
|
164
|
+
const fileMeta = inspectData?.files?.find(
|
|
165
|
+
(f) => f.path === sanitizedPath,
|
|
166
|
+
);
|
|
167
|
+
return {
|
|
168
|
+
path: sanitizedPath,
|
|
169
|
+
name,
|
|
170
|
+
size: fileMeta?.size ?? 0,
|
|
171
|
+
mimeType: fileMeta?.contentType ?? Bun.file(name).type,
|
|
172
|
+
isBinary: true,
|
|
173
|
+
content: null,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Text file but content fetch failed — file doesn't exist.
|
|
178
|
+
if (content == null) return null;
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
path: sanitizedPath,
|
|
182
|
+
name,
|
|
183
|
+
size: content.length,
|
|
184
|
+
mimeType: Bun.file(name).type,
|
|
185
|
+
isBinary: false,
|
|
186
|
+
content,
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
async toSlimSkill(skillId: string): Promise<SlimSkillResponse | null> {
|
|
191
|
+
const data = await inspectCached(skillId);
|
|
192
|
+
if (!data) return null;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
id: data.skill.slug,
|
|
196
|
+
name: data.skill.displayName,
|
|
197
|
+
description: data.skill.summary,
|
|
198
|
+
kind: "catalog",
|
|
199
|
+
status: "available",
|
|
200
|
+
origin: "clawhub",
|
|
201
|
+
slug: data.skill.slug,
|
|
202
|
+
author: data.owner?.handle ?? "",
|
|
203
|
+
stars: data.stats?.stars ?? 0,
|
|
204
|
+
installs: data.stats?.installs ?? 0,
|
|
205
|
+
reports: 0,
|
|
206
|
+
publishedAt: data.updatedAt
|
|
207
|
+
? new Date(data.updatedAt).toISOString()
|
|
208
|
+
: undefined,
|
|
209
|
+
version: data.latestVersion?.version ?? "",
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|