@vellumai/assistant 0.6.3 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +298 -39
- package/Dockerfile +14 -3
- package/README.md +3 -4
- package/bun.lock +13 -16
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +121 -0
- package/knip.json +20 -3
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +5 -4
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +1094 -72
- package/package.json +9 -8
- package/scripts/generate-openapi.ts +50 -12
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +235 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +434 -12
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- 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 +12 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +52 -159
- package/src/__tests__/btw-routes.test.ts +54 -1
- package/src/__tests__/call-controller.test.ts +582 -22
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- 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__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +576 -502
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +83 -0
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +1458 -198
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +45 -10
- package/src/__tests__/contact-store-user-file.test.ts +511 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +618 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
- package/src/__tests__/conversation-agent-loop.test.ts +510 -84
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
- package/src/__tests__/conversation-error.test.ts +102 -1
- package/src/__tests__/conversation-history-web-search.test.ts +17 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
- package/src/__tests__/conversation-queue.test.ts +932 -76
- package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -143
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +120 -34
- package/src/__tests__/conversation-slash-unknown.test.ts +32 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +45 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -3
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +495 -3
- package/src/__tests__/credentials-cli.test.ts +32 -16
- package/src/__tests__/cross-provider-web-search.test.ts +230 -35
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -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__/edit-propagation.test.ts +280 -0
- 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__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +101 -15
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- 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 -3
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +44 -1
- 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 +166 -32
- 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__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +609 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- 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__/messaging-skill-split.test.ts +3 -34
- 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-from-url.test.ts +684 -0
- 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 +10 -84
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- 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 +95 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +183 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1501 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
- 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 +224 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- 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 +424 -6
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +34 -2
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +80 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -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 +19 -30
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +126 -53
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +26 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +10 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +88 -113
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +442 -103
- 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-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- 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 +5 -22
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- 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-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -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-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -11
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +251 -19
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- 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/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -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/guardian-question-copy.ts +2 -2
- 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 +9 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -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 +28 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +130 -5
- 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/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +90 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +308 -16
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- 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 -10
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +53 -8
- package/src/cli.ts +0 -37
- 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/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- 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/services/reduce.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -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/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 +0 -167
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +39 -10
- package/src/config/feature-flag-registry.json +63 -15
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +220 -22
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +65 -51
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +32 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -30
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +49 -14
- package/src/config/schemas/heartbeat.ts +27 -10
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +53 -4
- package/src/config/schemas/stt.ts +60 -0
- package/src/config/schemas/tts.ts +283 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +6 -2
- 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/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +272 -35
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +23 -2
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +96 -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/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +99 -6
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
- package/src/daemon/conversation-agent-loop.ts +563 -104
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +46 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +85 -11
- package/src/daemon/conversation-messaging.ts +110 -7
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +591 -23
- package/src/daemon/conversation-queue-manager.ts +27 -0
- package/src/daemon/conversation-runtime-assembly.ts +769 -28
- package/src/daemon/conversation-slash.ts +38 -2
- package/src/daemon/conversation-surfaces.ts +483 -5
- package/src/daemon/conversation-tool-setup.ts +35 -5
- package/src/daemon/conversation-usage.ts +8 -5
- package/src/daemon/conversation.ts +193 -47
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -3
- package/src/daemon/handlers/shared.ts +51 -1
- package/src/daemon/handlers/skills.ts +323 -79
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +185 -26
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +48 -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 +23 -1
- 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/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +463 -10
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +156 -22
- 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 +222 -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 +442 -0
- package/src/home/assistant-feed-authoring.ts +128 -0
- package/src/home/emit-feed-event.ts +162 -0
- package/src/home/feed-scheduler.ts +263 -0
- package/src/home/feed-types.ts +235 -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 +413 -0
- package/src/home/suggested-prompts.ts +101 -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__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +152 -0
- package/src/ipc/cli-server.ts +252 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +21 -0
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -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 +233 -0
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/admin.ts +18 -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 +74 -0
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +199 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +65 -1
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +8 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +104 -29
- package/src/memory/graph/extraction.test.ts +295 -2
- package/src/memory/graph/extraction.ts +181 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +257 -66
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -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 +39 -30
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +106 -5
- package/src/memory/jobs-worker.ts +26 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- 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/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- 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/slack-thread-store.ts +37 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +79 -6
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +155 -38
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +6 -12
- package/src/notifications/preference-extractor.ts +2 -6
- 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 +10 -0
- package/src/oauth/platform-connection.test.ts +145 -0
- package/src/oauth/platform-connection.ts +62 -31
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +218 -699
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +71 -75
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +164 -65
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -13
- package/src/platform/client.test.ts +10 -0
- package/src/platform/client.ts +19 -1
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +127 -3
- package/src/prompts/system-prompt.ts +78 -38
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +5 -3
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +335 -70
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +74 -3
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +502 -28
- package/src/providers/model-intents.ts +8 -8
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +530 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +579 -0
- package/src/providers/openrouter/client.ts +168 -4
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +21 -10
- package/src/providers/retry.ts +185 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -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 +323 -0
- package/src/providers/speech-to-text/resolve.ts +393 -6
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +102 -3
- package/src/runtime/AGENTS.md +45 -3
- package/src/runtime/__tests__/agent-wake.test.ts +872 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -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 +553 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +34 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +15 -3
- 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/channel-reply-delivery.ts +106 -2
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +447 -11
- package/src/runtime/http-types.ts +29 -3
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- 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/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -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 +187 -8
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- 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 +618 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -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-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/avatar-routes.ts +20 -4
- 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 +9 -10
- 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 +133 -0
- package/src/runtime/routes/conversation-routes.ts +487 -160
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +452 -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-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- 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 +36 -6
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +325 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +722 -91
- package/src/runtime/routes/settings-routes.ts +26 -7
- 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/trust-rules-routes.ts +30 -14
- 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.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +11 -3
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -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 +340 -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 +71 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +58 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +122 -37
- package/src/security/secure-keys.ts +32 -10
- package/src/security/token-manager.ts +35 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/catalog-install.ts +31 -3
- 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-cache-store.ts +97 -0
- 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 +468 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +228 -0
- package/src/stt/stt-stream-session.ts +506 -0
- package/src/stt/types.ts +334 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +79 -27
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
- package/src/tools/browser/browser-execution.ts +1208 -41
- 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 +205 -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/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +41 -7
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +25 -12
- package/src/tools/network/web-search.ts +20 -2
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +0 -9
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +11 -2
- package/src/tools/terminal/shell.ts +16 -4
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +29 -3
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +1061 -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 +219 -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 +44 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +199 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/types/tar-stream.d.ts +66 -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/json.ts +17 -0
- package/src/util/platform.ts +56 -12
- package/src/util/pricing.ts +78 -5
- 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 +24 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/git-service.ts +23 -4
- 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/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +32 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- 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/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -250
- package/src/__tests__/update-bulletin-format.test.ts +0 -122
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -277
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -63
- package/src/config/bundled-skills/browser/TOOLS.json +0 -393
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -175
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -220
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -251
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -107
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- 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/UPDATES.md +0 -38
- package/src/prompts/templates/USER.md +0 -13
- package/src/prompts/update-bulletin-format.ts +0 -68
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -128
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -10,14 +10,43 @@ import { join, resolve } from "node:path";
|
|
|
10
10
|
|
|
11
11
|
import { type ChannelId, parseInterfaceId } from "../channels/types.js";
|
|
12
12
|
import { getAppDirPath, listAppFiles } from "../memory/app-store.js";
|
|
13
|
+
import {
|
|
14
|
+
getMessages as defaultGetMessages,
|
|
15
|
+
type MessageRow,
|
|
16
|
+
} from "../memory/conversation-crud.js";
|
|
17
|
+
import {
|
|
18
|
+
countMemoryPrefixBlocks,
|
|
19
|
+
extractMemoryPrefixBlocks,
|
|
20
|
+
} from "../memory/graph/conversation-graph-memory.js";
|
|
21
|
+
import { searchPkbFiles } from "../memory/pkb/pkb-search.js";
|
|
22
|
+
import type { QdrantSparseVector } from "../memory/qdrant-client.js";
|
|
23
|
+
import { readSlackMetadata } from "../messaging/providers/slack/message-metadata.js";
|
|
24
|
+
import {
|
|
25
|
+
extractTagLineTexts,
|
|
26
|
+
type RenderableSlackMessage,
|
|
27
|
+
renderSlackTranscript,
|
|
28
|
+
} from "../messaging/providers/slack/render-transcript.js";
|
|
13
29
|
import { isPermissionControlsV2Enabled } from "../permissions/v2-consent-policy.js";
|
|
14
|
-
import type { Message } from "../providers/types.js";
|
|
15
|
-
import
|
|
30
|
+
import type { ContentBlock, Message } from "../providers/types.js";
|
|
31
|
+
import {
|
|
32
|
+
type ActorTrustContext,
|
|
33
|
+
isUntrustedTrustClass,
|
|
34
|
+
type TrustClass,
|
|
35
|
+
} from "../runtime/actor-trust-resolver.js";
|
|
16
36
|
import { channelStatusToMemberStatus } from "../runtime/routes/inbound-stages/acl-enforcement.js";
|
|
17
37
|
import type { SubagentState } from "../subagent/types.js";
|
|
18
38
|
import { TERMINAL_STATUSES } from "../subagent/types.js";
|
|
39
|
+
import { getLogger } from "../util/logger.js";
|
|
19
40
|
import { getWorkspaceDir, getWorkspacePromptPath } from "../util/platform.js";
|
|
20
41
|
import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
42
|
+
import { filterMessagesForUntrustedActor } from "./conversation-lifecycle.js";
|
|
43
|
+
import {
|
|
44
|
+
getInContextPkbPaths,
|
|
45
|
+
type PkbContextConversation,
|
|
46
|
+
} from "./pkb-context-tracker.js";
|
|
47
|
+
import { buildPkbReminder } from "./pkb-reminder-builder.js";
|
|
48
|
+
|
|
49
|
+
const pkbReminderLog = getLogger("pkb-reminder");
|
|
21
50
|
|
|
22
51
|
/**
|
|
23
52
|
* Describes the capabilities of the channel through which the user is
|
|
@@ -557,7 +586,7 @@ export function injectNowScratchpad(
|
|
|
557
586
|
): Message {
|
|
558
587
|
const scratchpadBlock = {
|
|
559
588
|
type: "text" as const,
|
|
560
|
-
text: `<NOW.md Always keep this up to date>\n${content}\n</NOW.md>`,
|
|
589
|
+
text: `<NOW.md Always keep this up to date; keep under 10 lines>\n${content}\n</NOW.md>`,
|
|
561
590
|
};
|
|
562
591
|
|
|
563
592
|
// Find insertion point: skip any leading injected-context text blocks
|
|
@@ -586,7 +615,9 @@ export function injectNowScratchpad(
|
|
|
586
615
|
/** Strip `<NOW.md>` blocks injected by `injectNowScratchpad`. */
|
|
587
616
|
export function stripNowScratchpad(messages: Message[]): Message[] {
|
|
588
617
|
return stripUserTextBlocksByPrefix(messages, [
|
|
589
|
-
|
|
618
|
+
// Shared prefix catches both the current tag and any pre-line-limit
|
|
619
|
+
// variant that may linger in in-flight histories during a rolling deploy.
|
|
620
|
+
"<NOW.md Always keep this up to date",
|
|
590
621
|
"<now_scratchpad>", // backward-compat: strip legacy blocks from pre-rename history
|
|
591
622
|
]);
|
|
592
623
|
}
|
|
@@ -607,12 +638,15 @@ const AUTOINJECT_FILENAME = "_autoinject.md";
|
|
|
607
638
|
/** Max buffer.md lines injected into prompts — keeps context bounded even when filing is off. */
|
|
608
639
|
const MAX_BUFFER_LINES = 50;
|
|
609
640
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
641
|
+
/** Minimum hybrid-search score for a PKB path to surface as an injection hint. */
|
|
642
|
+
const PKB_HINT_THRESHOLD = 0.5;
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Stricter hint threshold for PKB entries under `archive/`. Archive files are
|
|
646
|
+
* date-indexed dumps of older notes — they match loosely and are rarely the
|
|
647
|
+
* most relevant read, so require a higher bar before recommending them.
|
|
648
|
+
*/
|
|
649
|
+
const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
|
|
616
650
|
|
|
617
651
|
/**
|
|
618
652
|
* Read `_autoinject.md` from the PKB directory and return the list of
|
|
@@ -638,6 +672,21 @@ export function readAutoinjectList(pkbDir: string): string[] | null {
|
|
|
638
672
|
}
|
|
639
673
|
}
|
|
640
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Resolve the effective list of auto-inject filenames for a PKB directory.
|
|
677
|
+
*
|
|
678
|
+
* This is the single source of truth used both by `readPkbContext` (which
|
|
679
|
+
* actually injects the files) and by the PKB reminder-hint tracker in
|
|
680
|
+
* `conversation-agent-loop.ts` (which needs to know what's already in
|
|
681
|
+
* context so it doesn't redundantly recommend those files).
|
|
682
|
+
*
|
|
683
|
+
* Returns `PKB_DEFAULT_FILES` when `_autoinject.md` is missing/unreadable,
|
|
684
|
+
* or the parsed list (possibly empty) when it is present.
|
|
685
|
+
*/
|
|
686
|
+
export function getPkbAutoInjectList(pkbRoot: string): string[] {
|
|
687
|
+
return readAutoinjectList(pkbRoot) ?? PKB_DEFAULT_FILES;
|
|
688
|
+
}
|
|
689
|
+
|
|
641
690
|
/**
|
|
642
691
|
* Read the always-loaded PKB files and append a nudge encouraging the
|
|
643
692
|
* assistant to proactively read topic files and use `remember` aggressively.
|
|
@@ -652,7 +701,7 @@ export function readPkbContext(): string | null {
|
|
|
652
701
|
const pkbDir = join(getWorkspaceDir(), "pkb");
|
|
653
702
|
if (!existsSync(pkbDir)) return null;
|
|
654
703
|
|
|
655
|
-
const filesToInject =
|
|
704
|
+
const filesToInject = getPkbAutoInjectList(pkbDir);
|
|
656
705
|
|
|
657
706
|
const parts: string[] = [];
|
|
658
707
|
for (const file of filesToInject) {
|
|
@@ -685,10 +734,13 @@ export function readPkbContext(): string | null {
|
|
|
685
734
|
*/
|
|
686
735
|
export function injectPkbContext(message: Message, content: string): Message {
|
|
687
736
|
// Escape closing tags that could break out of the XML wrapper
|
|
688
|
-
const escaped = content.replace(
|
|
737
|
+
const escaped = content.replace(
|
|
738
|
+
/<\/knowledge_base\s*>/gi,
|
|
739
|
+
"</knowledge_base>",
|
|
740
|
+
);
|
|
689
741
|
const pkbBlock = {
|
|
690
742
|
type: "text" as const,
|
|
691
|
-
text: `<
|
|
743
|
+
text: `<knowledge_base>\n${escaped}\n</knowledge_base>`,
|
|
692
744
|
};
|
|
693
745
|
|
|
694
746
|
// Find insertion point: skip any leading memory/image blocks
|
|
@@ -720,9 +772,12 @@ export function injectPkbContext(message: Message, content: string): Message {
|
|
|
720
772
|
};
|
|
721
773
|
}
|
|
722
774
|
|
|
723
|
-
/** Strip `<
|
|
775
|
+
/** Strip `<knowledge_base>` blocks injected by `injectPkbContext`. */
|
|
724
776
|
export function stripPkbContext(messages: Message[]): Message[] {
|
|
725
|
-
return stripUserTextBlocksByPrefix(messages, [
|
|
777
|
+
return stripUserTextBlocksByPrefix(messages, [
|
|
778
|
+
"<knowledge_base>",
|
|
779
|
+
"<pkb>", // backward-compat: strip legacy blocks from pre-rename history
|
|
780
|
+
]);
|
|
726
781
|
}
|
|
727
782
|
|
|
728
783
|
/**
|
|
@@ -876,6 +931,12 @@ export interface UnifiedTurnContextOptions {
|
|
|
876
931
|
interfaceName?: string;
|
|
877
932
|
channelName?: string;
|
|
878
933
|
actorContext?: InboundActorContext | null;
|
|
934
|
+
/**
|
|
935
|
+
* Human-readable duration since the previous user message (e.g. "14h ago",
|
|
936
|
+
* "yesterday", "3d ago"). Only populated when the gap exceeds 12 hours so
|
|
937
|
+
* the model can acknowledge long absences; otherwise omitted.
|
|
938
|
+
*/
|
|
939
|
+
timeSinceLastMessage?: string | null;
|
|
879
940
|
}
|
|
880
941
|
|
|
881
942
|
/**
|
|
@@ -902,12 +963,19 @@ export function buildUnifiedTurnContextBlock(
|
|
|
902
963
|
.replace(/[\r\n\u0085\u2028\u2029]+/g, " ")
|
|
903
964
|
// Replace remaining ASCII C0/C1 control characters and DEL.
|
|
904
965
|
.replace(/[\x00-\x1F\x7F-\x9F]/g, " ")
|
|
966
|
+
// Escape XML special characters to prevent turn_context breakout.
|
|
967
|
+
.replace(/&/g, "&")
|
|
968
|
+
.replace(/</g, "<")
|
|
969
|
+
.replace(/>/g, ">")
|
|
905
970
|
.trim();
|
|
906
971
|
return singleLine.length > 0 ? singleLine : "unknown";
|
|
907
972
|
};
|
|
908
973
|
|
|
909
974
|
const lines: string[] = ["<turn_context>"];
|
|
910
975
|
lines.push(`current_time: ${options.timestamp}`);
|
|
976
|
+
if (options.timeSinceLastMessage) {
|
|
977
|
+
lines.push(`time_since_last_message: ${options.timeSinceLastMessage}`);
|
|
978
|
+
}
|
|
911
979
|
if (options.interfaceName) {
|
|
912
980
|
lines.push(`interface: ${options.interfaceName}`);
|
|
913
981
|
}
|
|
@@ -1128,6 +1196,433 @@ export function stripTransportHints(messages: Message[]): Message[] {
|
|
|
1128
1196
|
return stripUserTextBlocksByPrefix(messages, ["<transport_hints>"]);
|
|
1129
1197
|
}
|
|
1130
1198
|
|
|
1199
|
+
// ---------------------------------------------------------------------------
|
|
1200
|
+
// Slack chronological transcript assembly
|
|
1201
|
+
// ---------------------------------------------------------------------------
|
|
1202
|
+
|
|
1203
|
+
/**
|
|
1204
|
+
* True when the channel capabilities describe a Slack non-DM conversation
|
|
1205
|
+
* (group/channel/mpim). Used to gate thread-only behavior such as the
|
|
1206
|
+
* `<active_thread>` focus block. DMs are excluded because they have no
|
|
1207
|
+
* threads.
|
|
1208
|
+
*
|
|
1209
|
+
* The gateway normalizer sets `chatType: "channel"` for every non-DM Slack
|
|
1210
|
+
* conversation (public, private, and mpim alike — see
|
|
1211
|
+
* `gateway/src/slack/normalize.ts`) and omits the field entirely for DMs.
|
|
1212
|
+
* We therefore accept only `chatType === "channel"` — when the gateway
|
|
1213
|
+
* omits `chatType` (as it does for DMs), the check correctly returns
|
|
1214
|
+
* `false`.
|
|
1215
|
+
*
|
|
1216
|
+
* The chronological-transcript override applies to ALL Slack
|
|
1217
|
+
* conversations (channels and DMs) — gate that on
|
|
1218
|
+
* `channelCapabilities.channel === "slack"` rather than this helper.
|
|
1219
|
+
*/
|
|
1220
|
+
export function isSlackChannelConversation(
|
|
1221
|
+
channelCapabilities?: ChannelCapabilities | null,
|
|
1222
|
+
): boolean {
|
|
1223
|
+
return (
|
|
1224
|
+
channelCapabilities?.channel === "slack" &&
|
|
1225
|
+
channelCapabilities.chatType === "channel"
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Minimal structural shape of a persisted message row used by the Slack
|
|
1231
|
+
* chronological-transcript assembly path. Decouples the assembly logic from
|
|
1232
|
+
* the DB-row type so it can be unit-tested with plain literals.
|
|
1233
|
+
*/
|
|
1234
|
+
export interface SlackTranscriptInputRow {
|
|
1235
|
+
role: "user" | "assistant";
|
|
1236
|
+
/** Raw persisted content column. JSON-encoded `ContentBlock[]` in production. */
|
|
1237
|
+
content: string;
|
|
1238
|
+
/** Epoch ms when the row was created. */
|
|
1239
|
+
createdAt: number;
|
|
1240
|
+
/** Raw `metadata` column value (JSON string with optional `slackMeta` sub-key). */
|
|
1241
|
+
metadata: string | null;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Extract the user-facing plain text from an already-parsed `ContentBlock[]`.
|
|
1246
|
+
* Only `text` blocks contribute to the rendered transcript line. Tool-use /
|
|
1247
|
+
* tool-result / thinking blocks are intentionally elided — they would clutter
|
|
1248
|
+
* the Slack-style transcript and the model can already recall them from the
|
|
1249
|
+
* surrounding turn structure.
|
|
1250
|
+
*
|
|
1251
|
+
* Rows with no text blocks (e.g. images, file uploads, pure tool turns) would
|
|
1252
|
+
* otherwise render as an empty transcript line like `[14:25 @alice]: `;
|
|
1253
|
+
* surface the attachment/tool context instead so the model can tell something
|
|
1254
|
+
* was actually said on that turn.
|
|
1255
|
+
*/
|
|
1256
|
+
function extractPlainTextFromBlocks(blocks: ContentBlock[]): string {
|
|
1257
|
+
const parts: string[] = [];
|
|
1258
|
+
const placeholderLabels: string[] = [];
|
|
1259
|
+
for (const block of blocks) {
|
|
1260
|
+
if (!block || typeof block !== "object") continue;
|
|
1261
|
+
if (block.type === "text") {
|
|
1262
|
+
parts.push(block.text);
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
const label = placeholderForBlockType(block.type);
|
|
1266
|
+
if (label && !placeholderLabels.includes(label)) {
|
|
1267
|
+
placeholderLabels.push(label);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (parts.length > 0) {
|
|
1271
|
+
return parts.join("\n");
|
|
1272
|
+
}
|
|
1273
|
+
return placeholderLabels.join(" ");
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
function placeholderForBlockType(type: ContentBlock["type"]): string | null {
|
|
1277
|
+
switch (type) {
|
|
1278
|
+
case "image":
|
|
1279
|
+
return "[image]";
|
|
1280
|
+
case "file":
|
|
1281
|
+
return "[file]";
|
|
1282
|
+
case "tool_use":
|
|
1283
|
+
case "server_tool_use":
|
|
1284
|
+
return "[tool call]";
|
|
1285
|
+
case "tool_result":
|
|
1286
|
+
case "web_search_tool_result":
|
|
1287
|
+
return "[tool result]";
|
|
1288
|
+
case "thinking":
|
|
1289
|
+
case "redacted_thinking":
|
|
1290
|
+
case "text":
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* Convert a persisted row into the {@link RenderableSlackMessage} shape
|
|
1297
|
+
* consumed by `renderSlackTranscript`.
|
|
1298
|
+
*
|
|
1299
|
+
* Legacy pre-upgrade rows (no `slackMeta` sub-key, malformed metadata, etc.)
|
|
1300
|
+
* yield `metadata: null`; the renderer then takes its flat-render fallback
|
|
1301
|
+
* path and the row stays in chronological order via `createdAt`.
|
|
1302
|
+
*
|
|
1303
|
+
* Sender labels are emitted only when they add information beyond the role
|
|
1304
|
+
* slot:
|
|
1305
|
+
* - Reaction rows: always labeled — `@assistant` for the assistant, the real
|
|
1306
|
+
* `slackMeta.displayName` for a known user, or `@user` as a last-resort
|
|
1307
|
+
* subject so the rendered `[time X reacted ...]` line still parses.
|
|
1308
|
+
* - Assistant message rows: `null` — the role slot already says "assistant".
|
|
1309
|
+
* - User message rows: real `slackMeta.displayName` when available (to
|
|
1310
|
+
* disambiguate speakers in multi-party channels); `null` otherwise so the
|
|
1311
|
+
* renderer drops the redundant `@user` placeholder.
|
|
1312
|
+
*/
|
|
1313
|
+
function rowToRenderable(row: SlackTranscriptInputRow): RenderableSlackMessage {
|
|
1314
|
+
let slackMeta: ReturnType<typeof readSlackMetadata> = null;
|
|
1315
|
+
if (row.metadata) {
|
|
1316
|
+
try {
|
|
1317
|
+
const outer = JSON.parse(row.metadata) as { slackMeta?: unknown };
|
|
1318
|
+
if (typeof outer.slackMeta === "string") {
|
|
1319
|
+
slackMeta = readSlackMetadata(outer.slackMeta);
|
|
1320
|
+
}
|
|
1321
|
+
} catch {
|
|
1322
|
+
// Malformed metadata — fall through to legacy/null treatment.
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
const isReaction = slackMeta?.eventKind === "reaction";
|
|
1327
|
+
let senderLabel: string | null;
|
|
1328
|
+
if (isReaction) {
|
|
1329
|
+
senderLabel =
|
|
1330
|
+
row.role === "assistant"
|
|
1331
|
+
? "@assistant"
|
|
1332
|
+
: (slackMeta?.displayName ?? "@user");
|
|
1333
|
+
} else if (row.role === "assistant") {
|
|
1334
|
+
senderLabel = null;
|
|
1335
|
+
} else {
|
|
1336
|
+
senderLabel = slackMeta?.displayName ?? null;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Parse `row.content` once and derive both the structured `contentBlocks`
|
|
1340
|
+
// view (for downstream tool-block preservation) and the flattened
|
|
1341
|
+
// `plainText` view (used for tag-line rendering) from the same parsed
|
|
1342
|
+
// result. Large Slack histories with many tool payloads would otherwise
|
|
1343
|
+
// pay a double JSON-parse cost per row.
|
|
1344
|
+
let contentBlocks: ContentBlock[] = [];
|
|
1345
|
+
let plainText: string;
|
|
1346
|
+
try {
|
|
1347
|
+
const parsed = JSON.parse(row.content);
|
|
1348
|
+
if (Array.isArray(parsed)) {
|
|
1349
|
+
contentBlocks = parsed as ContentBlock[];
|
|
1350
|
+
plainText = extractPlainTextFromBlocks(contentBlocks);
|
|
1351
|
+
} else if (typeof parsed === "string") {
|
|
1352
|
+
plainText = parsed;
|
|
1353
|
+
} else {
|
|
1354
|
+
plainText = row.content;
|
|
1355
|
+
}
|
|
1356
|
+
} catch {
|
|
1357
|
+
// Plain string row (legacy) — no structured blocks to preserve.
|
|
1358
|
+
plainText = row.content;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// Attachment-only rows (images, files) carry no text block, so the
|
|
1362
|
+
// transcript renderer would normally emit them *without* a tag line —
|
|
1363
|
+
// the model sees the image but loses sender/timestamp attribution.
|
|
1364
|
+
// Synthesize a leading text block carrying the placeholder so the
|
|
1365
|
+
// renderer emits `[14:25 @alice]: [image]` and then the image itself.
|
|
1366
|
+
// Pure tool-only rows (tool_use / tool_result) are intentionally
|
|
1367
|
+
// excluded — those are synthetic turn continuations that should stay
|
|
1368
|
+
// tag-line-free, matching the documented behaviour in
|
|
1369
|
+
// `buildMessageContentBlocks`.
|
|
1370
|
+
const hasTextBlock = contentBlocks.some((b) => b?.type === "text");
|
|
1371
|
+
const hasAttachmentBlock = contentBlocks.some(
|
|
1372
|
+
(b) => b?.type === "image" || b?.type === "file",
|
|
1373
|
+
);
|
|
1374
|
+
if (!hasTextBlock && hasAttachmentBlock && plainText !== "") {
|
|
1375
|
+
contentBlocks = [{ type: "text", text: plainText }, ...contentBlocks];
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
return {
|
|
1379
|
+
role: row.role,
|
|
1380
|
+
content: plainText,
|
|
1381
|
+
metadata: slackMeta,
|
|
1382
|
+
senderLabel,
|
|
1383
|
+
createdAt: row.createdAt,
|
|
1384
|
+
contentBlocks,
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Build a chronological Slack transcript for Slack conversations (both DMs
|
|
1390
|
+
* and group/channel/mpim) and project it onto the LLM-facing `Message[]`
|
|
1391
|
+
* shape.
|
|
1392
|
+
*
|
|
1393
|
+
* Returns `null` when the channel is not Slack (caller should fall through
|
|
1394
|
+
* to the default message history). Legacy pre-upgrade rows without
|
|
1395
|
+
* `slackMeta` are tolerated: the renderer's flat fallback orders them by
|
|
1396
|
+
* `createdAt` alongside post-upgrade rows.
|
|
1397
|
+
*
|
|
1398
|
+
* For ALL Slack conversations (channels and DMs), `<transport_hints>`
|
|
1399
|
+
* injection is suppressed by `applyRuntimeInjections` so the model sees
|
|
1400
|
+
* one consistent persisted view instead of a duplicated gateway hint.
|
|
1401
|
+
*/
|
|
1402
|
+
export function assembleSlackChronologicalMessages(
|
|
1403
|
+
rows: SlackTranscriptInputRow[],
|
|
1404
|
+
capabilities: ChannelCapabilities,
|
|
1405
|
+
): Message[] | null {
|
|
1406
|
+
if (capabilities.channel !== "slack") {
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
const renderable = rows.map(rowToRenderable);
|
|
1410
|
+
return renderSlackTranscript(renderable);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Load DB rows for a Slack conversation and project them onto the
|
|
1415
|
+
* chronological transcript shape.
|
|
1416
|
+
*
|
|
1417
|
+
* Convenience wrapper over `getMessages` + `assembleSlackChronologicalMessages`.
|
|
1418
|
+
* The loader is exposed as a parameter so tests can substitute a stub. In
|
|
1419
|
+
* production it defaults to `getMessages` from `conversation-crud.ts`.
|
|
1420
|
+
*
|
|
1421
|
+
* When `trustClass` identifies an untrusted actor (guardian-scoped rows
|
|
1422
|
+
* must not leak into the model context), rows are passed through
|
|
1423
|
+
* `filterMessagesForUntrustedActor` before assembly — mirroring the
|
|
1424
|
+
* filtering applied in `loadFromDb` so the chronological transcript
|
|
1425
|
+
* respects the same per-actor scoping as the default history path.
|
|
1426
|
+
*
|
|
1427
|
+
* Returns `null` when the channel is not Slack — callers should fall
|
|
1428
|
+
* through to the default in-memory message history.
|
|
1429
|
+
*/
|
|
1430
|
+
export function loadSlackChronologicalMessages(
|
|
1431
|
+
conversationId: string,
|
|
1432
|
+
capabilities: ChannelCapabilities,
|
|
1433
|
+
options: {
|
|
1434
|
+
loader?: (id: string) => MessageRow[];
|
|
1435
|
+
trustClass?: TrustClass;
|
|
1436
|
+
} = {},
|
|
1437
|
+
): Message[] | null {
|
|
1438
|
+
if (capabilities.channel !== "slack") {
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
const loader = options.loader ?? defaultGetMessages;
|
|
1442
|
+
const allRows = loader(conversationId);
|
|
1443
|
+
const scopedRows = isUntrustedTrustClass(options.trustClass)
|
|
1444
|
+
? filterMessagesForUntrustedActor(allRows)
|
|
1445
|
+
: allRows;
|
|
1446
|
+
// Coerce MessageRow.role (string) to the structural row's stricter union.
|
|
1447
|
+
const rows: SlackTranscriptInputRow[] = scopedRows.map((row) => ({
|
|
1448
|
+
role: row.role === "assistant" ? "assistant" : "user",
|
|
1449
|
+
content: row.content,
|
|
1450
|
+
createdAt: row.createdAt,
|
|
1451
|
+
metadata: row.metadata,
|
|
1452
|
+
}));
|
|
1453
|
+
return assembleSlackChronologicalMessages(rows, capabilities);
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// ---------------------------------------------------------------------------
|
|
1457
|
+
// Active-thread focus block (non-persisted; appended to current user turn)
|
|
1458
|
+
// ---------------------------------------------------------------------------
|
|
1459
|
+
|
|
1460
|
+
/**
|
|
1461
|
+
* Detect the "active" Slack thread ts for the current turn.
|
|
1462
|
+
*
|
|
1463
|
+
* The active thread is the thread the current inbound user message belongs
|
|
1464
|
+
* to: scan from newest to oldest and return the `slackMeta.threadTs` of the
|
|
1465
|
+
* most recent user row that carries one. Returns `null` when no recent user
|
|
1466
|
+
* row sits inside a thread (e.g. the inbound was a top-level channel post,
|
|
1467
|
+
* or the conversation has no Slack-tagged user rows yet).
|
|
1468
|
+
*
|
|
1469
|
+
* Pure: takes pre-mapped renderable rows and returns the ts string only.
|
|
1470
|
+
*/
|
|
1471
|
+
function detectActiveThreadTs(rows: RenderableSlackMessage[]): string | null {
|
|
1472
|
+
for (let i = rows.length - 1; i >= 0; i--) {
|
|
1473
|
+
const row = rows[i];
|
|
1474
|
+
if (row.role !== "user") continue;
|
|
1475
|
+
const meta = row.metadata;
|
|
1476
|
+
if (!meta) continue;
|
|
1477
|
+
if (meta.eventKind !== "message") continue;
|
|
1478
|
+
if (typeof meta.threadTs === "string" && meta.threadTs.length > 0) {
|
|
1479
|
+
return meta.threadTs;
|
|
1480
|
+
}
|
|
1481
|
+
// First non-thread user row wins: the inbound is top-level, no active
|
|
1482
|
+
// thread to focus on.
|
|
1483
|
+
return null;
|
|
1484
|
+
}
|
|
1485
|
+
return null;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* Build a focus block listing every message belonging to the active thread:
|
|
1490
|
+
* the parent (whose `channelTs` equals `activeThreadTs`) plus every reply
|
|
1491
|
+
* (whose `threadTs` equals `activeThreadTs`). Reactions targeting any of
|
|
1492
|
+
* those messages are also pulled in via their `targetChannelTs`. Edits and
|
|
1493
|
+
* deletions surface through the existing renderer markers.
|
|
1494
|
+
*
|
|
1495
|
+
* Returns `null` when no rows match (e.g. parent backfill hasn't run yet
|
|
1496
|
+
* AND the thread has no replies in storage either) so the caller can skip
|
|
1497
|
+
* the empty block. Otherwise returns the rendered XML block ready to append
|
|
1498
|
+
* to the user's tail message.
|
|
1499
|
+
*
|
|
1500
|
+
* Pure: takes pre-mapped renderable rows + a thread ts, returns text only.
|
|
1501
|
+
*/
|
|
1502
|
+
function buildActiveThreadBlockFromRenderable(
|
|
1503
|
+
rows: RenderableSlackMessage[],
|
|
1504
|
+
activeThreadTs: string,
|
|
1505
|
+
): string | null {
|
|
1506
|
+
const members: RenderableSlackMessage[] = [];
|
|
1507
|
+
for (const row of rows) {
|
|
1508
|
+
const meta = row.metadata;
|
|
1509
|
+
if (!meta) continue;
|
|
1510
|
+
if (meta.eventKind === "message") {
|
|
1511
|
+
if (
|
|
1512
|
+
meta.channelTs === activeThreadTs ||
|
|
1513
|
+
meta.threadTs === activeThreadTs
|
|
1514
|
+
) {
|
|
1515
|
+
members.push(row);
|
|
1516
|
+
}
|
|
1517
|
+
continue;
|
|
1518
|
+
}
|
|
1519
|
+
if (
|
|
1520
|
+
meta.eventKind === "reaction" &&
|
|
1521
|
+
meta.reaction &&
|
|
1522
|
+
meta.reaction.targetChannelTs === activeThreadTs
|
|
1523
|
+
) {
|
|
1524
|
+
members.push(row);
|
|
1525
|
+
continue;
|
|
1526
|
+
}
|
|
1527
|
+
// Reactions targeting a reply within the thread also belong in the
|
|
1528
|
+
// focus block — collect them by checking the reaction target against
|
|
1529
|
+
// any thread reply's channelTs we've already accepted. We do this in a
|
|
1530
|
+
// second pass below to avoid an O(n^2) inner scan here.
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// Second pass: pull in reactions whose target is one of the already-
|
|
1534
|
+
// collected reply messages. Using a Set keeps this O(n).
|
|
1535
|
+
const memberChannelTs = new Set(
|
|
1536
|
+
members
|
|
1537
|
+
.map((m) => m.metadata?.channelTs)
|
|
1538
|
+
.filter((v): v is string => typeof v === "string"),
|
|
1539
|
+
);
|
|
1540
|
+
for (const row of rows) {
|
|
1541
|
+
const meta = row.metadata;
|
|
1542
|
+
if (!meta || meta.eventKind !== "reaction" || !meta.reaction) continue;
|
|
1543
|
+
if (meta.reaction.targetChannelTs === activeThreadTs) continue; // already added
|
|
1544
|
+
if (memberChannelTs.has(meta.reaction.targetChannelTs)) {
|
|
1545
|
+
members.push(row);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
if (members.length === 0) return null;
|
|
1550
|
+
|
|
1551
|
+
// The active-thread block is flattened to plain text below, which discards
|
|
1552
|
+
// `Message.role`. Force a role-derived sender label on any member whose
|
|
1553
|
+
// `rowToRenderable` emitted `null` (assistant rows, user rows without a
|
|
1554
|
+
// real Slack displayName) so speaker attribution survives the flattening.
|
|
1555
|
+
const labeledMembers = members.map((m) =>
|
|
1556
|
+
m.senderLabel
|
|
1557
|
+
? m
|
|
1558
|
+
: {
|
|
1559
|
+
...m,
|
|
1560
|
+
senderLabel: m.role === "assistant" ? "@assistant" : "@user",
|
|
1561
|
+
},
|
|
1562
|
+
);
|
|
1563
|
+
|
|
1564
|
+
const rendered = renderSlackTranscript(labeledMembers);
|
|
1565
|
+
if (rendered.length === 0) return null;
|
|
1566
|
+
const lines = extractTagLineTexts(rendered).join("\n");
|
|
1567
|
+
return `<active_thread>\n${lines}\n</active_thread>`;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
/**
|
|
1571
|
+
* Build the Slack active-thread focus block from raw rows.
|
|
1572
|
+
*
|
|
1573
|
+
* Pure assembly entrypoint mirroring `assembleSlackChronologicalMessages`.
|
|
1574
|
+
* Returns the rendered `<active_thread>` block as a string, or `null` when:
|
|
1575
|
+
* - the channel is not Slack, OR
|
|
1576
|
+
* - the channel is a Slack DM (DMs do not have threads), OR
|
|
1577
|
+
* - the latest user row is top-level (not in a thread), OR
|
|
1578
|
+
* - no rows belong to the active thread.
|
|
1579
|
+
*/
|
|
1580
|
+
export function assembleSlackActiveThreadFocusBlock(
|
|
1581
|
+
rows: SlackTranscriptInputRow[],
|
|
1582
|
+
capabilities: ChannelCapabilities,
|
|
1583
|
+
): string | null {
|
|
1584
|
+
if (capabilities.channel !== "slack") return null;
|
|
1585
|
+
// DMs do not have threads, so the focus block is always a no-op.
|
|
1586
|
+
// The gateway sets `chatType: "channel"` for every non-DM Slack
|
|
1587
|
+
// conversation and omits the field for DMs, so gate the focus block
|
|
1588
|
+
// on the positive `"channel"` match.
|
|
1589
|
+
if (capabilities.chatType !== "channel") return null;
|
|
1590
|
+
const renderable = rows.map(rowToRenderable);
|
|
1591
|
+
const activeThreadTs = detectActiveThreadTs(renderable);
|
|
1592
|
+
if (!activeThreadTs) return null;
|
|
1593
|
+
return buildActiveThreadBlockFromRenderable(renderable, activeThreadTs);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Loader convenience over `assembleSlackActiveThreadFocusBlock` mirroring
|
|
1598
|
+
* `loadSlackChronologicalMessages`. Returns `null` when the channel is not
|
|
1599
|
+
* Slack, or when it is a Slack DM (DMs have no threads), so callers can
|
|
1600
|
+
* skip the injection entirely without paying for a DB read.
|
|
1601
|
+
*/
|
|
1602
|
+
export function loadSlackActiveThreadFocusBlock(
|
|
1603
|
+
conversationId: string,
|
|
1604
|
+
capabilities: ChannelCapabilities,
|
|
1605
|
+
options: {
|
|
1606
|
+
loader?: (id: string) => MessageRow[];
|
|
1607
|
+
trustClass?: TrustClass;
|
|
1608
|
+
} = {},
|
|
1609
|
+
): string | null {
|
|
1610
|
+
if (capabilities.channel !== "slack") return null;
|
|
1611
|
+
if (capabilities.chatType !== "channel") return null;
|
|
1612
|
+
const loader = options.loader ?? defaultGetMessages;
|
|
1613
|
+
const allRows = loader(conversationId);
|
|
1614
|
+
const scopedRows = isUntrustedTrustClass(options.trustClass)
|
|
1615
|
+
? filterMessagesForUntrustedActor(allRows)
|
|
1616
|
+
: allRows;
|
|
1617
|
+
const rows: SlackTranscriptInputRow[] = scopedRows.map((row) => ({
|
|
1618
|
+
role: row.role === "assistant" ? "assistant" : "user",
|
|
1619
|
+
content: row.content,
|
|
1620
|
+
createdAt: row.createdAt,
|
|
1621
|
+
metadata: row.metadata,
|
|
1622
|
+
}));
|
|
1623
|
+
return assembleSlackActiveThreadFocusBlock(rows, capabilities);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1131
1626
|
/** Prefixes stripped by the pipeline (order doesn't matter — single pass). */
|
|
1132
1627
|
const RUNTIME_INJECTION_PREFIXES = [
|
|
1133
1628
|
"<channel_capabilities>",
|
|
@@ -1154,11 +1649,18 @@ const RUNTIME_INJECTION_PREFIXES = [
|
|
|
1154
1649
|
"<active_workspace>",
|
|
1155
1650
|
"<active_dynamic_page>",
|
|
1156
1651
|
"<non_interactive_context>",
|
|
1157
|
-
|
|
1652
|
+
// Shared prefix catches both the current NOW.md tag and any pre-line-limit
|
|
1653
|
+
// variant that may linger in in-flight histories during a rolling deploy.
|
|
1654
|
+
"<NOW.md Always keep this up to date",
|
|
1158
1655
|
"<now_scratchpad>", // backward-compat: strip legacy blocks from pre-rename history
|
|
1159
|
-
"<
|
|
1656
|
+
"<knowledge_base>",
|
|
1657
|
+
"<pkb>", // backward-compat: strip legacy tag from pre-rename history
|
|
1160
1658
|
"<system_reminder>",
|
|
1161
1659
|
"<transport_hints>",
|
|
1660
|
+
// The Slack active-thread focus block is non-persisted and injected on
|
|
1661
|
+
// the FINAL user turn only. Strip it here so re-assembly during compaction
|
|
1662
|
+
// and overflow recovery does not duplicate it across turns.
|
|
1663
|
+
"<active_thread>",
|
|
1162
1664
|
"<system_notice>One or more tool calls returned an error.",
|
|
1163
1665
|
];
|
|
1164
1666
|
|
|
@@ -1179,16 +1681,23 @@ export function stripInjectionsForCompaction(messages: Message[]): Message[] {
|
|
|
1179
1681
|
* Returns null if no NOW.md injection is found.
|
|
1180
1682
|
*/
|
|
1181
1683
|
export function findLastInjectedNowContent(messages: Message[]): string | null {
|
|
1182
|
-
|
|
1684
|
+
// Matches every NOW.md opening tag we emit (the tag text may evolve over
|
|
1685
|
+
// time, e.g. adding a line-limit hint), so in-flight histories with older
|
|
1686
|
+
// tag variants remain discoverable during a rolling deploy.
|
|
1687
|
+
const openTagPrefix = "<NOW.md Always keep this up to date";
|
|
1183
1688
|
const suffix = "\n</NOW.md>";
|
|
1184
1689
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1185
1690
|
const msg = messages[i];
|
|
1186
1691
|
if (msg.role !== "user") continue;
|
|
1187
1692
|
for (const block of msg.content) {
|
|
1188
|
-
if (block.type
|
|
1189
|
-
|
|
1190
|
-
if (end > prefix.length) return block.text.slice(prefix.length, end);
|
|
1693
|
+
if (block.type !== "text" || !block.text.startsWith(openTagPrefix)) {
|
|
1694
|
+
continue;
|
|
1191
1695
|
}
|
|
1696
|
+
const tagEnd = block.text.indexOf(">\n");
|
|
1697
|
+
if (tagEnd < 0) continue;
|
|
1698
|
+
const contentStart = tagEnd + ">\n".length;
|
|
1699
|
+
const end = block.text.lastIndexOf(suffix);
|
|
1700
|
+
if (end > contentStart) return block.text.slice(contentStart, end);
|
|
1192
1701
|
}
|
|
1193
1702
|
}
|
|
1194
1703
|
return null;
|
|
@@ -1205,13 +1714,29 @@ export function findLastInjectedNowContent(messages: Message[]): string | null {
|
|
|
1205
1714
|
*/
|
|
1206
1715
|
export type InjectionMode = "full" | "minimal";
|
|
1207
1716
|
|
|
1717
|
+
/**
|
|
1718
|
+
* Per-turn injection bytes captured for later persistence to message
|
|
1719
|
+
* metadata. Empty in this PR — later PRs capture `<turn_context>` and
|
|
1720
|
+
* `<system_reminder>` bodies so they survive daemon restarts.
|
|
1721
|
+
*/
|
|
1722
|
+
export interface RuntimeInjectionBlocks {
|
|
1723
|
+
unifiedTurnContext?: string;
|
|
1724
|
+
pkbSystemReminder?: string;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
export interface RuntimeInjectionResult {
|
|
1728
|
+
messages: Message[];
|
|
1729
|
+
blocks: RuntimeInjectionBlocks;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1208
1732
|
/**
|
|
1209
1733
|
* Apply a chain of user-message injections to `runMessages`.
|
|
1210
1734
|
*
|
|
1211
1735
|
* Each injection is optional — pass `null`/`undefined` to skip it.
|
|
1212
|
-
* Returns the final message array ready for the provider
|
|
1736
|
+
* Returns the final message array ready for the provider, along with a
|
|
1737
|
+
* `blocks` object reserved for captured injection bytes (currently empty).
|
|
1213
1738
|
*/
|
|
1214
|
-
export function applyRuntimeInjections(
|
|
1739
|
+
export async function applyRuntimeInjections(
|
|
1215
1740
|
runMessages: Message[],
|
|
1216
1741
|
options: {
|
|
1217
1742
|
activeSurface?: ActiveSurfaceContext | null;
|
|
@@ -1222,15 +1747,114 @@ export function applyRuntimeInjections(
|
|
|
1222
1747
|
voiceCallControlPrompt?: string | null;
|
|
1223
1748
|
pkbContext?: string | null;
|
|
1224
1749
|
pkbActive?: boolean;
|
|
1750
|
+
/**
|
|
1751
|
+
* Dense query vector surfaced from the graph memory retriever (PR 3).
|
|
1752
|
+
* When present together with `pkbActive`, used to run `searchPkbFiles`
|
|
1753
|
+
* to surface relevance hints in the PKB system reminder. When missing,
|
|
1754
|
+
* the reminder falls back to the flat static text.
|
|
1755
|
+
*/
|
|
1756
|
+
pkbQueryVector?: number[];
|
|
1757
|
+
/** Optional sparse vector accompanying `pkbQueryVector`. */
|
|
1758
|
+
pkbSparseVector?: QdrantSparseVector;
|
|
1759
|
+
/** Memory scope id used to filter PKB search results. */
|
|
1760
|
+
pkbScopeId?: string;
|
|
1761
|
+
/**
|
|
1762
|
+
* The live conversation (or a minimal shape containing `messages`) used
|
|
1763
|
+
* to compute which PKB paths are already "in context" and therefore
|
|
1764
|
+
* suppressed from hint suggestions.
|
|
1765
|
+
*/
|
|
1766
|
+
pkbConversation?: PkbContextConversation;
|
|
1767
|
+
/** Auto-injected PKB filenames (resolved relative to `pkbRoot`). */
|
|
1768
|
+
pkbAutoInjectList?: string[];
|
|
1769
|
+
/** Absolute path to the PKB directory (e.g. `<workspace>/pkb`). */
|
|
1770
|
+
pkbRoot?: string;
|
|
1771
|
+
/**
|
|
1772
|
+
* Working directory against which relative `file_read` tool paths
|
|
1773
|
+
* resolve, used to detect workspace-relative reads like
|
|
1774
|
+
* `pkb/threads.md`. Falls back to `pkbRoot` when omitted.
|
|
1775
|
+
*/
|
|
1776
|
+
pkbWorkingDir?: string;
|
|
1225
1777
|
nowScratchpad?: string | null;
|
|
1226
1778
|
subagentStatusBlock?: string | null;
|
|
1227
1779
|
isNonInteractive?: boolean;
|
|
1228
1780
|
transportHints?: string[] | null;
|
|
1781
|
+
/**
|
|
1782
|
+
* Pre-rendered Slack chronological transcript that replaces the
|
|
1783
|
+
* default `runMessages` history for any Slack conversation (channels
|
|
1784
|
+
* and DMs alike).
|
|
1785
|
+
*
|
|
1786
|
+
* When `channelCapabilities` describes a Slack conversation and this
|
|
1787
|
+
* array is non-empty, it overrides `runMessages` so the model sees one
|
|
1788
|
+
* chronologically-ordered transcript built from the stored Slack
|
|
1789
|
+
* metadata. Channel renders include sibling-thread tags; DM renders
|
|
1790
|
+
* are flat (DMs have no threads). The `transportHints` pipeline is
|
|
1791
|
+
* skipped for any Slack conversation so the persisted view isn't
|
|
1792
|
+
* duplicated by gateway-side hints.
|
|
1793
|
+
*
|
|
1794
|
+
* Callers build this via `loadSlackChronologicalMessages` (or the
|
|
1795
|
+
* underlying `assembleSlackChronologicalMessages`) before invoking
|
|
1796
|
+
* this function so the assembly path stays free of direct DB calls
|
|
1797
|
+
* and remains easy to test.
|
|
1798
|
+
*/
|
|
1799
|
+
slackChronologicalMessages?: Message[] | null;
|
|
1800
|
+
/**
|
|
1801
|
+
* Pre-rendered `<active_thread>` focus block listing the messages of
|
|
1802
|
+
* the thread the current inbound user message belongs to.
|
|
1803
|
+
*
|
|
1804
|
+
* Appended (tail-block) to the FINAL user message ONLY when
|
|
1805
|
+
* `channelCapabilities` describes a Slack non-DM channel. The block is
|
|
1806
|
+
* non-persisted: history rebuilds re-derive it from storage on each
|
|
1807
|
+
* turn, and `RUNTIME_INJECTION_PREFIXES` strips any `<active_thread>`
|
|
1808
|
+
* blocks from prior turns so they do not accumulate.
|
|
1809
|
+
*
|
|
1810
|
+
* Callers build this via `loadSlackActiveThreadFocusBlock` (or the
|
|
1811
|
+
* underlying `assembleSlackActiveThreadFocusBlock`). Pass `null` /
|
|
1812
|
+
* `undefined` when the inbound is a top-level (non-thread) post.
|
|
1813
|
+
*/
|
|
1814
|
+
slackActiveThreadFocusBlock?: string | null;
|
|
1229
1815
|
mode?: InjectionMode;
|
|
1230
1816
|
},
|
|
1231
|
-
):
|
|
1817
|
+
): Promise<RuntimeInjectionResult> {
|
|
1232
1818
|
const mode = options.mode ?? "full";
|
|
1819
|
+
let pkbSystemReminderCaptured: string | undefined;
|
|
1820
|
+
const slackChannel = isSlackChannelConversation(options.channelCapabilities);
|
|
1821
|
+
// Slack DMs and channels both assemble context from persisted message
|
|
1822
|
+
// rows, so suppress hint injection for any Slack conversation. Other
|
|
1823
|
+
// channels (telegram, email, etc.) keep the generic hint pipeline.
|
|
1824
|
+
const slackConversation = options.channelCapabilities?.channel === "slack";
|
|
1825
|
+
let turnContextCaptured: string | undefined;
|
|
1233
1826
|
let result = runMessages;
|
|
1827
|
+
// Slack channels AND DMs both override `runMessages` with a pre-rendered
|
|
1828
|
+
// chronological transcript built from persisted message rows. The shared
|
|
1829
|
+
// assembler (`assembleSlackChronologicalMessages`) renders thread tags
|
|
1830
|
+
// for channels and a flat sequence for DMs, so the same branch handles
|
|
1831
|
+
// both. The active-thread focus block below stays gated on `slackChannel`
|
|
1832
|
+
// since DMs do not have threads.
|
|
1833
|
+
if (
|
|
1834
|
+
slackConversation &&
|
|
1835
|
+
options.slackChronologicalMessages &&
|
|
1836
|
+
options.slackChronologicalMessages.length > 0
|
|
1837
|
+
) {
|
|
1838
|
+
// `graphMemory.prepareMemory` prepends a `<memory __injected>` block
|
|
1839
|
+
// (and any memory-image groups) to the last user message before
|
|
1840
|
+
// runtime assembly runs. The Slack transcript is freshly rendered
|
|
1841
|
+
// from persisted rows and has no such prefix, so swap it in and then
|
|
1842
|
+
// re-prepend the captured prefix onto the new tail user message.
|
|
1843
|
+
const carriedMemoryBlocks = extractMemoryPrefixBlocks(runMessages);
|
|
1844
|
+
result = options.slackChronologicalMessages;
|
|
1845
|
+
if (carriedMemoryBlocks.length > 0) {
|
|
1846
|
+
const slackTail = result[result.length - 1];
|
|
1847
|
+
if (slackTail && slackTail.role === "user") {
|
|
1848
|
+
result = [
|
|
1849
|
+
...result.slice(0, -1),
|
|
1850
|
+
{
|
|
1851
|
+
...slackTail,
|
|
1852
|
+
content: [...carriedMemoryBlocks, ...slackTail.content],
|
|
1853
|
+
},
|
|
1854
|
+
];
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1234
1858
|
|
|
1235
1859
|
// For non-interactive conversations (scheduled jobs, work items), instruct the
|
|
1236
1860
|
// model to never ask for clarification — there is no human present to answer.
|
|
@@ -1274,17 +1898,90 @@ export function applyRuntimeInjections(
|
|
|
1274
1898
|
}
|
|
1275
1899
|
|
|
1276
1900
|
// PKB behavioral nudge — injected on every turn when PKB is active so
|
|
1277
|
-
// the model keeps reading topic files and calling `remember`.
|
|
1901
|
+
// the model keeps reading topic files and calling `remember`. When a
|
|
1902
|
+
// query vector is available from the graph memory retriever, run a
|
|
1903
|
+
// hybrid PKB search to surface up to three relevance hints; fall back
|
|
1904
|
+
// to the flat static reminder on empty results or any error.
|
|
1278
1905
|
if (mode === "full" && options.pkbActive) {
|
|
1279
1906
|
const userTail = result[result.length - 1];
|
|
1280
1907
|
if (userTail && userTail.role === "user") {
|
|
1908
|
+
let hints: string[] = [];
|
|
1909
|
+
const queryVector = options.pkbQueryVector;
|
|
1910
|
+
if (
|
|
1911
|
+
queryVector &&
|
|
1912
|
+
queryVector.length > 0 &&
|
|
1913
|
+
options.pkbScopeId &&
|
|
1914
|
+
options.pkbConversation &&
|
|
1915
|
+
options.pkbRoot
|
|
1916
|
+
) {
|
|
1917
|
+
try {
|
|
1918
|
+
const results = await searchPkbFiles(
|
|
1919
|
+
queryVector,
|
|
1920
|
+
options.pkbSparseVector,
|
|
1921
|
+
8,
|
|
1922
|
+
[options.pkbScopeId],
|
|
1923
|
+
);
|
|
1924
|
+
const workingDir = options.pkbWorkingDir ?? options.pkbRoot;
|
|
1925
|
+
const inContext = getInContextPkbPaths(
|
|
1926
|
+
options.pkbConversation,
|
|
1927
|
+
options.pkbAutoInjectList ?? [],
|
|
1928
|
+
options.pkbRoot,
|
|
1929
|
+
workingDir,
|
|
1930
|
+
);
|
|
1931
|
+
const pkbRoot = options.pkbRoot;
|
|
1932
|
+
// Gate on `denseScore` (cosine, [0, 1]) so the quality bar is stable
|
|
1933
|
+
// regardless of whether sparse was provided. Rank by `hybridScore`
|
|
1934
|
+
// (RRF) when available — that captures the sparse signal for
|
|
1935
|
+
// re-ordering eligible hits. hybridScore and denseScore live on
|
|
1936
|
+
// different scales, so items with hybridScore are ordered together
|
|
1937
|
+
// and placed ahead of items that only have denseScore.
|
|
1938
|
+
hints = results
|
|
1939
|
+
.filter((r) => {
|
|
1940
|
+
const abs = resolve(pkbRoot, r.path);
|
|
1941
|
+
if (inContext.has(abs)) return false;
|
|
1942
|
+
const threshold = r.path
|
|
1943
|
+
.replace(/\\/g, "/")
|
|
1944
|
+
.startsWith("archive/")
|
|
1945
|
+
? PKB_HINT_ARCHIVE_THRESHOLD
|
|
1946
|
+
: PKB_HINT_THRESHOLD;
|
|
1947
|
+
return r.denseScore >= threshold;
|
|
1948
|
+
})
|
|
1949
|
+
.sort((a, b) => {
|
|
1950
|
+
const aHasHybrid = a.hybridScore !== undefined;
|
|
1951
|
+
const bHasHybrid = b.hybridScore !== undefined;
|
|
1952
|
+
if (aHasHybrid && !bHasHybrid) return -1;
|
|
1953
|
+
if (!aHasHybrid && bHasHybrid) return 1;
|
|
1954
|
+
if (aHasHybrid && bHasHybrid) {
|
|
1955
|
+
return b.hybridScore! - a.hybridScore!;
|
|
1956
|
+
}
|
|
1957
|
+
return b.denseScore - a.denseScore;
|
|
1958
|
+
})
|
|
1959
|
+
.slice(0, 3)
|
|
1960
|
+
.map((r) => r.path);
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
pkbReminderLog.warn(
|
|
1963
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
1964
|
+
"PKB hint search failed — falling back to flat reminder",
|
|
1965
|
+
);
|
|
1966
|
+
hints = [];
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
const reminder = buildPkbReminder(hints);
|
|
1971
|
+
pkbSystemReminderCaptured = reminder;
|
|
1972
|
+
// Splice the reminder in right after the memory prefix blocks so it
|
|
1973
|
+
// lands above the user's typed text, producing the tail shape
|
|
1974
|
+
// `[<turn_context>, <memory __injected>, <system_reminder>, ...your_text, ...later_appends]`
|
|
1975
|
+
// after `unifiedTurnContext` later prepends `<turn_context>` at index 0.
|
|
1976
|
+
const memoryPrefixCount = countMemoryPrefixBlocks(userTail.content);
|
|
1281
1977
|
result = [
|
|
1282
1978
|
...result.slice(0, -1),
|
|
1283
1979
|
{
|
|
1284
1980
|
...userTail,
|
|
1285
1981
|
content: [
|
|
1286
|
-
...userTail.content,
|
|
1287
|
-
{ type: "text" as const, text:
|
|
1982
|
+
...userTail.content.slice(0, memoryPrefixCount),
|
|
1983
|
+
{ type: "text" as const, text: reminder },
|
|
1984
|
+
...userTail.content.slice(memoryPrefixCount),
|
|
1288
1985
|
],
|
|
1289
1986
|
},
|
|
1290
1987
|
];
|
|
@@ -1344,6 +2041,7 @@ export function applyRuntimeInjections(
|
|
|
1344
2041
|
if (options.unifiedTurnContext) {
|
|
1345
2042
|
const userTail = result[result.length - 1];
|
|
1346
2043
|
if (userTail && userTail.role === "user") {
|
|
2044
|
+
turnContextCaptured = options.unifiedTurnContext;
|
|
1347
2045
|
result = [
|
|
1348
2046
|
...result.slice(0, -1),
|
|
1349
2047
|
{
|
|
@@ -1357,8 +2055,15 @@ export function applyRuntimeInjections(
|
|
|
1357
2055
|
}
|
|
1358
2056
|
}
|
|
1359
2057
|
|
|
2058
|
+
// Slack conversations (both channels and DMs) build their own
|
|
2059
|
+
// chronological transcript from persisted messages and intentionally do
|
|
2060
|
+
// not receive the per-turn `<transport_hints>` block — the rendered
|
|
2061
|
+
// history already covers the active thread / DM, so duplicating it
|
|
2062
|
+
// would confuse the model. Other channels (telegram, email, etc.) keep
|
|
2063
|
+
// the existing injection.
|
|
1360
2064
|
if (
|
|
1361
2065
|
mode === "full" &&
|
|
2066
|
+
!slackConversation &&
|
|
1362
2067
|
options.transportHints &&
|
|
1363
2068
|
options.transportHints.length > 0
|
|
1364
2069
|
) {
|
|
@@ -1371,6 +2076,36 @@ export function applyRuntimeInjections(
|
|
|
1371
2076
|
}
|
|
1372
2077
|
}
|
|
1373
2078
|
|
|
2079
|
+
// Slack active-thread focus block: when the inbound user message lives
|
|
2080
|
+
// inside a thread, append a non-persisted `<active_thread>` tail block
|
|
2081
|
+
// listing that thread's parent + replies so the model can orient even
|
|
2082
|
+
// when the channel-wide chronological transcript is long and
|
|
2083
|
+
// interleaved. Stripped on subsequent rebuilds via the
|
|
2084
|
+
// `RUNTIME_INJECTION_PREFIXES` list so focus blocks never accumulate.
|
|
2085
|
+
if (
|
|
2086
|
+
mode === "full" &&
|
|
2087
|
+
slackChannel &&
|
|
2088
|
+
typeof options.slackActiveThreadFocusBlock === "string" &&
|
|
2089
|
+
options.slackActiveThreadFocusBlock.length > 0
|
|
2090
|
+
) {
|
|
2091
|
+
const userTail = result[result.length - 1];
|
|
2092
|
+
if (userTail && userTail.role === "user") {
|
|
2093
|
+
result = [
|
|
2094
|
+
...result.slice(0, -1),
|
|
2095
|
+
{
|
|
2096
|
+
...userTail,
|
|
2097
|
+
content: [
|
|
2098
|
+
...userTail.content,
|
|
2099
|
+
{
|
|
2100
|
+
type: "text" as const,
|
|
2101
|
+
text: options.slackActiveThreadFocusBlock,
|
|
2102
|
+
},
|
|
2103
|
+
],
|
|
2104
|
+
},
|
|
2105
|
+
];
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
|
|
1374
2109
|
// Workspace top-level context is injected last so it appears first
|
|
1375
2110
|
// (prepended) in the user message content, keeping cache breakpoints
|
|
1376
2111
|
// anchored to the trailing blocks.
|
|
@@ -1387,5 +2122,11 @@ export function applyRuntimeInjections(
|
|
|
1387
2122
|
}
|
|
1388
2123
|
}
|
|
1389
2124
|
|
|
1390
|
-
return
|
|
2125
|
+
return {
|
|
2126
|
+
messages: result,
|
|
2127
|
+
blocks: {
|
|
2128
|
+
unifiedTurnContext: turnContextCaptured,
|
|
2129
|
+
pkbSystemReminder: pkbSystemReminderCaptured,
|
|
2130
|
+
},
|
|
2131
|
+
};
|
|
1391
2132
|
}
|