@vellumai/assistant 0.6.4 → 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 +32 -36
- package/Dockerfile +12 -0
- package/README.md +3 -4
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- 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 +123 -11
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- 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 +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- 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__/browser-fill-credential.test.ts +1 -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 +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +428 -501
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- 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 +11 -28
- 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 +427 -114
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +530 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
- package/src/__tests__/conversation-agent-loop.test.ts +412 -82
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
- package/src/__tests__/conversation-queue.test.ts +41 -26
- package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +34 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +30 -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 +1 -1
- 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 +43 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- 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 +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- 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__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -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 +26 -7
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/model-intents.test.ts +9 -83
- 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-store.test.ts +10 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -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 +13 -13
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +50 -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__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/relay-server.test.ts +1 -1
- 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__/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 +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -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 +22 -35
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- 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 +2 -2
- package/src/__tests__/tool-executor.test.ts +60 -94
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- 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-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 +11 -11
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -13
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +209 -17
- 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/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/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -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__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- 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/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 +14 -1
- package/src/cli/commands/email.ts +234 -194
- 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/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -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 +23 -4
- package/src/cli.ts +0 -37
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
- 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/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -175
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +30 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- 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 +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +53 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +2 -2
- 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/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/window-manager.ts +229 -25
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- 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 +0 -1
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
- package/src/daemon/conversation-agent-loop.ts +462 -80
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-lifecycle.ts +30 -6
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-process.ts +10 -4
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +760 -29
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +10 -5
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +118 -30
- 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/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +2 -2
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +76 -14
- package/src/daemon/message-types/conversations.ts +14 -0
- package/src/daemon/message-types/messages.ts +9 -1
- 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 +117 -9
- package/src/daemon/tool-side-effects.ts +0 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +76 -28
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +4 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +56 -2
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- 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__/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 +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +4 -4
- 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 +17 -1
- 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/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +103 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +2 -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 +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +173 -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 +230 -48
- 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/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- 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 +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +1 -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/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -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/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/oauth/oauth-store.ts +1 -0
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/seed-providers.ts +4 -2
- 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 +217 -708
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +26 -78
- 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 +161 -62
- 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 -16
- package/src/platform/client.ts +19 -1
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- 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__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +501 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +76 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- 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 +93 -3
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -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 +52 -1
- package/src/runtime/http-types.ts +23 -1
- 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-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/vbundle-importer.ts +154 -9
- 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/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- 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/avatar-routes.ts +20 -4
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +133 -27
- 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/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- 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/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/migration-routes.ts +720 -124
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +28 -6
- package/src/schedule/scheduler.ts +8 -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 +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
- package/src/tools/browser/browser-execution.ts +65 -38
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- 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 +20 -10
- package/src/tools/network/web-search.ts +19 -4
- 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/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +12 -3
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +2 -2
- package/src/util/pricing.ts +15 -5
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- 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 +16 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- 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 -279
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- 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-detach.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-status.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 -49
- 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 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- 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 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- 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 -347
- 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 -108
- 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/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- 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 -139
- 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
|
@@ -102,6 +102,15 @@ export async function handleGuardianCallbackDecision(
|
|
|
102
102
|
approvalMessageTs,
|
|
103
103
|
} = params;
|
|
104
104
|
|
|
105
|
+
// Reactions have their own deterministic emoji-to-action mapping in
|
|
106
|
+
// `handleApprovalInterception`. Return null immediately so reaction
|
|
107
|
+
// callbackData never enters the conversational engine below, which would
|
|
108
|
+
// misclassify `reaction:white_check_mark` etc. as plain text and only
|
|
109
|
+
// ever produce `approve_once`/`reject`.
|
|
110
|
+
if (callbackData?.startsWith("reaction:")) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
105
114
|
// Callback/button path: deterministic and takes priority.
|
|
106
115
|
let callbackDecision: ApprovalDecisionResult | null = null;
|
|
107
116
|
if (callbackData) {
|
|
@@ -10,7 +10,7 @@ import { getAvatarImagePath } from "../../util/platform.js";
|
|
|
10
10
|
import { buildAssistantEvent } from "../assistant-event.js";
|
|
11
11
|
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
12
12
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
13
|
-
import { httpError } from "../http-errors.js";
|
|
13
|
+
import { httpError, type HttpErrorCode } from "../http-errors.js";
|
|
14
14
|
import type { RouteDefinition } from "../http-router.js";
|
|
15
15
|
|
|
16
16
|
const log = getLogger("avatar-routes");
|
|
@@ -78,9 +78,25 @@ export function avatarRouteDefinitions(): RouteDefinition[] {
|
|
|
78
78
|
const result = writeTraitsAndRenderAvatar(body);
|
|
79
79
|
|
|
80
80
|
if (!result.ok) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
// Map each failure reason to an HTTP status that reflects its
|
|
82
|
+
// cause: invalid inputs → 400, missing native dependency → 503,
|
|
83
|
+
// everything else → 500.
|
|
84
|
+
let status: number;
|
|
85
|
+
let code: HttpErrorCode;
|
|
86
|
+
switch (result.reason) {
|
|
87
|
+
case "invalid_traits":
|
|
88
|
+
status = 400;
|
|
89
|
+
code = "BAD_REQUEST";
|
|
90
|
+
break;
|
|
91
|
+
case "native_unavailable":
|
|
92
|
+
status = 503;
|
|
93
|
+
code = "SERVICE_UNAVAILABLE";
|
|
94
|
+
break;
|
|
95
|
+
case "render_error":
|
|
96
|
+
status = 500;
|
|
97
|
+
code = "INTERNAL_ERROR";
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
84
100
|
return httpError(code, result.message, status);
|
|
85
101
|
}
|
|
86
102
|
|
|
@@ -16,7 +16,6 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
16
16
|
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
|
|
19
|
-
import { getConfig } from "../../config/loader.js";
|
|
20
19
|
import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
|
|
21
20
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
22
21
|
import { resolvePersonaContext } from "../../prompts/persona-resolver.js";
|
|
@@ -178,9 +177,7 @@ async function handleBtw(
|
|
|
178
177
|
userPersona,
|
|
179
178
|
channelPersona,
|
|
180
179
|
userSlug,
|
|
181
|
-
...(isGreeting
|
|
182
|
-
? { modelIntent: getConfig().ui.greetingModelIntent }
|
|
183
|
-
: {}),
|
|
180
|
+
...(isGreeting ? { callSite: "emptyStateGreeting" as const } : {}),
|
|
184
181
|
onEvent: (event) => {
|
|
185
182
|
if (event.type === "text_delta") {
|
|
186
183
|
controller.enqueue(
|
|
@@ -386,8 +386,13 @@ export function conversationManagementRouteDefinitions(
|
|
|
386
386
|
);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
// Broadcast conversation_title_updated so
|
|
390
|
-
//
|
|
389
|
+
// Broadcast conversation_title_updated so the client currently
|
|
390
|
+
// viewing this conversation can update the header in-place.
|
|
391
|
+
// Scoped to the conversation id so foreign conversationId values
|
|
392
|
+
// don't leak to other subscribers' speculative ID-resolution
|
|
393
|
+
// paths. Other clients learn about the rename via the unscoped
|
|
394
|
+
// `conversation_list_invalidated` published below, which triggers
|
|
395
|
+
// their sidebars to refetch and pick up the new title.
|
|
391
396
|
assistantEventHub
|
|
392
397
|
.publish(
|
|
393
398
|
buildAssistantEvent(
|
|
@@ -752,6 +757,19 @@ export function conversationManagementRouteDefinitions(
|
|
|
752
757
|
groupId: u.groupId,
|
|
753
758
|
})),
|
|
754
759
|
);
|
|
760
|
+
assistantEventHub
|
|
761
|
+
.publish(
|
|
762
|
+
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
763
|
+
type: "conversation_list_invalidated",
|
|
764
|
+
reason: "reordered",
|
|
765
|
+
}),
|
|
766
|
+
)
|
|
767
|
+
.catch((err) => {
|
|
768
|
+
log.warn(
|
|
769
|
+
{ err },
|
|
770
|
+
"Failed to publish conversation_list_invalidated (reordered)",
|
|
771
|
+
);
|
|
772
|
+
});
|
|
755
773
|
return Response.json({ ok: true });
|
|
756
774
|
},
|
|
757
775
|
},
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
getLastAssistantTimestampBefore,
|
|
66
66
|
getMessages,
|
|
67
67
|
getMessagesPaginated,
|
|
68
|
+
hasMessages,
|
|
68
69
|
type MessageRow,
|
|
69
70
|
provenanceFromTrustContext,
|
|
70
71
|
setConversationOriginChannelIfUnset,
|
|
@@ -1066,7 +1067,20 @@ function makeHubPublisher(
|
|
|
1066
1067
|
typeof (msg as { conversationId?: unknown }).conversationId === "string"
|
|
1067
1068
|
? (msg as { conversationId: string }).conversationId
|
|
1068
1069
|
: undefined;
|
|
1069
|
-
|
|
1070
|
+
// `conversation_list_invalidated` is a list-level system event: it
|
|
1071
|
+
// describes no particular conversation and every connected client
|
|
1072
|
+
// should refresh its sidebar. Publish it unscoped so the SSE hub does
|
|
1073
|
+
// not filter it out by the subscriber's `filter.conversationId`.
|
|
1074
|
+
// Other events (including `conversation_title_updated`) stay scoped to
|
|
1075
|
+
// their conversation — unscoped scoped-events would leak foreign
|
|
1076
|
+
// `conversationId` values to native clients' speculative ID-resolution
|
|
1077
|
+
// path. For `conversation_title_updated` we instead enqueue a matching
|
|
1078
|
+
// unscoped `conversation_list_invalidated` below so other clients'
|
|
1079
|
+
// sidebars can refresh and pick up the new title.
|
|
1080
|
+
const resolvedConversationId =
|
|
1081
|
+
msg.type === "conversation_list_invalidated"
|
|
1082
|
+
? undefined
|
|
1083
|
+
: (msgConversationId ?? conversationId);
|
|
1070
1084
|
const event = buildAssistantEvent(
|
|
1071
1085
|
DAEMON_INTERNAL_ASSISTANT_ID,
|
|
1072
1086
|
msg,
|
|
@@ -1082,6 +1096,29 @@ function makeHubPublisher(
|
|
|
1082
1096
|
"assistant-events hub subscriber threw during POST /messages",
|
|
1083
1097
|
);
|
|
1084
1098
|
}
|
|
1099
|
+
|
|
1100
|
+
// When the agent loop auto-generates a conversation title, also
|
|
1101
|
+
// broadcast an unscoped `conversation_list_invalidated` so every
|
|
1102
|
+
// connected client's sidebar can refresh and pick up the new title.
|
|
1103
|
+
// Without this, clients viewing other conversations (or a draft)
|
|
1104
|
+
// would never learn that the title for this conversation changed.
|
|
1105
|
+
// The scoped `conversation_title_updated` above still handles the
|
|
1106
|
+
// in-place update for the client currently viewing this conversation.
|
|
1107
|
+
if (msg.type === "conversation_title_updated") {
|
|
1108
|
+
try {
|
|
1109
|
+
await deps.assistantEventHub.publish(
|
|
1110
|
+
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
1111
|
+
type: "conversation_list_invalidated",
|
|
1112
|
+
reason: "renamed",
|
|
1113
|
+
}),
|
|
1114
|
+
);
|
|
1115
|
+
} catch (err) {
|
|
1116
|
+
log.warn(
|
|
1117
|
+
{ err },
|
|
1118
|
+
"Failed to publish conversation_list_invalidated after title update",
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1085
1122
|
})();
|
|
1086
1123
|
};
|
|
1087
1124
|
}
|
|
@@ -1302,6 +1339,7 @@ export async function handleSendMessage(
|
|
|
1302
1339
|
bypassSecretCheck?: boolean;
|
|
1303
1340
|
hostHomeDir?: string;
|
|
1304
1341
|
hostUsername?: string;
|
|
1342
|
+
clientMessageId?: string;
|
|
1305
1343
|
onboarding?: {
|
|
1306
1344
|
tools: string[];
|
|
1307
1345
|
tasks: string[];
|
|
@@ -1312,6 +1350,8 @@ export async function handleSendMessage(
|
|
|
1312
1350
|
};
|
|
1313
1351
|
|
|
1314
1352
|
const { conversationKey, content, attachmentIds } = body;
|
|
1353
|
+
const clientMessageId =
|
|
1354
|
+
typeof body.clientMessageId === "string" ? body.clientMessageId : undefined;
|
|
1315
1355
|
if (!body.sourceChannel || typeof body.sourceChannel !== "string") {
|
|
1316
1356
|
return httpError("BAD_REQUEST", "sourceChannel is required", 400);
|
|
1317
1357
|
}
|
|
@@ -1414,19 +1454,27 @@ export async function handleSendMessage(
|
|
|
1414
1454
|
|
|
1415
1455
|
const smDeps = deps.sendMessageDeps;
|
|
1416
1456
|
|
|
1417
|
-
// Notify all connected clients that the conversation list changed when
|
|
1418
|
-
//
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
.
|
|
1428
|
-
|
|
1429
|
-
|
|
1457
|
+
// Notify all connected clients that the conversation list changed when
|
|
1458
|
+
// this is the first message in a standard conversation, so sidebars on
|
|
1459
|
+
// other devices can refresh. We check for first-message rather than
|
|
1460
|
+
// first-create because the SSE subscribe handler (events-routes.ts) may
|
|
1461
|
+
// have already materialised the conversation from a draft key before any
|
|
1462
|
+
// message was sent — in that case `mapping.created` is `false` even
|
|
1463
|
+
// though, from the user's perspective, this is a brand-new conversation
|
|
1464
|
+
// that other clients don't yet know about.
|
|
1465
|
+
if (mapping.conversationType === "standard") {
|
|
1466
|
+
if (!hasMessages(mapping.conversationId)) {
|
|
1467
|
+
smDeps.assistantEventHub
|
|
1468
|
+
.publish(
|
|
1469
|
+
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
1470
|
+
type: "conversation_list_invalidated",
|
|
1471
|
+
reason: "created",
|
|
1472
|
+
}),
|
|
1473
|
+
)
|
|
1474
|
+
.catch((err) => {
|
|
1475
|
+
log.warn({ err }, "Failed to publish conversation_list_invalidated");
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1430
1478
|
}
|
|
1431
1479
|
|
|
1432
1480
|
// Build transport metadata from the request so the daemon can inject
|
|
@@ -1720,6 +1768,7 @@ export async function handleSendMessage(
|
|
|
1720
1768
|
text: rawContent,
|
|
1721
1769
|
conversationId,
|
|
1722
1770
|
messageId: persisted.id,
|
|
1771
|
+
clientMessageId,
|
|
1723
1772
|
});
|
|
1724
1773
|
onEvent({ type: "assistant_text_delta", text: cannedGreeting });
|
|
1725
1774
|
onEvent({ type: "message_complete", conversationId });
|
|
@@ -1817,6 +1866,7 @@ export async function handleSendMessage(
|
|
|
1817
1866
|
{ isInteractive },
|
|
1818
1867
|
undefined, // displayContent
|
|
1819
1868
|
transport,
|
|
1869
|
+
clientMessageId,
|
|
1820
1870
|
);
|
|
1821
1871
|
if (enqueueResult.rejected) {
|
|
1822
1872
|
return Response.json(
|
|
@@ -1929,9 +1979,9 @@ export async function handleSendMessage(
|
|
|
1929
1979
|
messageCount: conversation.getMessages().length,
|
|
1930
1980
|
inputTokens: conversation.usageStats.inputTokens,
|
|
1931
1981
|
outputTokens: conversation.usageStats.outputTokens,
|
|
1932
|
-
maxInputTokens: config.contextWindow.maxInputTokens,
|
|
1933
|
-
model: config.
|
|
1934
|
-
provider: config.
|
|
1982
|
+
maxInputTokens: config.llm.default.contextWindow.maxInputTokens,
|
|
1983
|
+
model: config.llm.default.model,
|
|
1984
|
+
provider: config.llm.default.provider,
|
|
1935
1985
|
estimatedCost: conversation.usageStats.estimatedCost,
|
|
1936
1986
|
userMessageInterface: sourceInterface,
|
|
1937
1987
|
};
|
|
@@ -2019,6 +2069,7 @@ export async function handleSendMessage(
|
|
|
2019
2069
|
text: rawContent,
|
|
2020
2070
|
conversationId,
|
|
2021
2071
|
messageId: persisted.id,
|
|
2072
|
+
clientMessageId,
|
|
2022
2073
|
});
|
|
2023
2074
|
if (modelInfoEvent) {
|
|
2024
2075
|
onEvent(modelInfoEvent);
|
|
@@ -2075,6 +2126,7 @@ export async function handleSendMessage(
|
|
|
2075
2126
|
text: rawContent,
|
|
2076
2127
|
conversationId,
|
|
2077
2128
|
messageId: persisted.id,
|
|
2129
|
+
clientMessageId,
|
|
2078
2130
|
});
|
|
2079
2131
|
conversation.emitActivityState(
|
|
2080
2132
|
"thinking",
|
|
@@ -2144,6 +2196,7 @@ export async function handleSendMessage(
|
|
|
2144
2196
|
conversationId: mapping.conversationId,
|
|
2145
2197
|
messageId,
|
|
2146
2198
|
requestId,
|
|
2199
|
+
clientMessageId,
|
|
2147
2200
|
});
|
|
2148
2201
|
|
|
2149
2202
|
// Fire-and-forget the agent loop; events flow to the hub via onEvent.
|
|
@@ -2165,28 +2218,62 @@ export async function handleSendMessage(
|
|
|
2165
2218
|
);
|
|
2166
2219
|
}
|
|
2167
2220
|
|
|
2221
|
+
function escapeXmlContent(text: string): string {
|
|
2222
|
+
return text
|
|
2223
|
+
.replace(/&/g, "&")
|
|
2224
|
+
.replace(/</g, "<")
|
|
2225
|
+
.replace(/>/g, ">");
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2168
2228
|
async function generateLlmSuggestion(
|
|
2169
2229
|
provider: Provider,
|
|
2170
2230
|
assistantText: string,
|
|
2231
|
+
priorUserText: string | null,
|
|
2171
2232
|
): Promise<string | null> {
|
|
2172
2233
|
const log = (await import("../../util/logger.js")).getLogger("runtime-http");
|
|
2173
|
-
const
|
|
2174
|
-
assistantText.length > 2000 ? assistantText.slice(-2000) : assistantText
|
|
2234
|
+
const truncatedAssistant = escapeXmlContent(
|
|
2235
|
+
assistantText.length > 2000 ? assistantText.slice(-2000) : assistantText,
|
|
2236
|
+
);
|
|
2237
|
+
const truncatedUser =
|
|
2238
|
+
priorUserText && priorUserText.length > 500
|
|
2239
|
+
? escapeXmlContent(priorUserText.slice(-500))
|
|
2240
|
+
: priorUserText
|
|
2241
|
+
? escapeXmlContent(priorUserText)
|
|
2242
|
+
: priorUserText;
|
|
2175
2243
|
|
|
2176
|
-
const prompt = `Given this assistant message, write a very short tab-complete suggestion the user could send next. Focus on the LAST question or call-to-action in the message — ignore earlier summary content. Be casual, curious, or actionable — like a quick reply, not a formal request. Reply with ONLY the suggestion text.\n\nAssistant's message:\n${truncated}`;
|
|
2177
2244
|
const systemPrompt =
|
|
2178
|
-
"You
|
|
2245
|
+
"You generate short, casual reply suggestions a user might type next in a chat. Match the tone and register of the preceding conversation. Output only the reply text inside the requested tags — no preamble, no commentary.";
|
|
2246
|
+
|
|
2247
|
+
const userPrompt =
|
|
2248
|
+
`Here is the end of a conversation:\n\n` +
|
|
2249
|
+
`<user_message>${truncatedUser ?? "(no prior user message)"}</user_message>\n` +
|
|
2250
|
+
`<assistant_message>${truncatedAssistant}</assistant_message>\n\n` +
|
|
2251
|
+
`Write the user's next reply, focusing on the LAST question or call-to-action in the assistant message. Keep it short (under 15 words), casual, and in the user's voice. Respond in this exact format:\n\n` +
|
|
2252
|
+
`<reply>YOUR_REPLY_HERE</reply>`;
|
|
2179
2253
|
|
|
2180
2254
|
const response = await provider.sendMessage(
|
|
2181
|
-
[
|
|
2255
|
+
[
|
|
2256
|
+
{ role: "user", content: [{ type: "text", text: userPrompt }] },
|
|
2257
|
+
{ role: "assistant", content: [{ type: "text", text: "<reply>" }] },
|
|
2258
|
+
],
|
|
2182
2259
|
[], // no tools
|
|
2183
2260
|
systemPrompt,
|
|
2184
|
-
{
|
|
2261
|
+
{
|
|
2262
|
+
config: {
|
|
2263
|
+
callSite: "conversationStarters",
|
|
2264
|
+
max_tokens: 60,
|
|
2265
|
+
stop_sequences: ["</reply>"],
|
|
2266
|
+
temperature: 0.7,
|
|
2267
|
+
},
|
|
2268
|
+
},
|
|
2185
2269
|
);
|
|
2186
2270
|
|
|
2187
2271
|
const textBlock = response.content.find((b) => b.type === "text");
|
|
2188
|
-
const raw = textBlock && "text" in textBlock ? textBlock.text
|
|
2189
|
-
const stripped = raw
|
|
2272
|
+
const raw = textBlock && "text" in textBlock ? textBlock.text : "";
|
|
2273
|
+
const stripped = raw
|
|
2274
|
+
.replace(/<\/?reply>/gi, "")
|
|
2275
|
+
.replace(/^["'`]+|["'`]+$/g, "")
|
|
2276
|
+
.trim();
|
|
2190
2277
|
|
|
2191
2278
|
if (!stripped) {
|
|
2192
2279
|
log.debug("Suggestion rejected: empty LLM response");
|
|
@@ -2299,14 +2386,33 @@ export async function handleGetSuggestion(
|
|
|
2299
2386
|
});
|
|
2300
2387
|
}
|
|
2301
2388
|
|
|
2389
|
+
// Find the most recent user message preceding this assistant turn so the
|
|
2390
|
+
// suggestion model can see both sides of the conversation and doesn't have
|
|
2391
|
+
// to guess which role it's generating for.
|
|
2392
|
+
let priorUserText: string | null = null;
|
|
2393
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
2394
|
+
if (rawMessages[j].role !== "user") continue;
|
|
2395
|
+
let userContent: unknown;
|
|
2396
|
+
try {
|
|
2397
|
+
userContent = JSON.parse(rawMessages[j].content);
|
|
2398
|
+
} catch {
|
|
2399
|
+
userContent = rawMessages[j].content;
|
|
2400
|
+
}
|
|
2401
|
+
const userText = renderHistoryContent(userContent).text.trim();
|
|
2402
|
+
if (userText) {
|
|
2403
|
+
priorUserText = userText;
|
|
2404
|
+
break;
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2302
2408
|
// Try LLM suggestion using the configured provider
|
|
2303
|
-
const provider = await getConfiguredProvider();
|
|
2409
|
+
const provider = await getConfiguredProvider("conversationStarters");
|
|
2304
2410
|
if (provider) {
|
|
2305
2411
|
try {
|
|
2306
2412
|
// Deduplicate concurrent requests
|
|
2307
2413
|
let promise = suggestionInFlight.get(msg.id);
|
|
2308
2414
|
if (!promise) {
|
|
2309
|
-
promise = generateLlmSuggestion(provider, text);
|
|
2415
|
+
promise = generateLlmSuggestion(provider, text, priorUserText);
|
|
2310
2416
|
suggestionInFlight.set(msg.id, promise);
|
|
2311
2417
|
}
|
|
2312
2418
|
|
|
@@ -65,7 +65,7 @@ function handleDebug(): Response {
|
|
|
65
65
|
startedAt: new Date(startedAt).toISOString(),
|
|
66
66
|
},
|
|
67
67
|
provider: {
|
|
68
|
-
configuredProvider: config.
|
|
68
|
+
configuredProvider: config.llm.default.provider,
|
|
69
69
|
registeredProviders,
|
|
70
70
|
routingSources,
|
|
71
71
|
inferenceMode: config.services.inference.mode,
|
|
@@ -222,7 +222,7 @@ async function handleDictation(body: DictationBody): Promise<Response> {
|
|
|
222
222
|
const transcription = expandSnippets(body.transcription, profile.snippets);
|
|
223
223
|
|
|
224
224
|
try {
|
|
225
|
-
const provider = await getConfiguredProvider();
|
|
225
|
+
const provider = await getConfiguredProvider("interactionClassifier");
|
|
226
226
|
if (!provider) {
|
|
227
227
|
log.warn(
|
|
228
228
|
"Dictation: no provider available, using heuristic + raw transcription",
|
|
@@ -288,7 +288,7 @@ async function handleDictation(body: DictationBody): Promise<Response> {
|
|
|
288
288
|
systemPrompt,
|
|
289
289
|
{
|
|
290
290
|
config: {
|
|
291
|
-
|
|
291
|
+
callSite: "interactionClassifier",
|
|
292
292
|
max_tokens: maxTokens,
|
|
293
293
|
tool_choice: {
|
|
294
294
|
type: "tool" as const,
|
|
@@ -381,7 +381,7 @@ async function handleCommandMode(
|
|
|
381
381
|
const maxTokens = Math.max(1024, computeMaxTokens(inputLength));
|
|
382
382
|
|
|
383
383
|
try {
|
|
384
|
-
const provider = await getConfiguredProvider();
|
|
384
|
+
const provider = await getConfiguredProvider("interactionClassifier");
|
|
385
385
|
if (!provider) {
|
|
386
386
|
log.warn("Command mode: no provider available, returning selected text");
|
|
387
387
|
const normalizedText = applyDictionary(
|
|
@@ -399,7 +399,9 @@ async function handleCommandMode(
|
|
|
399
399
|
[userMessage(body.transcription)],
|
|
400
400
|
[],
|
|
401
401
|
systemPrompt,
|
|
402
|
-
{
|
|
402
|
+
{
|
|
403
|
+
config: { callSite: "interactionClassifier", max_tokens: maxTokens },
|
|
404
|
+
},
|
|
403
405
|
);
|
|
404
406
|
|
|
405
407
|
const textBlock = response.content.find((b) => b.type === "text");
|
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
* When `conversationKey` is provided, subscribers receive events scoped to
|
|
11
11
|
* that conversation. When omitted, subscribers receive events from ALL
|
|
12
12
|
* conversations for this assistant (unfiltered).
|
|
13
|
+
*
|
|
14
|
+
* If the conversationKey has no server-side mapping yet (e.g. a client-
|
|
15
|
+
* generated draft UUID that has not been sent a first message), this
|
|
16
|
+
* handler eagerly materialises the conversation so the subscriber's
|
|
17
|
+
* `filter.conversationId` matches the id under which the first turn's
|
|
18
|
+
* scoped events (text deltas, tool calls, message_complete) will be
|
|
19
|
+
* published by `handleSendMessage`. The `conversation_list_invalidated`
|
|
20
|
+
* notification for other clients is driven by `handleSendMessage`'s
|
|
21
|
+
* first-message check, so eager materialisation here is safe and does
|
|
22
|
+
* not hide the first-message notification from other clients.
|
|
13
23
|
*/
|
|
14
24
|
|
|
15
25
|
import { getOrCreateConversation } from "../../memory/conversation-key-store.js";
|
|
@@ -75,6 +85,12 @@ export function handleSubscribeAssistantEvents(
|
|
|
75
85
|
assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
|
|
76
86
|
};
|
|
77
87
|
if (conversationKey) {
|
|
88
|
+
// Eagerly resolve (and if necessary create) the conversation so the
|
|
89
|
+
// subscriber's filter matches the id under which first-turn scoped
|
|
90
|
+
// events will be published. The `conversation_list_invalidated`
|
|
91
|
+
// publish is driven by `handleSendMessage`'s first-message check,
|
|
92
|
+
// so eager materialisation here is safe and does not suppress the
|
|
93
|
+
// cross-client notification.
|
|
78
94
|
const mapping = getOrCreateConversation(conversationKey);
|
|
79
95
|
filter.conversationId = mapping.conversationId;
|
|
80
96
|
}
|
|
@@ -31,6 +31,7 @@ import type {
|
|
|
31
31
|
ApprovalCopyGenerator,
|
|
32
32
|
} from "../http-types.js";
|
|
33
33
|
import { parseApprovalIntent } from "../nl-approval-parser.js";
|
|
34
|
+
import { isTrackedApprovalPromptTs } from "./approval-prompt-ts-tracker.js";
|
|
34
35
|
import { handleGuardianCallbackDecision } from "./approval-strategies/guardian-callback-strategy.js";
|
|
35
36
|
import { handleGuardianTextEngineDecision } from "./approval-strategies/guardian-text-engine-strategy.js";
|
|
36
37
|
import {
|
|
@@ -139,7 +140,15 @@ export async function handleApprovalInterception(
|
|
|
139
140
|
// so getChannelApprovalPrompt(conversationId) would return null.
|
|
140
141
|
// Only guardians can approve via reaction — non-guardian reactions are
|
|
141
142
|
// silently ignored to prevent self-approval.
|
|
142
|
-
|
|
143
|
+
//
|
|
144
|
+
// `reaction_removed:` callbackData never expresses an approval intent, and
|
|
145
|
+
// `isSlackReactionEvent` short-circuits before reaching here for removals,
|
|
146
|
+
// but guard explicitly so a future refactor can't turn an un-react into an
|
|
147
|
+
// unintended approval.
|
|
148
|
+
if (
|
|
149
|
+
callbackData?.startsWith("reaction:") &&
|
|
150
|
+
!callbackData.startsWith("reaction_removed:")
|
|
151
|
+
) {
|
|
143
152
|
if (trustCtx.trustClass !== "guardian" || !actorExternalId) {
|
|
144
153
|
return { handled: true, type: "stale_ignored" };
|
|
145
154
|
}
|
|
@@ -149,6 +158,23 @@ export async function handleApprovalInterception(
|
|
|
149
158
|
return { handled: true, type: "stale_ignored" };
|
|
150
159
|
}
|
|
151
160
|
|
|
161
|
+
// Require the reacted-to message to be a tracked approval prompt. Without
|
|
162
|
+
// this check, any unrelated 👍 reaction from the guardian in a subscribed
|
|
163
|
+
// channel would approve the outstanding pending request (now that
|
|
164
|
+
// reactions are admitted from any subscribed channel, not just tracked
|
|
165
|
+
// bot threads). `approvalMessageTs` is `item.ts` of the reacted-to
|
|
166
|
+
// Slack message, propagated from `sourceMetadata.messageId`.
|
|
167
|
+
if (
|
|
168
|
+
!approvalMessageTs ||
|
|
169
|
+
!isTrackedApprovalPromptTs(
|
|
170
|
+
sourceChannel,
|
|
171
|
+
conversationExternalId,
|
|
172
|
+
approvalMessageTs,
|
|
173
|
+
)
|
|
174
|
+
) {
|
|
175
|
+
return { handled: true, type: "stale_ignored" };
|
|
176
|
+
}
|
|
177
|
+
|
|
152
178
|
const allPending = getAllPendingApprovalsByGuardianChat(
|
|
153
179
|
sourceChannel,
|
|
154
180
|
conversationExternalId,
|
|
@@ -493,8 +519,12 @@ export async function handleApprovalInterception(
|
|
|
493
519
|
// ── Slack reaction path ──
|
|
494
520
|
// Reactions produce `callbackData` of the form `reaction:<emoji_name>`.
|
|
495
521
|
// Only guardians can approve via reaction — non-guardian reactions are
|
|
496
|
-
// silently ignored to prevent self-approval.
|
|
497
|
-
|
|
522
|
+
// silently ignored to prevent self-approval. `reaction_removed:` never
|
|
523
|
+
// expresses an approval intent.
|
|
524
|
+
if (
|
|
525
|
+
callbackData?.startsWith("reaction:") &&
|
|
526
|
+
!callbackData.startsWith("reaction_removed:")
|
|
527
|
+
) {
|
|
498
528
|
if (trustCtx.trustClass !== "guardian") {
|
|
499
529
|
return { handled: true, type: "stale_ignored" };
|
|
500
530
|
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "../gateway-client.js";
|
|
18
18
|
import { buildActionLegend } from "../guardian-decision-types.js";
|
|
19
19
|
import type { ApprovalCopyGenerator } from "../http-types.js";
|
|
20
|
+
import { trackApprovalPromptTs } from "./approval-prompt-ts-tracker.js";
|
|
20
21
|
import { requiredDecisionKeywords } from "./channel-route-shared.js";
|
|
21
22
|
|
|
22
23
|
const log = getLogger("runtime-http");
|
|
@@ -141,7 +142,7 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
try {
|
|
144
|
-
await deliverApprovalPrompt(
|
|
145
|
+
const deliveryResult = await deliverApprovalPrompt(
|
|
145
146
|
replyCallbackUrl,
|
|
146
147
|
chatId,
|
|
147
148
|
enrichedText,
|
|
@@ -149,6 +150,9 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
149
150
|
assistantId,
|
|
150
151
|
bearerToken,
|
|
151
152
|
);
|
|
153
|
+
if (deliveryResult.ts) {
|
|
154
|
+
trackApprovalPromptTs(sourceChannel, chatId, deliveryResult.ts);
|
|
155
|
+
}
|
|
152
156
|
return true;
|
|
153
157
|
} catch (err) {
|
|
154
158
|
log.error(
|
|
@@ -168,7 +172,7 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
168
172
|
const taggedFallback = `${plainTextFallback}\n[ref:${uiMetadata.requestId}]`;
|
|
169
173
|
|
|
170
174
|
try {
|
|
171
|
-
await deliverChannelReply(
|
|
175
|
+
const fallbackResult = await deliverChannelReply(
|
|
172
176
|
replyCallbackUrl,
|
|
173
177
|
{
|
|
174
178
|
chatId,
|
|
@@ -177,6 +181,9 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
177
181
|
},
|
|
178
182
|
bearerToken,
|
|
179
183
|
);
|
|
184
|
+
if (fallbackResult.ts) {
|
|
185
|
+
trackApprovalPromptTs(sourceChannel, chatId, fallbackResult.ts);
|
|
186
|
+
}
|
|
180
187
|
return true;
|
|
181
188
|
} catch (err) {
|
|
182
189
|
log.error(
|
|
@@ -197,7 +204,7 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
197
204
|
const taggedPlainText = `${plainText}\n[ref:${uiMetadata.requestId}]`;
|
|
198
205
|
|
|
199
206
|
try {
|
|
200
|
-
await deliverChannelReply(
|
|
207
|
+
const plainResult = await deliverChannelReply(
|
|
201
208
|
replyCallbackUrl,
|
|
202
209
|
{
|
|
203
210
|
chatId,
|
|
@@ -206,6 +213,9 @@ export async function deliverGeneratedApprovalPrompt(
|
|
|
206
213
|
},
|
|
207
214
|
bearerToken,
|
|
208
215
|
);
|
|
216
|
+
if (plainResult.ts) {
|
|
217
|
+
trackApprovalPromptTs(sourceChannel, chatId, plainResult.ts);
|
|
218
|
+
}
|
|
209
219
|
return true;
|
|
210
220
|
} catch (err) {
|
|
211
221
|
log.error(
|