@vellumai/assistant 0.8.5 → 0.8.7-dev.202606052118.34cd356
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -1
- package/ARCHITECTURE.md +1 -1
- package/Dockerfile +21 -4
- package/bun.lock +13 -4
- package/bunfig.toml +6 -1
- package/docker-entrypoint.sh +12 -8
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +114 -86
- package/examples/plugins/echo/README.md +13 -12
- package/examples/plugins/echo/register.ts +0 -54
- package/knip.json +1 -0
- package/node_modules/@vellumai/environments/bun.lock +24 -0
- package/node_modules/@vellumai/environments/package.json +18 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
- package/node_modules/@vellumai/environments/src/index.ts +11 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
- package/node_modules/@vellumai/environments/src/types.ts +70 -0
- package/node_modules/@vellumai/environments/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +15 -17
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +15 -7
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +8748 -589
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +88 -54
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
- package/src/__tests__/agent-loop-exit-reason.test.ts +284 -48
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +21 -33
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +7 -5
- package/src/__tests__/agent-loop-thinking.test.ts +17 -12
- package/src/__tests__/agent-loop.test.ts +238 -422
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +7 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -40
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +3 -3
- package/src/__tests__/anthropic-provider.test.ts +296 -57
- package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
- package/src/__tests__/app-control-flow.test.ts +6 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +5 -11
- package/src/__tests__/approval-routes-http.test.ts +17 -16
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-event.test.ts +15 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -27
- package/src/__tests__/assistant-stream-state.test.ts +645 -0
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/avatar-e2e.test.ts +7 -37
- package/src/__tests__/avatar-generator.test.ts +12 -42
- package/src/__tests__/avatar-identity-sync.test.ts +28 -3
- package/src/__tests__/background-shell-bash.test.ts +3 -7
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +72 -17
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/call-pointer-messages.test.ts +5 -3
- package/src/__tests__/call-site-routing-provider.test.ts +22 -40
- package/src/__tests__/catalog-files.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +52 -23
- package/src/__tests__/channel-approvals.test.ts +4 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-invite-transport.test.ts +1 -5
- package/src/__tests__/channel-readiness-routes.test.ts +0 -4
- package/src/__tests__/channel-readiness-slack-remote.test.ts +170 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +388 -79
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/clawhub-files.test.ts +1 -0
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +6 -17
- package/src/__tests__/compaction-trail-store.test.ts +186 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +14 -16
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/config-watcher.test.ts +28 -0
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-search-agent-runner.test.ts +6 -3
- package/src/__tests__/context-token-estimator.test.ts +56 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +73 -23
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +23 -34
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +477 -930
- package/src/__tests__/conversation-agent-loop.test.ts +1056 -1068
- package/src/__tests__/conversation-analysis-routes.test.ts +8 -3
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -1
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-clear-safety.test.ts +20 -10
- package/src/__tests__/conversation-confirmation-signals.test.ts +16 -45
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +10 -17
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +132 -157
- package/src/__tests__/conversation-fork-route.test.ts +19 -16
- package/src/__tests__/conversation-history-web-search.test.ts +12 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
- package/src/__tests__/conversation-lifecycle.test.ts +4 -2
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -3
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -1
- package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
- package/src/__tests__/conversation-pairing.test.ts +60 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +36 -7
- package/src/__tests__/conversation-process-callsite.test.ts +28 -30
- package/src/__tests__/conversation-provider-retry-repair.test.ts +85 -51
- package/src/__tests__/conversation-queue.test.ts +605 -455
- package/src/__tests__/conversation-routes-disk-view.test.ts +9 -20
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +35 -10
- package/src/__tests__/conversation-routes-slash-commands.test.ts +40 -8
- package/src/__tests__/conversation-runtime-assembly.test.ts +395 -313
- package/src/__tests__/conversation-runtime-workspace.test.ts +114 -36
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +125 -62
- package/src/__tests__/conversation-slash-unknown.test.ts +18 -15
- package/src/__tests__/conversation-speed-override.test.ts +9 -22
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +136 -15
- package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-table-action.test.ts +13 -32
- package/src/__tests__/conversation-sync-tags.test.ts +140 -12
- package/src/__tests__/conversation-title-service.test.ts +136 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +53 -11
- package/src/__tests__/conversation-unread-route.test.ts +14 -2
- package/src/__tests__/conversation-usage.test.ts +1 -2
- package/src/__tests__/conversation-wipe.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +21 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +119 -23
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +39 -13
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-execution-tools.test.ts +1 -2
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +275 -4
- package/src/__tests__/cu-unified-flow.test.ts +26 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -0
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +119 -36
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +9 -35
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +38 -43
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-page-surface.test.ts +99 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/edit-propagation.test.ts +1 -2
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/filing-service.test.ts +3 -2
- package/src/__tests__/first-greeting.test.ts +103 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/gemini-inline-media.test.ts +78 -0
- package/src/__tests__/gemini-provider.test.ts +375 -26
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +60 -71
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +11 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +3 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -1
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +162 -0
- package/src/__tests__/history-repair-observability.test.ts +1 -1
- package/src/__tests__/history-repair.test.ts +2 -1
- package/src/__tests__/host-app-control-proxy.test.ts +2 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-proxy.test.ts +2 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +4 -3
- package/src/__tests__/host-file-edit-tool.test.ts +4 -2
- package/src/__tests__/host-file-proxy.test.ts +31 -0
- package/src/__tests__/host-file-read-tool.test.ts +4 -2
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-write-tool.test.ts +9 -3
- package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
- package/src/__tests__/host-shell-tool.test.ts +11 -5
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +31 -9
- package/src/__tests__/identity-intro-cache.test.ts +140 -96
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +56 -75
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +78 -58
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +214 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-attachments.test.ts +7 -8
- package/src/__tests__/list-messages-hidden-metadata.test.ts +131 -11
- package/src/__tests__/list-messages-page-latest.test.ts +60 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +56 -6
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
- package/src/__tests__/llm-resolver.test.ts +346 -39
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/llm-usage-store.test.ts +268 -1
- package/src/__tests__/log-export-routes.test.ts +59 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-auth-routes.test.ts +15 -10
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/mcp-health-check.test.ts +18 -13
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/messaging-send-tool.test.ts +9 -4
- package/src/__tests__/migration-export-http.test.ts +12 -12
- package/src/__tests__/migration-import-commit-http.test.ts +8 -8
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +235 -22
- package/src/__tests__/notification-decision-identity.test.ts +9 -18
- package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +38 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +15 -2
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +105 -80
- package/src/__tests__/openai-responses-provider.test.ts +90 -86
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +48 -2
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -286
- package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +86 -13
- package/src/__tests__/pipeline-runner.test.ts +31 -43
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-bootstrap.test.ts +72 -63
- package/src/__tests__/plugin-registry.test.ts +0 -27
- package/src/__tests__/plugin-route-contribution.test.ts +6 -16
- package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +51 -64
- package/src/__tests__/plugin-types.test.ts +8 -173
- package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
- package/src/__tests__/process-message-background-slack.test.ts +38 -32
- package/src/__tests__/process-message-display-content.test.ts +55 -66
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
- package/src/__tests__/provider-error-scenarios.test.ts +7 -6
- package/src/__tests__/provider-platform-proxy-integration.test.ts +215 -8
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
- package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
- package/src/__tests__/provider-usage-tracking.test.ts +0 -6
- package/src/__tests__/ratelimit.test.ts +9 -4
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +6 -1
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +30 -23
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
- package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
- package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +390 -0
- package/src/__tests__/schedule-routes.test.ts +683 -12
- package/src/__tests__/schedule-store.test.ts +124 -1
- package/src/__tests__/schedule-tools.test.ts +160 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +7 -3
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
- package/src/__tests__/secret-response-routing.test.ts +13 -11
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +87 -44
- package/src/__tests__/server-history-render.test.ts +318 -2
- package/src/__tests__/shell-observability.test.ts +249 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +52 -21
- package/src/__tests__/skill-feature-flags.test.ts +20 -22
- package/src/__tests__/skill-load-feature-flag.test.ts +15 -15
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
- package/src/__tests__/skillssh-files.test.ts +1 -0
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/starter-task-flow.test.ts +6 -6
- package/src/__tests__/strip-memory-injections.test.ts +102 -14
- package/src/__tests__/subagent-call-site-routing.test.ts +14 -6
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +25 -12
- package/src/__tests__/subagent-fork-spawn.test.ts +14 -5
- package/src/__tests__/subagent-manager-notify.test.ts +21 -11
- package/src/__tests__/subagent-notify-parent.test.ts +6 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +59 -1
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +4 -3
- package/src/__tests__/sync-message-contract.test.ts +19 -16
- package/src/__tests__/system-prompt.test.ts +112 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +9 -25
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/thread-backfill.test.ts +4 -9
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +481 -15
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +1 -1
- package/src/__tests__/tools-audio-read.test.ts +113 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
- package/src/__tests__/turn-events-store.test.ts +11 -7
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +2 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +10 -7
- package/src/__tests__/voice-session-bridge.test.ts +56 -38
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +695 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +125 -0
- package/src/acp/auto-install.ts +174 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +52 -11
- package/src/acp/resolve-agent.test.ts +147 -6
- package/src/acp/resolve-agent.ts +81 -7
- package/src/acp/resume-hint.ts +22 -0
- package/src/acp/session-manager.ts +492 -77
- package/src/agent/compaction-circuit.ts +98 -0
- package/src/agent/loop.ts +730 -449
- package/src/api/README.md +126 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/constants/tool-execution.ts +21 -0
- package/src/api/events/assistant-activity-state.ts +75 -0
- package/src/api/events/assistant-outbound-attachment.ts +49 -0
- package/src/api/events/assistant-text-delta.ts +30 -0
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/assistant-turn-start.ts +31 -0
- package/src/api/events/avatar-updated.ts +24 -0
- package/src/api/events/compaction-circuit-closed.ts +26 -0
- package/src/api/events/compaction-circuit-open.ts +28 -0
- package/src/api/events/confirmation-request.ts +114 -0
- package/src/api/events/contact-request.ts +33 -0
- package/src/api/events/conversation-error.ts +77 -0
- package/src/api/events/conversation-list-invalidated.ts +38 -0
- package/src/api/events/conversation-title-updated.ts +24 -0
- package/src/api/events/disk-pressure-status-changed.ts +61 -0
- package/src/api/events/document-comment-created.ts +44 -0
- package/src/api/events/document-comment-deleted.ts +22 -0
- package/src/api/events/document-comment-reopened.ts +23 -0
- package/src/api/events/document-comment-resolved.ts +25 -0
- package/src/api/events/document-editor-update.ts +27 -0
- package/src/api/events/error.ts +32 -0
- package/src/api/events/generation-cancelled.ts +22 -0
- package/src/api/events/generation-handoff.ts +39 -0
- package/src/api/events/home-feed-updated.ts +26 -0
- package/src/api/events/identity-changed.ts +32 -0
- package/src/api/events/interaction-resolved.ts +50 -0
- package/src/api/events/message-complete.ts +40 -0
- package/src/api/events/message-dequeued.ts +21 -0
- package/src/api/events/message-queued-deleted.ts +23 -0
- package/src/api/events/message-queued.ts +22 -0
- package/src/api/events/message-request-complete.ts +29 -0
- package/src/api/events/navigate-settings.ts +20 -0
- package/src/api/events/notification-intent.ts +33 -0
- package/src/api/events/open-url.ts +28 -0
- package/src/api/events/question-request.ts +67 -0
- package/src/{events → api/events}/relationship-state-updated.ts +6 -8
- package/src/api/events/secret-request.ts +42 -0
- package/src/api/events/subagent-event.ts +79 -0
- package/src/api/events/subagent-spawned.ts +40 -0
- package/src/api/events/subagent-status-changed.ts +65 -0
- package/src/api/events/sync-changed.ts +29 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-result.ts +129 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/tool-use-start.ts +30 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/events/turn-profile-auto-routed.ts +28 -0
- package/src/api/events/ui-surface-complete.ts +30 -0
- package/src/api/events/ui-surface-dismiss.ts +22 -0
- package/src/api/events/ui-surface-show.ts +67 -0
- package/src/api/events/ui-surface-update.ts +26 -0
- package/src/api/events/usage-update.ts +34 -0
- package/src/api/events/user-message-echo.ts +35 -0
- package/src/api/index.ts +517 -3
- package/src/api/requests/dictation.ts +45 -0
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/api/responses/disk-pressure-status.ts +26 -0
- package/src/api/responses/home.ts +217 -0
- package/src/api/responses/llm-context-response.ts +41 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/api/responses/memory-v3-selection-log.ts +50 -0
- package/src/api/responses/subagent-detail.ts +48 -0
- package/src/approvals/guardian-decision-primitive.ts +7 -15
- package/src/approvals/guardian-request-resolvers.ts +7 -10
- package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
- package/src/avatar/__tests__/avatar-store.test.ts +198 -0
- package/src/avatar/avatar-manifest.ts +195 -0
- package/src/avatar/avatar-store.ts +113 -0
- package/src/avatar/traits-png-sync.ts +8 -2
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/next-wake.test.ts +31 -1
- package/src/background-wake/next-wake.ts +5 -1
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/call-conversation-messages.ts +6 -4
- package/src/calls/guardian-action-sweep.ts +6 -4
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/relay-server.ts +12 -8
- package/src/calls/voice-session-bridge.ts +17 -31
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
- package/src/cli/commands/__tests__/notifications.test.ts +242 -54
- package/src/cli/commands/avatar.ts +17 -11
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/conversations.ts +15 -1
- package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
- package/src/cli/commands/db/__tests__/status.test.ts +253 -0
- package/src/cli/commands/db/format.ts +48 -0
- package/src/cli/commands/db/index.ts +29 -0
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
- package/src/cli/commands/db/repair-step-integrity.ts +146 -0
- package/src/cli/commands/db/repair-steps.ts +164 -0
- package/src/cli/commands/db/repair.ts +141 -0
- package/src/cli/commands/db/status.ts +366 -0
- package/src/cli/commands/memory-v3.ts +168 -203
- package/src/cli/commands/notifications.ts +427 -65
- package/src/cli/lib/cli-colors.ts +24 -6
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +6 -5
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +4 -4
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +47 -55
- package/src/config/bundled-skills/acp/SKILL.md +64 -30
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -387
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +33 -24
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +10 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +3 -8
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +81 -25
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -211
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/call-site-catalog.ts +8 -15
- package/src/config/schemas/heartbeat.ts +10 -1
- package/src/config/schemas/llm.ts +93 -4
- package/src/config/schemas/memory-lifecycle.ts +24 -0
- package/src/config/schemas/memory-v2.ts +8 -227
- package/src/config/schemas/memory-v3.ts +47 -0
- package/src/config/schemas/memory.ts +6 -1
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/schemas/timeouts.ts +3 -1
- package/src/config/seed-inference-profiles.ts +38 -18
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +55 -32
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +52 -5
- package/src/context/tool-result-truncation.ts +1 -66
- package/src/context/window-manager.ts +141 -26
- package/src/credential-execution/executable-discovery.ts +56 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +9 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +15 -17
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +11 -8
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +11 -6
- package/src/daemon/approval-generators.ts +4 -4
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +7 -1
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +1146 -247
- package/src/daemon/conversation-agent-loop.ts +570 -1457
- package/src/daemon/conversation-error.ts +40 -12
- package/src/daemon/conversation-history.ts +27 -10
- package/src/daemon/conversation-launch.ts +4 -8
- package/src/daemon/conversation-lifecycle.ts +13 -42
- package/src/daemon/conversation-messaging.ts +89 -49
- package/src/daemon/conversation-notifiers.ts +7 -5
- package/src/daemon/conversation-process.ts +183 -130
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +209 -362
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +15 -95
- package/src/daemon/conversation-surfaces.ts +346 -107
- package/src/daemon/conversation-tool-setup.ts +38 -77
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +143 -186
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +7 -4
- package/src/daemon/disk-pressure-guard.ts +54 -50
- package/src/daemon/external-plugins-bootstrap.ts +53 -32
- package/src/daemon/first-greeting.ts +53 -13
- package/src/daemon/guardian-action-generators.ts +2 -2
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +9 -23
- package/src/daemon/handlers/shared.ts +158 -77
- package/src/daemon/handlers/skills.ts +53 -20
- package/src/daemon/host-app-control-proxy.ts +54 -1
- package/src/daemon/host-cu-proxy.ts +46 -22
- package/src/daemon/host-file-proxy.ts +25 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -6
- package/src/daemon/lifecycle.ts +65 -67
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-protocol.ts +2 -3
- package/src/daemon/message-provenance.ts +49 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/contacts.ts +3 -20
- package/src/daemon/message-types/conversations.ts +25 -125
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/documents.ts +3 -9
- package/src/daemon/message-types/home.ts +5 -18
- package/src/daemon/message-types/integrations.ts +4 -13
- package/src/daemon/message-types/messages.ts +50 -428
- package/src/daemon/message-types/notifications.ts +2 -32
- package/src/daemon/message-types/settings.ts +3 -8
- package/src/daemon/message-types/skills.ts +4 -0
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/surfaces.ts +138 -3
- package/src/daemon/message-types/sync.ts +12 -25
- package/src/daemon/message-types/workspace.ts +3 -11
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +59 -58
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +30 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/tool-side-effects.ts +10 -7
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +24 -2
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +34 -0
- package/src/heartbeat/heartbeat-run-store.ts +54 -1
- package/src/heartbeat/heartbeat-service.ts +105 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-types.ts +36 -221
- package/src/home/feed-writer.ts +146 -7
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/__tests__/email-ipc.test.ts +0 -9
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +6 -3
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
- package/src/ipc/routes/route-adapter.ts +45 -6
- package/src/ipc/skill-routes/__tests__/memory.test.ts +34 -9
- package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
- package/src/ipc/skill-routes/__tests__/registries.test.ts +59 -20
- package/src/ipc/skill-routes/memory.ts +29 -13
- package/src/ipc/skill-routes/providers.ts +5 -6
- package/src/ipc/skill-routes/registries.ts +39 -88
- package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/conversation-queries.test.ts +192 -8
- package/src/memory/__tests__/db-maintenance.test.ts +128 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +82 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +11 -6
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/context-search/agent-runner.ts +2 -4
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +386 -115
- package/src/memory/conversation-queries.ts +78 -22
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +18 -2
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/consolidation.ts +8 -11
- package/src/memory/graph/conversation-graph-memory.ts +106 -8
- package/src/memory/graph/extraction.ts +6 -9
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/graph/retriever.ts +20 -26
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/job-handlers/conversation-starters.ts +45 -34
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/job-handlers/summarization.ts +1 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-store.ts +36 -1
- package/src/memory/jobs-worker.ts +93 -43
- package/src/memory/llm-request-log-source-clickhouse.ts +55 -1
- package/src/memory/llm-request-log-source-local.ts +13 -0
- package/src/memory/llm-request-log-source.ts +21 -6
- package/src/memory/llm-request-log-store.ts +147 -3
- package/src/memory/llm-usage-store.ts +234 -50
- package/src/memory/memory-marker.ts +17 -0
- package/src/memory/memory-retrospective-job.ts +6 -2
- package/src/memory/memory-v2-activation-log-store.ts +13 -1
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
- package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
- package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
- package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
- package/src/memory/migrations/index.ts +9 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +27 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +125 -1
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/migration.test.ts +11 -3
- package/src/memory/v2/__tests__/page-index.test.ts +37 -1
- package/src/memory/v2/__tests__/router.test.ts +14 -4
- package/src/memory/v2/__tests__/sweep-job.test.ts +9 -5
- package/src/memory/v2/backfill-jobs.ts +6 -0
- package/src/memory/v2/consolidation-job.ts +99 -10
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v2/migration.ts +5 -3
- package/src/memory/v2/page-index.ts +11 -0
- package/src/memory/v2/router.ts +8 -11
- package/src/memory/v2/sweep-job.ts +8 -11
- package/src/memory/v2/types.ts +1 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.ts +2 -2
- package/src/messaging/style-analyzer.ts +8 -11
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -8
- package/src/notifications/decision-engine.ts +16 -16
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/notifications/preference-extractor.ts +11 -14
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/permissions/prompter.ts +46 -36
- package/src/permissions/question-prompter.test.ts +35 -26
- package/src/permissions/question-prompter.ts +6 -10
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +10 -1
- package/src/plugin-api/types.ts +176 -4
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +15 -0
- package/src/plugins/defaults/compaction/register.ts +24 -0
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/package.json +15 -0
- package/src/plugins/defaults/empty-response/register.ts +23 -0
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/history-repair/package.json +15 -0
- package/src/plugins/defaults/history-repair/register.ts +24 -0
- package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
- package/src/plugins/defaults/index.ts +22 -49
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors.ts → memory-retrieval/injectors.ts} +297 -120
- package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +242 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +118 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +39 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +36 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +37 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +219 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +330 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +288 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +107 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +436 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +274 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +61 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +332 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +179 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +470 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +432 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +168 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +192 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +54 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +106 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +44 -0
- package/src/plugins/defaults/memory-v3-shadow/assign.ts +268 -0
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +124 -0
- package/src/plugins/defaults/memory-v3-shadow/core.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/data/README.md +84 -0
- package/src/plugins/defaults/memory-v3-shadow/data/assignments.json +5 -0
- package/src/plugins/defaults/memory-v3-shadow/data/core.json +1 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-x.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-y.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-b/topic-z.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +314 -0
- package/src/plugins/defaults/memory-v3-shadow/needle.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +126 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +15 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +34 -0
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +523 -0
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/router.ts +190 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +84 -0
- package/src/plugins/defaults/memory-v3-shadow/selector.ts +226 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +349 -0
- package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +209 -0
- package/src/plugins/defaults/memory-v3-shadow/tree.ts +174 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/working-set.ts +88 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +15 -0
- package/src/plugins/defaults/title-generate/register.ts +35 -0
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +15 -0
- package/src/plugins/defaults/tool-error/register.ts +23 -0
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +24 -0
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +132 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/pipeline.ts +8 -35
- package/src/plugins/registry.ts +8 -25
- package/src/plugins/types.ts +62 -677
- package/src/plugins/user-loader.ts +4 -3
- package/src/proactive-artifact/aux-message-injector.ts +4 -5
- package/src/proactive-artifact/job.test.ts +29 -21
- package/src/proactive-artifact/job.ts +3 -1
- package/src/prompts/__tests__/system-prompt.test.ts +46 -4
- package/src/prompts/sections.ts +20 -7
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
- package/src/prompts/templates/BOOTSTRAP.md +12 -12
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +21 -0
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -25
- package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
- package/src/providers/anthropic/client.ts +61 -34
- package/src/providers/call-site-routing.ts +34 -18
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +176 -37
- package/src/providers/gemini/inline-media.ts +74 -0
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +269 -7
- package/src/providers/openai/chat-completions-provider.ts +155 -16
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +54 -57
- package/src/providers/openrouter/client.ts +15 -14
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/providers/provider-send-message.ts +23 -14
- package/src/providers/ratelimit.ts +1 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -9
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +20 -2
- package/src/providers/usage-tracking.ts +1 -9
- package/src/runtime/__tests__/agent-wake.test.ts +142 -32
- package/src/runtime/__tests__/background-job-runner.test.ts +2 -3
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/agent-wake.ts +95 -23
- package/src/runtime/assistant-event-hub.ts +38 -8
- package/src/runtime/assistant-stream-state.ts +368 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
- package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
- package/src/runtime/auth/route-policy.ts +42 -1069
- package/src/runtime/background-job-runner.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -1
- package/src/runtime/channel-approvals.ts +4 -15
- package/src/runtime/channel-invite-transport.ts +5 -6
- package/src/runtime/channel-readiness-service.ts +70 -5
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +59 -30
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/http-router.ts +35 -43
- package/src/runtime/http-types.ts +23 -71
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/invite-instruction-generator.ts +3 -3
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/pending-interactions.ts +3 -2
- package/src/runtime/routes/__tests__/acp-routes.test.ts +253 -55
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +129 -1
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +26 -72
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +58 -5
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +297 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/__tests__/tts-routes.test.ts +9 -5
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/acp-routes.test.ts +186 -100
- package/src/runtime/routes/acp-routes.ts +110 -35
- package/src/runtime/routes/app-management-routes.ts +175 -106
- package/src/runtime/routes/app-routes.ts +38 -20
- package/src/runtime/routes/approval-routes.ts +17 -5
- package/src/runtime/routes/attachment-routes.ts +51 -16
- package/src/runtime/routes/audio-routes.ts +1 -0
- package/src/runtime/routes/audit-routes.ts +5 -0
- package/src/runtime/routes/auth-routes.ts +5 -0
- package/src/runtime/routes/avatar-routes.ts +264 -59
- package/src/runtime/routes/background-tool-routes.ts +9 -0
- package/src/runtime/routes/background-wake-routes.ts +201 -23
- package/src/runtime/routes/backup-routes.ts +45 -0
- package/src/runtime/routes/bookmark-routes.ts +13 -0
- package/src/runtime/routes/brain-graph-routes.ts +9 -0
- package/src/runtime/routes/browser-routes.ts +6 -1
- package/src/runtime/routes/browser-tabs-routes.ts +11 -10
- package/src/runtime/routes/btw-routes.ts +37 -27
- package/src/runtime/routes/cache-routes.ts +13 -0
- package/src/runtime/routes/call-routes.ts +21 -10
- package/src/runtime/routes/channel-availability-routes.ts +5 -1
- package/src/runtime/routes/channel-readiness-routes.ts +37 -4
- package/src/runtime/routes/channel-route-definitions.ts +21 -0
- package/src/runtime/routes/channel-verification-routes.ts +21 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
- package/src/runtime/routes/client-routes.ts +9 -0
- package/src/runtime/routes/consolidation-routes.ts +133 -25
- package/src/runtime/routes/contact-prompt-routes.ts +9 -0
- package/src/runtime/routes/contact-routes.ts +90 -23
- package/src/runtime/routes/content-source-routes.ts +5 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +11 -1
- package/src/runtime/routes/conversation-attention-routes.ts +5 -0
- package/src/runtime/routes/conversation-cli-routes.ts +54 -7
- package/src/runtime/routes/conversation-compaction-routes.ts +292 -0
- package/src/runtime/routes/conversation-list-routes.ts +225 -9
- package/src/runtime/routes/conversation-management-routes.ts +96 -28
- package/src/runtime/routes/conversation-query-routes.ts +150 -51
- package/src/runtime/routes/conversation-routes.ts +615 -327
- package/src/runtime/routes/conversation-starter-routes.ts +35 -20
- package/src/runtime/routes/conversations-import-routes.ts +48 -13
- package/src/runtime/routes/credential-prompt-routes.ts +5 -0
- package/src/runtime/routes/credential-routes.ts +25 -6
- package/src/runtime/routes/debug-bash-routes.ts +5 -0
- package/src/runtime/routes/debug-routes.ts +11 -2
- package/src/runtime/routes/defer-routes.ts +13 -0
- package/src/runtime/routes/diagnostics-routes.ts +37 -46
- package/src/runtime/routes/disk-pressure-routes.ts +17 -31
- package/src/runtime/routes/document-comments-routes.ts +46 -27
- package/src/runtime/routes/documents-routes.ts +35 -11
- package/src/runtime/routes/domain-routes.ts +98 -51
- package/src/runtime/routes/email-routes.ts +33 -0
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +107 -8
- package/src/runtime/routes/filing-routes.ts +9 -4
- package/src/runtime/routes/gateway-log-routes.ts +31 -4
- package/src/runtime/routes/global-search-routes.ts +53 -50
- package/src/runtime/routes/group-routes.ts +32 -5
- package/src/runtime/routes/guardian-action-routes.ts +9 -0
- package/src/runtime/routes/guardian-approval-interception.ts +0 -31
- package/src/runtime/routes/heartbeat-routes.ts +57 -21
- package/src/runtime/routes/home-feed-routes.ts +149 -16
- package/src/runtime/routes/home-state-routes.ts +8 -40
- package/src/runtime/routes/host-app-control-routes.ts +6 -1
- package/src/runtime/routes/host-bash-routes.ts +5 -0
- package/src/runtime/routes/host-browser-routes.ts +13 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +26 -6
- package/src/runtime/routes/host-transfer-routes.ts +13 -2
- package/src/runtime/routes/http-adapter.ts +1 -2
- package/src/runtime/routes/identity-intro-cache.ts +72 -39
- package/src/runtime/routes/identity-routes.ts +257 -20
- package/src/runtime/routes/image-generation-routes.ts +45 -2
- package/src/runtime/routes/inbound-message-handler.ts +16 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +524 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +72 -27
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
- package/src/runtime/routes/inference-provider-connection-routes.ts +26 -31
- package/src/runtime/routes/inference-send-routes.ts +11 -11
- package/src/runtime/routes/integrations/a2a.ts +32 -7
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +23 -3
- package/src/runtime/routes/integrations/slack/share.ts +36 -8
- package/src/runtime/routes/integrations/telegram.ts +34 -9
- package/src/runtime/routes/integrations/twilio.ts +77 -7
- package/src/runtime/routes/integrations/vercel.ts +18 -3
- package/src/runtime/routes/internal-oauth-routes.ts +5 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/internal-twilio-routes.ts +13 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/log-export-routes.ts +36 -10
- package/src/runtime/routes/mcp-auth-routes.ts +25 -0
- package/src/runtime/routes/memory-item-routes.ts +21 -10
- package/src/runtime/routes/memory-v2-routes.ts +105 -44
- package/src/runtime/routes/memory-v3-routes.ts +313 -257
- package/src/runtime/routes/migration-rollback-routes.ts +5 -1
- package/src/runtime/routes/migration-routes.ts +49 -13
- package/src/runtime/routes/notification-routes.ts +80 -2
- package/src/runtime/routes/oauth-apps.ts +99 -23
- package/src/runtime/routes/oauth-commands-routes.ts +43 -15
- package/src/runtime/routes/oauth-connect-routes.ts +9 -0
- package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
- package/src/runtime/routes/oauth-providers.ts +79 -15
- package/src/runtime/routes/platform-routes.ts +102 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +9 -6
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
- package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
- package/src/runtime/routes/playground/force-compact.ts +2 -2
- package/src/runtime/routes/playground/helpers.ts +1 -2
- package/src/runtime/routes/playground/inject-failures.ts +13 -8
- package/src/runtime/routes/playground/reset-circuit.ts +14 -9
- package/src/runtime/routes/playground/seed-conversation.ts +1 -1
- package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
- package/src/runtime/routes/playground/state.ts +4 -3
- package/src/runtime/routes/plugins-routes.ts +22 -19
- package/src/runtime/routes/profiler-routes.ts +17 -4
- package/src/runtime/routes/ps-routes.ts +5 -0
- package/src/runtime/routes/publish-routes.ts +13 -3
- package/src/runtime/routes/question-routes.ts +5 -0
- package/src/runtime/routes/recording-routes.ts +25 -12
- package/src/runtime/routes/rename-conversation-routes.ts +10 -0
- package/src/runtime/routes/sanity-routes.ts +9 -2
- package/src/runtime/routes/schedule-routes.ts +288 -88
- package/src/runtime/routes/secret-routes.ts +31 -6
- package/src/runtime/routes/sequence-routes.ts +33 -0
- package/src/runtime/routes/settings-routes.ts +65 -19
- package/src/runtime/routes/skills-routes.ts +166 -73
- package/src/runtime/routes/slack-channel-routes.ts +5 -0
- package/src/runtime/routes/stt-routes.ts +13 -6
- package/src/runtime/routes/subagents-routes.ts +24 -18
- package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
- package/src/runtime/routes/surface-action-routes.ts +10 -38
- package/src/runtime/routes/surface-content-routes.ts +21 -6
- package/src/runtime/routes/surface-conversation-resolver.ts +66 -0
- package/src/runtime/routes/task-routes.ts +37 -0
- package/src/runtime/routes/telemetry-routes.ts +9 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trace-event-routes.ts +42 -1
- package/src/runtime/routes/trust-rules-routes.ts +31 -2
- package/src/runtime/routes/tts-routes.ts +48 -6
- package/src/runtime/routes/types.ts +83 -16
- package/src/runtime/routes/ui-request-routes.ts +5 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
- package/src/runtime/routes/usage-routes.ts +118 -42
- package/src/runtime/routes/user-routes-cli.ts +9 -0
- package/src/runtime/routes/user-routes.ts +5 -1
- package/src/runtime/routes/wake-conversation-routes.ts +5 -0
- package/src/runtime/routes/watcher-routes.ts +21 -0
- package/src/runtime/routes/webhook-routes.ts +50 -2
- package/src/runtime/routes/wipe-conversation-routes.ts +8 -0
- package/src/runtime/routes/work-items-routes.ts +49 -23
- package/src/runtime/routes/workspace-commit-routes.ts +5 -0
- package/src/runtime/routes/workspace-routes.test.ts +42 -0
- package/src/runtime/routes/workspace-routes.ts +124 -9
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +10 -4
- package/src/runtime/services/analyze-conversation.ts +5 -8
- package/src/runtime/services/conversation-serializer.ts +24 -2
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +17 -3
- package/src/runtime/sync/sync-publisher.ts +2 -2
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/run-script.ts +28 -3
- package/src/schedule/schedule-store.ts +36 -2
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +126 -21
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/cancel.ts +2 -4
- package/src/signals/user-message.ts +10 -16
- package/src/skills/catalog-files.ts +4 -1
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -0
- package/src/skills/skillssh-files.ts +1 -0
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +33 -24
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/telemetry/types.ts +55 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +250 -4
- package/src/telemetry/usage-telemetry-reporter.ts +88 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +198 -93
- package/src/tools/acp/spawn.ts +32 -70
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/definitions.ts +42 -24
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
- package/src/tools/ask-question/ask-question-tool.ts +85 -90
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +295 -289
- package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
- package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
- package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
- package/src/tools/credentials/vault.ts +112 -111
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +3 -6
- package/src/tools/execution-timeout.ts +3 -4
- package/src/tools/executor.ts +18 -107
- package/src/tools/filesystem/edit.ts +45 -42
- package/src/tools/filesystem/list.ts +33 -30
- package/src/tools/filesystem/read.ts +54 -35
- package/src/tools/filesystem/write.ts +69 -32
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/edit.ts +44 -42
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/read.ts +49 -35
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/transfer.ts +121 -108
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/host-filesystem/write.ts +33 -31
- package/src/tools/host-terminal/host-shell.ts +50 -48
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/memory/register.ts +23 -24
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +222 -6
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-fetch.ts +49 -46
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +414 -97
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +184 -118
- package/src/tools/schedule/create.ts +14 -1
- package/src/tools/schedule/update.ts +16 -0
- package/src/tools/shared/filesystem/audio-read.ts +122 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/execute.ts +34 -31
- package/src/tools/skills/load.ts +29 -23
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/notify-parent.ts +35 -32
- package/src/tools/subagent/spawn.ts +2 -1
- package/src/tools/system/avatar-generator.ts +13 -22
- package/src/tools/system/request-permission.ts +30 -27
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/terminal/shell.ts +190 -61
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-defaults.ts +20 -9
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +86 -33
- package/src/tools/ui-surface/definitions.ts +196 -95
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/usage/types.ts +10 -0
- package/src/util/browser.ts +7 -2
- package/src/util/errors.ts +2 -2
- package/src/util/map-limit.ts +27 -0
- package/src/util/mutex.ts +47 -0
- package/src/util/platform.ts +15 -12
- package/src/work-items/work-item-runner.ts +7 -2
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
- package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
- package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
- package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +15 -17
- package/tsconfig.json +4 -1
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -262
- package/src/__tests__/empty-response-pipeline.test.ts +0 -301
- package/src/__tests__/history-repair-pipeline.test.ts +0 -396
- package/src/__tests__/llm-call-pipeline.test.ts +0 -281
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -376
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -481
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -344
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
- package/src/cli/commands/memory-v3-render.ts +0 -344
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/daemon/message-types/disk-pressure.ts +0 -9
- package/src/email/feature-gate.ts +0 -23
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
- package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -468
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
- package/src/memory/v3/__tests__/edges.test.ts +0 -563
- package/src/memory/v3/__tests__/filter.test.ts +0 -512
- package/src/memory/v3/__tests__/gate.test.ts +0 -574
- package/src/memory/v3/__tests__/index-composition.test.ts +0 -233
- package/src/memory/v3/__tests__/loop.test.ts +0 -530
- package/src/memory/v3/__tests__/retriever.test.ts +0 -226
- package/src/memory/v3/__tests__/scouts.test.ts +0 -440
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -312
- package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
- package/src/memory/v3/__tests__/traversal.test.ts +0 -469
- package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
- package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
- package/src/memory/v3/__tests__/tree-walk.test.ts +0 -707
- package/src/memory/v3/__tests__/validate.test.ts +0 -245
- package/src/memory/v3/auto-edges.ts +0 -223
- package/src/memory/v3/coactivation-store.ts +0 -124
- package/src/memory/v3/consolidation-job.ts +0 -323
- package/src/memory/v3/edge-learning-job.ts +0 -160
- package/src/memory/v3/edges.ts +0 -249
- package/src/memory/v3/filter.ts +0 -281
- package/src/memory/v3/gate.ts +0 -334
- package/src/memory/v3/index-composition.ts +0 -113
- package/src/memory/v3/llm-capture.ts +0 -46
- package/src/memory/v3/loop.ts +0 -382
- package/src/memory/v3/maintenance.ts +0 -144
- package/src/memory/v3/prompt-context.ts +0 -33
- package/src/memory/v3/prompts/consolidation.ts +0 -458
- package/src/memory/v3/prompts/system-prompts.ts +0 -196
- package/src/memory/v3/retriever.ts +0 -33
- package/src/memory/v3/scouts.ts +0 -420
- package/src/memory/v3/shadow-middleware.ts +0 -305
- package/src/memory/v3/traversal.ts +0 -206
- package/src/memory/v3/tree-index.ts +0 -237
- package/src/memory/v3/tree-store.ts +0 -394
- package/src/memory/v3/tree-walk.ts +0 -351
- package/src/memory/v3/types.ts +0 -65
- package/src/memory/v3/validate.ts +0 -300
- package/src/plugins/defaults/circuit-breaker.ts +0 -141
- package/src/plugins/defaults/compaction.ts +0 -141
- package/src/plugins/defaults/empty-response.ts +0 -124
- package/src/plugins/defaults/history-repair.ts +0 -83
- package/src/plugins/defaults/llm-call.ts +0 -77
- package/src/plugins/defaults/memory-retrieval.ts +0 -219
- package/src/plugins/defaults/overflow-reduce.ts +0 -185
- package/src/plugins/defaults/persistence.ts +0 -127
- package/src/plugins/defaults/title-generate.ts +0 -90
- package/src/plugins/defaults/token-estimate.ts +0 -101
- package/src/plugins/defaults/tool-error.ts +0 -119
- package/src/plugins/defaults/tool-execute.ts +0 -87
- package/src/plugins/defaults/tool-result-truncate.ts +0 -84
- package/src/skills/category-inference.ts +0 -111
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
createAssistantMessage,
|
|
11
11
|
createUserMessage,
|
|
12
12
|
} from "../../agent/message-types.js";
|
|
13
|
+
import { ConversationMessageSchema } from "../../api/responses/conversation-message.js";
|
|
13
14
|
import {
|
|
14
15
|
CHANNEL_IDS,
|
|
15
16
|
INTERFACE_IDS,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
parseInterfaceId,
|
|
19
20
|
supportsHostProxy,
|
|
20
21
|
} from "../../channels/types.js";
|
|
22
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
21
23
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
22
24
|
import { getConfig } from "../../config/loader.js";
|
|
23
25
|
import {
|
|
@@ -26,6 +28,7 @@ import {
|
|
|
26
28
|
} from "../../conversations/message-consolidation.js";
|
|
27
29
|
import { createApprovalConversationGenerator } from "../../daemon/approval-generators.js";
|
|
28
30
|
import type { Conversation } from "../../daemon/conversation.js";
|
|
31
|
+
import { persistQueuedMessageBody } from "../../daemon/conversation-messaging.js";
|
|
29
32
|
import {
|
|
30
33
|
buildModelInfoEvent,
|
|
31
34
|
formatCleanResult,
|
|
@@ -40,10 +43,15 @@ import { getOrCreateConversation as getOrCreateConversationInstance } from "../.
|
|
|
40
43
|
import { canonicalizeTimeZone } from "../../daemon/date-context.js";
|
|
41
44
|
import {
|
|
42
45
|
buildScanFirstMessage,
|
|
46
|
+
buildSelfIntroMessage,
|
|
43
47
|
getCannedFirstGreeting,
|
|
44
48
|
isWakeUpGreeting,
|
|
45
49
|
} from "../../daemon/first-greeting.js";
|
|
46
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
collectAttachmentRefs,
|
|
52
|
+
type HistoryAttachmentRef,
|
|
53
|
+
renderHistoryContent,
|
|
54
|
+
} from "../../daemon/handlers/shared.js";
|
|
47
55
|
import { HostAppControlProxy } from "../../daemon/host-app-control-proxy.js";
|
|
48
56
|
import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
|
|
49
57
|
import {
|
|
@@ -75,6 +83,7 @@ import {
|
|
|
75
83
|
} from "../../memory/canonical-guardian-store.js";
|
|
76
84
|
import {
|
|
77
85
|
addMessage,
|
|
86
|
+
extractImageSourcePaths,
|
|
78
87
|
getConversation,
|
|
79
88
|
getMessages,
|
|
80
89
|
getMessagesPaginated,
|
|
@@ -82,8 +91,6 @@ import {
|
|
|
82
91
|
type MessageRow,
|
|
83
92
|
provenanceFromTrustContext,
|
|
84
93
|
setConversationInferenceProfile,
|
|
85
|
-
setConversationOriginChannelIfUnset,
|
|
86
|
-
setConversationOriginInterfaceIfUnset,
|
|
87
94
|
} from "../../memory/conversation-crud.js";
|
|
88
95
|
import {
|
|
89
96
|
getConversationByKey,
|
|
@@ -103,10 +110,15 @@ import type { Provider } from "../../providers/types.js";
|
|
|
103
110
|
import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
104
111
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
105
112
|
import { getLogger } from "../../util/logger.js";
|
|
106
|
-
import {
|
|
113
|
+
import {
|
|
114
|
+
getWorkspaceDir,
|
|
115
|
+
getWorkspacePromptPath,
|
|
116
|
+
} from "../../util/platform.js";
|
|
107
117
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
108
118
|
import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
|
|
109
119
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
120
|
+
import { getPersistedSeq } from "../assistant-stream-state.js";
|
|
121
|
+
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
110
122
|
import { routeGuardianReply } from "../guardian-reply-router.js";
|
|
111
123
|
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
112
124
|
import type {
|
|
@@ -131,6 +143,10 @@ import {
|
|
|
131
143
|
NotFoundError,
|
|
132
144
|
RouteError,
|
|
133
145
|
} from "./errors.js";
|
|
146
|
+
import {
|
|
147
|
+
collectPendingConfirmations,
|
|
148
|
+
enrichToolCallsWithConfirmation,
|
|
149
|
+
} from "./tool-call-confirmation-enrichment.js";
|
|
134
150
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
135
151
|
import { RouteResponse } from "./types.js";
|
|
136
152
|
|
|
@@ -140,6 +156,128 @@ const log = getLogger("conversation-routes");
|
|
|
140
156
|
const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/g;
|
|
141
157
|
const ATTACHMENT_ENTRY_RE = /^attachment:(\d+)$/;
|
|
142
158
|
|
|
159
|
+
/** Rewrites a rendered `contentOrder` to reflect attachment alignment. */
|
|
160
|
+
type ContentOrderRewrite = (contentOrder: string[]) => string[];
|
|
161
|
+
|
|
162
|
+
interface AlignedAttachments {
|
|
163
|
+
/** Hydrated rows, reordered to match the inline file-block order. */
|
|
164
|
+
attachments: RuntimeAttachmentMetadata[];
|
|
165
|
+
/**
|
|
166
|
+
* Resolves a content-walk attachment ref index to its hydrated DB row,
|
|
167
|
+
* mirroring the inline placement `rewriteContentOrder` encodes. Refs with no
|
|
168
|
+
* inline placement (unmatched ids, count mismatch, no DB rows) are absent, so
|
|
169
|
+
* `renderHistoryContent` emits no `attachment` block for them — the row still
|
|
170
|
+
* ships via the flat `attachments` array.
|
|
171
|
+
*/
|
|
172
|
+
refIndexToAttachment: Map<number, RuntimeAttachmentMetadata>;
|
|
173
|
+
rewriteContentOrder: ContentOrderRewrite;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Align DB-hydrated attachment rows with the file-block refs `renderHistoryContent`
|
|
178
|
+
* captured. When a file block was persisted with `_attachmentId` (user-message
|
|
179
|
+
* uploads) we join on that id to position the chip inline; DB rows without a
|
|
180
|
+
* matching ref go to the tail as orphan chips, and unmatched refs drop their
|
|
181
|
+
* `attachment:N` entry. Assistant-authored file blocks carry no `_attachmentId`,
|
|
182
|
+
* so when no ids match we fall back to positional alignment if the ref and row
|
|
183
|
+
* counts agree; otherwise we strip the markers and let chips fall to the tail.
|
|
184
|
+
*/
|
|
185
|
+
function alignAttachments(
|
|
186
|
+
attachmentRefs: HistoryAttachmentRef[],
|
|
187
|
+
attachments: RuntimeAttachmentMetadata[],
|
|
188
|
+
): AlignedAttachments {
|
|
189
|
+
const refIndexToAttachment = new Map<number, RuntimeAttachmentMetadata>();
|
|
190
|
+
const identity: ContentOrderRewrite = (contentOrder) => contentOrder;
|
|
191
|
+
const stripAttachmentEntries: ContentOrderRewrite = (contentOrder) =>
|
|
192
|
+
contentOrder.filter((entry) => !ATTACHMENT_ENTRY_RE.test(entry));
|
|
193
|
+
|
|
194
|
+
if (attachmentRefs.length === 0) {
|
|
195
|
+
return { attachments, refIndexToAttachment, rewriteContentOrder: identity };
|
|
196
|
+
}
|
|
197
|
+
if (attachments.length === 0) {
|
|
198
|
+
// Refs were captured but no DB rows came back — drop the contentOrder
|
|
199
|
+
// entries to avoid out-of-bounds renders.
|
|
200
|
+
return {
|
|
201
|
+
attachments,
|
|
202
|
+
refIndexToAttachment,
|
|
203
|
+
rewriteContentOrder: stripAttachmentEntries,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const byId = new Map<string, number>();
|
|
208
|
+
attachments.forEach((att, idx) => {
|
|
209
|
+
if (att.id) byId.set(att.id, idx);
|
|
210
|
+
});
|
|
211
|
+
const consumed = new Set<number>();
|
|
212
|
+
const orderedRowIdx: Array<number | null> = attachmentRefs.map((ref) => {
|
|
213
|
+
if (!ref.attachmentId) return null;
|
|
214
|
+
const idx = byId.get(ref.attachmentId);
|
|
215
|
+
if (idx === undefined || consumed.has(idx)) return null;
|
|
216
|
+
consumed.add(idx);
|
|
217
|
+
return idx;
|
|
218
|
+
});
|
|
219
|
+
const matchedRows = orderedRowIdx.filter(
|
|
220
|
+
(idx): idx is number => idx !== null,
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (matchedRows.length > 0) {
|
|
224
|
+
const orphanRows: number[] = [];
|
|
225
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
226
|
+
if (!consumed.has(i)) orphanRows.push(i);
|
|
227
|
+
}
|
|
228
|
+
const reordered = [
|
|
229
|
+
...matchedRows.map((i) => attachments[i]),
|
|
230
|
+
...orphanRows.map((i) => attachments[i]),
|
|
231
|
+
];
|
|
232
|
+
const refToNewIdx = new Map<number, number>();
|
|
233
|
+
let nextIdx = 0;
|
|
234
|
+
orderedRowIdx.forEach((rowIdx, refIdx) => {
|
|
235
|
+
if (rowIdx !== null) {
|
|
236
|
+
refToNewIdx.set(refIdx, nextIdx);
|
|
237
|
+
refIndexToAttachment.set(refIdx, reordered[nextIdx]);
|
|
238
|
+
nextIdx++;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
const rewriteContentOrder: ContentOrderRewrite = (contentOrder) =>
|
|
242
|
+
contentOrder
|
|
243
|
+
.map((entry) => {
|
|
244
|
+
const match = entry.match(ATTACHMENT_ENTRY_RE);
|
|
245
|
+
if (!match) return entry;
|
|
246
|
+
const remapped = refToNewIdx.get(Number(match[1]));
|
|
247
|
+
return remapped !== undefined ? `attachment:${remapped}` : undefined;
|
|
248
|
+
})
|
|
249
|
+
.filter((e): e is string => e !== undefined);
|
|
250
|
+
return {
|
|
251
|
+
attachments: reordered,
|
|
252
|
+
refIndexToAttachment,
|
|
253
|
+
rewriteContentOrder,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (attachmentRefs.length !== attachments.length) {
|
|
258
|
+
// No ref carried an attachmentId we could match and the counts disagree, so
|
|
259
|
+
// positional mapping can't be trusted — strip any attachment:N entries so
|
|
260
|
+
// the client doesn't position attachments inline against a misaligned array
|
|
261
|
+
// (they fall to the tail instead).
|
|
262
|
+
return {
|
|
263
|
+
attachments,
|
|
264
|
+
refIndexToAttachment,
|
|
265
|
+
rewriteContentOrder: stripAttachmentEntries,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// No ref matched an id but the counts agree (the assistant-authored case):
|
|
270
|
+
// the Nth marker maps to the Nth row positionally, so the original
|
|
271
|
+
// contentOrder is left untouched.
|
|
272
|
+
attachmentRefs.forEach((_ref, refIdx) => {
|
|
273
|
+
refIndexToAttachment.set(refIdx, attachments[refIdx]);
|
|
274
|
+
});
|
|
275
|
+
return { attachments, refIndexToAttachment, rewriteContentOrder: identity };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Feature flag gating the self-intro first message (see first-greeting.ts). */
|
|
279
|
+
const SELF_INTRO_GREETING_FLAG = "self-intro-greeting" as const;
|
|
280
|
+
|
|
143
281
|
const SUGGESTION_CACHE_MAX = 100;
|
|
144
282
|
const VALID_RISK_THRESHOLDS = ["none", "low", "medium", "high"] as const;
|
|
145
283
|
type RiskThreshold = (typeof VALID_RISK_THRESHOLDS)[number];
|
|
@@ -395,23 +533,10 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
395
533
|
// is not re-processed as a new user turn.
|
|
396
534
|
let messageId: string | undefined;
|
|
397
535
|
try {
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
guardianImageSourcePaths[`${i}:${a.filename}`] = a.filePath;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
const channelMeta = {
|
|
406
|
-
userMessageChannel: sourceChannel,
|
|
407
|
-
assistantMessageChannel: sourceChannel,
|
|
408
|
-
userMessageInterface: sourceInterface,
|
|
409
|
-
assistantMessageInterface: sourceInterface,
|
|
410
|
-
provenanceTrustClass: "guardian" as const,
|
|
411
|
-
...(Object.keys(guardianImageSourcePaths).length > 0
|
|
412
|
-
? { imageSourcePaths: guardianImageSourcePaths }
|
|
413
|
-
: {}),
|
|
414
|
-
};
|
|
536
|
+
const channelMeta = buildChannelMetadata(sourceChannel, sourceInterface, {
|
|
537
|
+
provenanceOverride: { provenanceTrustClass: "guardian" },
|
|
538
|
+
attachments,
|
|
539
|
+
});
|
|
415
540
|
|
|
416
541
|
const cleanUserMessage = createUserMessage(content, attachments);
|
|
417
542
|
const llmUserMessage = enrichMessageWithSourcePaths(
|
|
@@ -422,7 +547,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
422
547
|
conversationId,
|
|
423
548
|
"user",
|
|
424
549
|
JSON.stringify(cleanUserMessage.content),
|
|
425
|
-
channelMeta,
|
|
550
|
+
{ metadata: channelMeta },
|
|
426
551
|
);
|
|
427
552
|
messageId = persistedUser.id;
|
|
428
553
|
|
|
@@ -436,7 +561,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
436
561
|
conversationId,
|
|
437
562
|
"assistant",
|
|
438
563
|
JSON.stringify(assistantMessage.content),
|
|
439
|
-
channelMeta,
|
|
564
|
+
{ metadata: channelMeta },
|
|
440
565
|
);
|
|
441
566
|
|
|
442
567
|
// Avoid mutating in-memory history / emitting stream deltas while a run is active.
|
|
@@ -516,6 +641,7 @@ export function handleListMessages({
|
|
|
516
641
|
hasMore: false,
|
|
517
642
|
oldestTimestamp: null,
|
|
518
643
|
oldestMessageId: null,
|
|
644
|
+
seq: null,
|
|
519
645
|
};
|
|
520
646
|
}
|
|
521
647
|
return { messages: [] };
|
|
@@ -538,6 +664,10 @@ export function handleListMessages({
|
|
|
538
664
|
|
|
539
665
|
let rawMessages: MessageRow[];
|
|
540
666
|
let hasMore = false;
|
|
667
|
+
// Resume cursor surfaced when the paginated scan stops on its row cap with a
|
|
668
|
+
// (possibly empty) page — lets us still emit an oldest cursor so the client
|
|
669
|
+
// can request the next window instead of stalling.
|
|
670
|
+
let scanResumeCursor: { createdAt: number; id: string } | undefined;
|
|
541
671
|
|
|
542
672
|
// Drop messages flagged as hidden in metadata (e.g. internal scaffolding
|
|
543
673
|
// like retrospective instructions). The LLM-side history loader
|
|
@@ -550,7 +680,14 @@ export function handleListMessages({
|
|
|
550
680
|
// assistant message has tool_use blocks but its matching user tool_result
|
|
551
681
|
// is left visible, the result will render as a standalone orphan because
|
|
552
682
|
// `mergeToolResultsIntoAssistantMessages` has nothing to merge it into.
|
|
553
|
-
|
|
683
|
+
//
|
|
684
|
+
// Only renderable roles reach this UI-facing transcript. `system` rows (a
|
|
685
|
+
// permitted `MessageRole`, e.g. skill-authored context) are agent-context
|
|
686
|
+
// scaffolding, never a displayed turn, so they are dropped here at the
|
|
687
|
+
// source rather than narrowed away per-client.
|
|
688
|
+
const visibleFilter = (m: MessageRow) =>
|
|
689
|
+
!isHiddenMessage(m.metadata) &&
|
|
690
|
+
(m.role === "user" || m.role === "assistant");
|
|
554
691
|
|
|
555
692
|
if (isPaginated) {
|
|
556
693
|
const result = getMessagesPaginated(
|
|
@@ -561,6 +698,7 @@ export function handleListMessages({
|
|
|
561
698
|
);
|
|
562
699
|
rawMessages = result.messages;
|
|
563
700
|
hasMore = result.hasMore;
|
|
701
|
+
scanResumeCursor = result.nextCursor;
|
|
564
702
|
} else {
|
|
565
703
|
rawMessages = getMessages(resolvedConversationId).filter(visibleFilter);
|
|
566
704
|
}
|
|
@@ -583,7 +721,10 @@ export function handleListMessages({
|
|
|
583
721
|
mergeConsecutiveAssistantMessages(mergedMessages);
|
|
584
722
|
const assistantSlackDisplayName = getAssistantName()?.trim() || undefined;
|
|
585
723
|
|
|
586
|
-
// Parse content
|
|
724
|
+
// Parse each row's stored content and per-message metadata. Rendering is
|
|
725
|
+
// deferred to the serializer pass below so it runs after attachment
|
|
726
|
+
// alignment, letting renderHistoryContent inline `attachment` blocks during
|
|
727
|
+
// its single content walk.
|
|
587
728
|
const parsed = consolidatedMessages.map((msg) => {
|
|
588
729
|
let content: unknown;
|
|
589
730
|
try {
|
|
@@ -591,7 +732,6 @@ export function handleListMessages({
|
|
|
591
732
|
} catch {
|
|
592
733
|
content = msg.content;
|
|
593
734
|
}
|
|
594
|
-
const rendered = renderHistoryContent(content);
|
|
595
735
|
|
|
596
736
|
// Extract sentAt from metadata for display timestamps. When a message
|
|
597
737
|
// was queued or its persistence was delayed (long assistant generation),
|
|
@@ -639,94 +779,51 @@ export function handleListMessages({
|
|
|
639
779
|
},
|
|
640
780
|
);
|
|
641
781
|
|
|
642
|
-
//
|
|
643
|
-
//
|
|
644
|
-
//
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const keepIndices: number[] = [];
|
|
648
|
-
const filteredSegments: string[] = [];
|
|
649
|
-
for (let i = 0; i < originalSegments.length; i++) {
|
|
650
|
-
const cleaned = originalSegments[i]
|
|
651
|
-
.replace(NO_RESPONSE_INLINE_RE, "")
|
|
652
|
-
.trim();
|
|
653
|
-
if (cleaned.length > 0) {
|
|
654
|
-
keepIndices.push(i);
|
|
655
|
-
filteredSegments.push(cleaned);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
// Remap contentOrder text:N indices to account for removed segments
|
|
659
|
-
const indexMap = new Map<number, number>();
|
|
660
|
-
keepIndices.forEach((oldIdx, newIdx) => indexMap.set(oldIdx, newIdx));
|
|
661
|
-
const filteredContentOrder = rendered.contentOrder
|
|
662
|
-
.map((entry) => {
|
|
663
|
-
const m = entry.match(/^text:(\d+)$/);
|
|
664
|
-
if (!m) return entry;
|
|
665
|
-
const newIdx = indexMap.get(Number(m[1]));
|
|
666
|
-
return newIdx !== undefined ? `text:${newIdx}` : undefined;
|
|
667
|
-
})
|
|
668
|
-
.filter((e): e is string => e !== undefined);
|
|
669
|
-
|
|
670
|
-
return {
|
|
671
|
-
role: msg.role,
|
|
672
|
-
text: rendered.text.replace(NO_RESPONSE_INLINE_RE, "").trim(),
|
|
673
|
-
timestamp: msg.createdAt,
|
|
674
|
-
sentAt,
|
|
675
|
-
toolCalls: rendered.toolCalls,
|
|
676
|
-
toolCallsBeforeText: rendered.toolCallsBeforeText,
|
|
677
|
-
textSegments: filteredSegments,
|
|
678
|
-
contentOrder: filteredContentOrder,
|
|
679
|
-
surfaces: rendered.surfaces,
|
|
680
|
-
attachmentRefs: rendered.attachments,
|
|
681
|
-
slackMessage,
|
|
682
|
-
...(rendered.thinkingSegments.length > 0
|
|
683
|
-
? { thinkingSegments: rendered.thinkingSegments }
|
|
684
|
-
: {}),
|
|
685
|
-
id: msg.id,
|
|
686
|
-
subagentNotification,
|
|
687
|
-
};
|
|
688
|
-
}
|
|
782
|
+
// `visibleFilter` has already dropped every non-renderable role, so the
|
|
783
|
+
// only values reaching here are `user` and `assistant`; narrow the raw DB
|
|
784
|
+
// `string` to the wire union.
|
|
785
|
+
const role: "user" | "assistant" =
|
|
786
|
+
msg.role === "assistant" ? "assistant" : "user";
|
|
689
787
|
|
|
690
788
|
return {
|
|
691
|
-
role: msg.role,
|
|
692
|
-
text: rendered.text,
|
|
693
|
-
timestamp: msg.createdAt,
|
|
694
|
-
sentAt,
|
|
695
|
-
toolCalls: rendered.toolCalls,
|
|
696
|
-
toolCallsBeforeText: rendered.toolCallsBeforeText,
|
|
697
|
-
textSegments: rendered.textSegments,
|
|
698
|
-
contentOrder: rendered.contentOrder,
|
|
699
|
-
surfaces: rendered.surfaces,
|
|
700
|
-
attachmentRefs: rendered.attachments,
|
|
701
|
-
slackMessage,
|
|
702
|
-
...(rendered.thinkingSegments.length > 0
|
|
703
|
-
? { thinkingSegments: rendered.thinkingSegments }
|
|
704
|
-
: {}),
|
|
705
789
|
id: msg.id,
|
|
790
|
+
role,
|
|
791
|
+
content,
|
|
792
|
+
createdAt: msg.createdAt,
|
|
793
|
+
sentAt,
|
|
706
794
|
subagentNotification,
|
|
795
|
+
slackMessage,
|
|
707
796
|
};
|
|
708
797
|
});
|
|
709
798
|
|
|
799
|
+
// Confirmation context layered onto rendered tool calls at render time: the
|
|
800
|
+
// derived scope ladder for scope-aware tools, and any in-flight prompt read
|
|
801
|
+
// from the pending-interactions registry. Both are computed once per request
|
|
802
|
+
// and applied per message below.
|
|
803
|
+
const workspaceDir = getWorkspaceDir();
|
|
804
|
+
const pendingConfirmations = collectPendingConfirmations(
|
|
805
|
+
resolvedConversationId,
|
|
806
|
+
);
|
|
807
|
+
|
|
710
808
|
const messages: RuntimeMessagePayload[] = parsed.map((m) => {
|
|
809
|
+
const mergedMessageIds = m.id ? (mergedIdMap.get(m.id) ?? []) : [];
|
|
810
|
+
|
|
811
|
+
// Hydrate the row's attachments from the DB. A metadata-only query avoids
|
|
812
|
+
// loading large base64 blobs for non-image attachments (documents, audio);
|
|
813
|
+
// full data is fetched only for images so the client can generate
|
|
814
|
+
// thumbnails for inline display on history restore. Merged messages
|
|
815
|
+
// (consecutive assistant merge) are queried too so their attachments
|
|
816
|
+
// aren't lost before DB compaction relinks them.
|
|
711
817
|
let msgAttachments: RuntimeAttachmentMetadata[] = [];
|
|
712
818
|
if (m.id) {
|
|
713
|
-
|
|
714
|
-
// blobs for non-image attachments (documents, audio). Then
|
|
715
|
-
// selectively fetch full data only for images so the client can
|
|
716
|
-
// generate thumbnails for inline display on history restore.
|
|
717
|
-
// Also query attachments for any messages that were merged into
|
|
718
|
-
// this one (consecutive assistant merge), so their attachments
|
|
719
|
-
// aren't lost before DB compaction relinks them.
|
|
720
|
-
const idsToQuery = [m.id, ...(mergedIdMap.get(m.id) ?? [])];
|
|
819
|
+
const idsToQuery = [m.id, ...mergedMessageIds];
|
|
721
820
|
const linked = idsToQuery.flatMap((id) =>
|
|
722
821
|
getAttachmentMetadataForMessage(id),
|
|
723
822
|
);
|
|
724
823
|
if (linked.length > 0) {
|
|
725
824
|
msgAttachments = linked.map((a) => {
|
|
726
825
|
if (a.mimeType.startsWith("image/")) {
|
|
727
|
-
const full = getAttachmentById(a.id, {
|
|
728
|
-
hydrateFileData: true,
|
|
729
|
-
});
|
|
826
|
+
const full = getAttachmentById(a.id, { hydrateFileData: true });
|
|
730
827
|
return {
|
|
731
828
|
id: a.id,
|
|
732
829
|
filename: a.originalFilename,
|
|
@@ -753,100 +850,101 @@ export function handleListMessages({
|
|
|
753
850
|
}
|
|
754
851
|
}
|
|
755
852
|
|
|
756
|
-
// Align
|
|
757
|
-
//
|
|
758
|
-
//
|
|
759
|
-
//
|
|
760
|
-
//
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
853
|
+
// Align the hydrated rows with the file-block refs, then render. Rendering
|
|
854
|
+
// after alignment lets renderHistoryContent inline each `attachment` block
|
|
855
|
+
// during its single content walk, so `contentBlocks` comes back ready to
|
|
856
|
+
// ship with no post-processing. The aligned reorder/rewrite keeps the
|
|
857
|
+
// legacy `attachments` array and `contentOrder` positions consistent.
|
|
858
|
+
const attachmentRefs = collectAttachmentRefs(m.content);
|
|
859
|
+
const aligned = alignAttachments(attachmentRefs, msgAttachments);
|
|
860
|
+
msgAttachments = aligned.attachments;
|
|
861
|
+
const attachmentBlocks = attachmentRefs.map(
|
|
862
|
+
(_ref, refIdx) => aligned.refIndexToAttachment.get(refIdx) ?? null,
|
|
863
|
+
);
|
|
864
|
+
const rendered = renderHistoryContent(
|
|
865
|
+
m.content,
|
|
866
|
+
attachmentBlocks,
|
|
867
|
+
m.id ?? undefined,
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
const toolCalls = enrichToolCallsWithConfirmation(rendered.toolCalls, {
|
|
871
|
+
workspaceDir,
|
|
872
|
+
pendingConfirmations,
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
// Strip <no_response/> markers from assistant messages so web/API clients
|
|
876
|
+
// never see the raw sentinel. Only assistant messages produce it; user
|
|
877
|
+
// messages are untouched. The filter is applied consistently to the flat
|
|
878
|
+
// text, the segments, the contentOrder text refs, and the text blocks of
|
|
879
|
+
// contentBlocks.
|
|
880
|
+
let text = rendered.text;
|
|
881
|
+
let textSegments = rendered.textSegments;
|
|
882
|
+
let contentOrder = rendered.contentOrder;
|
|
883
|
+
let contentBlocks = rendered.contentBlocks;
|
|
884
|
+
if (m.role === "assistant") {
|
|
885
|
+
const keepIndices: number[] = [];
|
|
886
|
+
const filteredSegments: string[] = [];
|
|
887
|
+
for (let i = 0; i < rendered.textSegments.length; i++) {
|
|
888
|
+
const cleaned = rendered.textSegments[i]
|
|
889
|
+
.replace(NO_RESPONSE_INLINE_RE, "")
|
|
890
|
+
.trim();
|
|
891
|
+
if (cleaned.length > 0) {
|
|
892
|
+
keepIndices.push(i);
|
|
893
|
+
filteredSegments.push(cleaned);
|
|
789
894
|
}
|
|
790
|
-
msgAttachments = [
|
|
791
|
-
...matchedRows.map((i) => msgAttachments[i]),
|
|
792
|
-
...orphanRows.map((i) => msgAttachments[i]),
|
|
793
|
-
];
|
|
794
|
-
const refToNewIdx = new Map<number, number>();
|
|
795
|
-
let nextIdx = 0;
|
|
796
|
-
orderedRowIdx.forEach((rowIdx, refIdx) => {
|
|
797
|
-
if (rowIdx !== null) {
|
|
798
|
-
refToNewIdx.set(refIdx, nextIdx);
|
|
799
|
-
nextIdx++;
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
alignedContentOrder = m.contentOrder
|
|
803
|
-
.map((entry) => {
|
|
804
|
-
const match = entry.match(ATTACHMENT_ENTRY_RE);
|
|
805
|
-
if (!match) return entry;
|
|
806
|
-
const remapped = refToNewIdx.get(Number(match[1]));
|
|
807
|
-
return remapped !== undefined
|
|
808
|
-
? `attachment:${remapped}`
|
|
809
|
-
: undefined;
|
|
810
|
-
})
|
|
811
|
-
.filter((e): e is string => e !== undefined);
|
|
812
|
-
} else {
|
|
813
|
-
// No refs carried an attachmentId we could match — strip any
|
|
814
|
-
// attachment:N entries so the client doesn't try to position
|
|
815
|
-
// attachments inline against a misaligned array.
|
|
816
|
-
alignedContentOrder = m.contentOrder.filter(
|
|
817
|
-
(entry) => !ATTACHMENT_ENTRY_RE.test(entry),
|
|
818
|
-
);
|
|
819
895
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
896
|
+
const indexMap = new Map<number, number>();
|
|
897
|
+
keepIndices.forEach((oldIdx, newIdx) => indexMap.set(oldIdx, newIdx));
|
|
898
|
+
contentOrder = rendered.contentOrder
|
|
899
|
+
.map((entry) => {
|
|
900
|
+
const tm = entry.match(/^text:(\d+)$/);
|
|
901
|
+
if (!tm) return entry;
|
|
902
|
+
const newIdx = indexMap.get(Number(tm[1]));
|
|
903
|
+
return newIdx !== undefined ? `text:${newIdx}` : undefined;
|
|
904
|
+
})
|
|
905
|
+
.filter((e): e is string => e !== undefined);
|
|
906
|
+
textSegments = filteredSegments;
|
|
907
|
+
text = rendered.text.replace(NO_RESPONSE_INLINE_RE, "").trim();
|
|
908
|
+
contentBlocks = rendered.contentBlocks
|
|
909
|
+
.map((block) =>
|
|
910
|
+
block.type === "text"
|
|
911
|
+
? {
|
|
912
|
+
type: "text" as const,
|
|
913
|
+
text: block.text.replace(NO_RESPONSE_INLINE_RE, "").trim(),
|
|
914
|
+
}
|
|
915
|
+
: block,
|
|
916
|
+
)
|
|
917
|
+
.filter((block) => block.type !== "text" || block.text.length > 0);
|
|
826
918
|
}
|
|
827
919
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
//
|
|
831
|
-
//
|
|
832
|
-
//
|
|
833
|
-
//
|
|
834
|
-
|
|
920
|
+
const alignedContentOrder = aligned.rewriteContentOrder(contentOrder);
|
|
921
|
+
|
|
922
|
+
// Use sentAt (actual event time) for the display timestamp when available,
|
|
923
|
+
// falling back to createdAt (persistence time). Clients use this display
|
|
924
|
+
// timestamp as their pagination cursor after memory-pressure trimming,
|
|
925
|
+
// while server-side pagination filters on createdAt. The mismatch is
|
|
926
|
+
// benign — it may return slightly extra data on a page boundary but never
|
|
927
|
+
// loses messages.
|
|
928
|
+
const displayTimestamp = m.sentAt ?? m.createdAt;
|
|
835
929
|
return {
|
|
836
930
|
id: m.id ?? "",
|
|
931
|
+
...(mergedMessageIds.length > 0 ? { mergedMessageIds } : {}),
|
|
837
932
|
role: m.role,
|
|
838
|
-
|
|
933
|
+
// Flat plain-text body the legacy Swift client reads directly; see the
|
|
934
|
+
// `content` field on ConversationMessageSchema for why this must stay.
|
|
935
|
+
content: text,
|
|
839
936
|
timestamp: new Date(displayTimestamp).toISOString(),
|
|
840
937
|
attachments: msgAttachments,
|
|
841
|
-
...(
|
|
842
|
-
...(
|
|
843
|
-
...(
|
|
844
|
-
...(
|
|
845
|
-
? { thinkingSegments:
|
|
938
|
+
...(toolCalls.length > 0 ? { toolCalls } : {}),
|
|
939
|
+
...(rendered.surfaces.length > 0 ? { surfaces: rendered.surfaces } : {}),
|
|
940
|
+
...(textSegments.length > 0 ? { textSegments } : {}),
|
|
941
|
+
...(rendered.thinkingSegments.length > 0
|
|
942
|
+
? { thinkingSegments: rendered.thinkingSegments }
|
|
846
943
|
: {}),
|
|
847
944
|
...(alignedContentOrder.length > 0
|
|
848
945
|
? { contentOrder: alignedContentOrder }
|
|
849
946
|
: {}),
|
|
947
|
+
...(contentBlocks.length > 0 ? { contentBlocks } : {}),
|
|
850
948
|
...(m.subagentNotification
|
|
851
949
|
? { subagentNotification: m.subagentNotification }
|
|
852
950
|
: {}),
|
|
@@ -854,11 +952,24 @@ export function handleListMessages({
|
|
|
854
952
|
};
|
|
855
953
|
});
|
|
856
954
|
|
|
955
|
+
// Snapshot↔stream alignment token: the `seq` of the last event whose
|
|
956
|
+
// content is durably persisted for this conversation in the current
|
|
957
|
+
// daemon process. Returned on every resolved-conversation response so a
|
|
958
|
+
// client can apply only stream events with a higher `seq`. Null when
|
|
959
|
+
// nothing has been persisted in-process (cold/aged-out/post-restart).
|
|
960
|
+
const persistedSeq = getPersistedSeq(resolvedConversationId);
|
|
961
|
+
|
|
857
962
|
if (isPaginated) {
|
|
963
|
+
// Prefer the page's oldest visible row (the documented cursor semantic).
|
|
964
|
+
// When a scan-cap-truncated page comes back empty there's no visible row
|
|
965
|
+
// to anchor on, so fall back to the resume cursor so the client still gets
|
|
966
|
+
// a `(timestamp, id)` to continue paginating from instead of stalling.
|
|
858
967
|
const oldestTimestamp =
|
|
859
|
-
rawMessages.length > 0
|
|
968
|
+
rawMessages.length > 0
|
|
969
|
+
? rawMessages[0].createdAt
|
|
970
|
+
: scanResumeCursor?.createdAt;
|
|
860
971
|
const oldestMessageId =
|
|
861
|
-
rawMessages.length > 0 ? rawMessages[0].id :
|
|
972
|
+
rawMessages.length > 0 ? rawMessages[0].id : scanResumeCursor?.id;
|
|
862
973
|
// `page=latest` always emits both metadata fields so the web client has
|
|
863
974
|
// a stable contract; emit `null` when the conversation is empty.
|
|
864
975
|
// The existing `beforeTimestamp` branch keeps its conditional shape to
|
|
@@ -869,6 +980,7 @@ export function handleListMessages({
|
|
|
869
980
|
hasMore,
|
|
870
981
|
oldestTimestamp: oldestTimestamp ?? null,
|
|
871
982
|
oldestMessageId: oldestMessageId ?? null,
|
|
983
|
+
seq: persistedSeq,
|
|
872
984
|
};
|
|
873
985
|
}
|
|
874
986
|
|
|
@@ -877,10 +989,11 @@ export function handleListMessages({
|
|
|
877
989
|
hasMore,
|
|
878
990
|
...(oldestTimestamp != null ? { oldestTimestamp } : {}),
|
|
879
991
|
...(oldestMessageId != null ? { oldestMessageId } : {}),
|
|
992
|
+
seq: persistedSeq,
|
|
880
993
|
};
|
|
881
994
|
}
|
|
882
995
|
|
|
883
|
-
return { messages };
|
|
996
|
+
return { messages, seq: persistedSeq };
|
|
884
997
|
}
|
|
885
998
|
|
|
886
999
|
/**
|
|
@@ -1002,13 +1115,15 @@ export async function handleSendMessage(
|
|
|
1002
1115
|
cohort?: string;
|
|
1003
1116
|
websiteUrl?: string;
|
|
1004
1117
|
contentSourceUrl?: string;
|
|
1118
|
+
bootstrapTemplate?: string;
|
|
1119
|
+
initialMessage?: string;
|
|
1120
|
+
skills?: string[];
|
|
1005
1121
|
};
|
|
1006
1122
|
};
|
|
1007
1123
|
|
|
1008
1124
|
const actorPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
1009
1125
|
const principalType = headers?.["x-vellum-principal-type"];
|
|
1010
|
-
const originClientId =
|
|
1011
|
-
headers?.["x-vellum-client-id"]?.trim() || undefined;
|
|
1126
|
+
const originClientId = headers?.["x-vellum-client-id"]?.trim() || undefined;
|
|
1012
1127
|
|
|
1013
1128
|
const { conversationKey, content, attachmentIds } = body;
|
|
1014
1129
|
const inboundConversationId =
|
|
@@ -1149,10 +1264,13 @@ export async function handleSendMessage(
|
|
|
1149
1264
|
// assistant-minted internal id) when the client supplies it — clients
|
|
1150
1265
|
// must obtain this id from a prior daemon response, so a missing row
|
|
1151
1266
|
// is a 404. Otherwise fall through to the external-key path: the
|
|
1152
|
-
// client-supplied `conversationKey` (
|
|
1153
|
-
//
|
|
1154
|
-
// default
|
|
1155
|
-
//
|
|
1267
|
+
// client-supplied `conversationKey` (external-key lookup; materializes
|
|
1268
|
+
// on first use) or, when neither is provided, a channel-dependent
|
|
1269
|
+
// default. The vellum channel mints a fresh conversation on every
|
|
1270
|
+
// empty-handed send so first-message-of-a-new-chat surfaces with a
|
|
1271
|
+
// server-minted id; other channels (phone, slack, …) share a stable
|
|
1272
|
+
// `default:<channel>:<interface>` thread so repeated calls from the
|
|
1273
|
+
// same channel/interface stay co-located.
|
|
1156
1274
|
let mapping: {
|
|
1157
1275
|
conversationId: string;
|
|
1158
1276
|
conversationType: string;
|
|
@@ -1174,7 +1292,9 @@ export async function handleSendMessage(
|
|
|
1174
1292
|
const resolvedConversationKey =
|
|
1175
1293
|
conversationKey && conversationKey.length > 0
|
|
1176
1294
|
? conversationKey
|
|
1177
|
-
:
|
|
1295
|
+
: sourceChannel === "vellum"
|
|
1296
|
+
? crypto.randomUUID()
|
|
1297
|
+
: `default:${sourceChannel}:${sourceInterface}`;
|
|
1178
1298
|
mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1179
1299
|
conversationType: "standard",
|
|
1180
1300
|
});
|
|
@@ -1318,10 +1438,20 @@ export async function handleSendMessage(
|
|
|
1318
1438
|
}
|
|
1319
1439
|
|
|
1320
1440
|
const isInteractive = isInteractiveInterface(sourceInterface);
|
|
1441
|
+
// Use the JWT-verified requester principal — not guardianPrincipalId,
|
|
1442
|
+
// which is the workspace owner and would let a trusted contact's web
|
|
1443
|
+
// turn match against the guardian's macOS client.
|
|
1444
|
+
const sourceActorPrincipalId = actorPrincipalId ?? undefined;
|
|
1321
1445
|
// Bash/File/Transfer singletons are globally available via isAvailable() —
|
|
1322
1446
|
// no per-conversation gating needed. CU is per-conversation (owns step
|
|
1323
1447
|
// count, AX tree history, loop detection).
|
|
1324
|
-
if (
|
|
1448
|
+
if (
|
|
1449
|
+
shouldAttachHostProxyForCapability(
|
|
1450
|
+
"host_cu",
|
|
1451
|
+
sourceInterface,
|
|
1452
|
+
sourceActorPrincipalId,
|
|
1453
|
+
)
|
|
1454
|
+
) {
|
|
1325
1455
|
if (!conversation.isProcessing() || !conversation.hostCuProxy) {
|
|
1326
1456
|
conversation.setHostCuProxy(new HostCuProxy());
|
|
1327
1457
|
}
|
|
@@ -1334,7 +1464,13 @@ export async function handleSendMessage(
|
|
|
1334
1464
|
// lives in the skill-projection layer (which reads the `feature-flag:
|
|
1335
1465
|
// app-control` declaration in SKILL.md frontmatter), so an attached proxy
|
|
1336
1466
|
// is harmless when the flag resolves to off.
|
|
1337
|
-
if (
|
|
1467
|
+
if (
|
|
1468
|
+
shouldAttachHostProxyForCapability(
|
|
1469
|
+
"host_app_control",
|
|
1470
|
+
sourceInterface,
|
|
1471
|
+
sourceActorPrincipalId,
|
|
1472
|
+
)
|
|
1473
|
+
) {
|
|
1338
1474
|
if (!conversation.isProcessing() || !conversation.hostAppControlProxy) {
|
|
1339
1475
|
conversation.setHostAppControlProxy(
|
|
1340
1476
|
new HostAppControlProxy(mapping.conversationId),
|
|
@@ -1347,7 +1483,11 @@ export async function handleSendMessage(
|
|
|
1347
1483
|
// this message will be queued and preactivation is deferred to dequeue
|
|
1348
1484
|
// time in drainQueueImpl to avoid mutating in-flight turn state.
|
|
1349
1485
|
if (!conversation.isProcessing()) {
|
|
1350
|
-
preactivateHostProxySkills(
|
|
1486
|
+
preactivateHostProxySkills(
|
|
1487
|
+
conversation,
|
|
1488
|
+
sourceInterface,
|
|
1489
|
+
sourceActorPrincipalId,
|
|
1490
|
+
);
|
|
1351
1491
|
}
|
|
1352
1492
|
// Wire sendToClient to the SSE hub so all subsystems can reach the HTTP client.
|
|
1353
1493
|
// hasNoClient must remain `!isInteractive` so downstream tool gating
|
|
@@ -1380,6 +1520,16 @@ export async function handleSendMessage(
|
|
|
1380
1520
|
conversation.getMessages().length,
|
|
1381
1521
|
);
|
|
1382
1522
|
const isScanPath = !!scanUrl && isWakeUp;
|
|
1523
|
+
// Self-intro path: when we know a name, send a natural introduction on the
|
|
1524
|
+
// user's behalf instead of the canned greeting, so the assistant generates a
|
|
1525
|
+
// real first response. Gated behind the `self-intro-greeting` flag (default
|
|
1526
|
+
// off); `undefined` (flag off or no names) falls back to the canned path.
|
|
1527
|
+
const selfIntroGreetingEnabled =
|
|
1528
|
+
isWakeUp &&
|
|
1529
|
+
isAssistantFeatureFlagEnabled(SELF_INTRO_GREETING_FLAG, getConfig());
|
|
1530
|
+
const selfIntro = selfIntroGreetingEnabled
|
|
1531
|
+
? buildSelfIntroMessage(body.onboarding ?? undefined)
|
|
1532
|
+
: undefined;
|
|
1383
1533
|
|
|
1384
1534
|
let effectiveContent: string | undefined;
|
|
1385
1535
|
if (isScanPath) {
|
|
@@ -1388,55 +1538,46 @@ export async function handleSendMessage(
|
|
|
1388
1538
|
: ("content-source" as const);
|
|
1389
1539
|
effectiveContent = buildScanFirstMessage(scanUrl, scanVariant);
|
|
1390
1540
|
// Fall through to normal inference path below
|
|
1391
|
-
} else if (
|
|
1392
|
-
effectiveContent =
|
|
1393
|
-
|
|
1394
|
-
//
|
|
1541
|
+
} else if (selfIntroGreetingEnabled && body.onboarding?.initialMessage) {
|
|
1542
|
+
effectiveContent = body.onboarding.initialMessage;
|
|
1543
|
+
} else if (isWakeUp && selfIntro) {
|
|
1544
|
+
// Rewrite to the self-introduction and fall through to real inference
|
|
1545
|
+
// (mirrors the scan path above).
|
|
1546
|
+
effectiveContent = selfIntro;
|
|
1395
1547
|
} else if (isWakeUp) {
|
|
1396
1548
|
const cannedGreeting = getCannedFirstGreeting(body.onboarding ?? undefined);
|
|
1397
1549
|
|
|
1398
|
-
conversation.
|
|
1550
|
+
conversation.setProcessing(true);
|
|
1399
1551
|
let cleanupDeferred = false;
|
|
1400
1552
|
try {
|
|
1401
|
-
const
|
|
1402
|
-
const
|
|
1403
|
-
|
|
1553
|
+
const rawContent = content ?? "";
|
|
1554
|
+
const attachments = hasAttachments
|
|
1555
|
+
? smDeps.resolveAttachments(attachmentIds)
|
|
1556
|
+
: [];
|
|
1557
|
+
const greetingMeta = {
|
|
1404
1558
|
userMessageChannel: sourceChannel,
|
|
1405
1559
|
assistantMessageChannel: sourceChannel,
|
|
1406
1560
|
userMessageInterface: sourceInterface,
|
|
1407
1561
|
assistantMessageInterface: sourceInterface,
|
|
1408
1562
|
};
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
:
|
|
1414
|
-
|
|
1415
|
-
const persisted = await addMessage(
|
|
1416
|
-
mapping.conversationId,
|
|
1417
|
-
"user",
|
|
1418
|
-
JSON.stringify(userMsg.content),
|
|
1419
|
-
channelMeta,
|
|
1420
|
-
);
|
|
1421
|
-
conversation.getMessages().push(userMsg);
|
|
1422
|
-
|
|
1423
|
-
setConversationOriginChannelIfUnset(
|
|
1424
|
-
mapping.conversationId,
|
|
1425
|
-
sourceChannel,
|
|
1426
|
-
);
|
|
1427
|
-
setConversationOriginInterfaceIfUnset(
|
|
1428
|
-
mapping.conversationId,
|
|
1429
|
-
sourceInterface,
|
|
1430
|
-
);
|
|
1563
|
+
const persisted = await persistQueuedMessageBody(conversation, {
|
|
1564
|
+
content: rawContent,
|
|
1565
|
+
attachments,
|
|
1566
|
+
requestId: crypto.randomUUID(),
|
|
1567
|
+
metadata: greetingMeta,
|
|
1568
|
+
});
|
|
1431
1569
|
|
|
1432
1570
|
const conversationId = mapping.conversationId;
|
|
1571
|
+
const channelMeta = buildChannelMetadata(sourceChannel, sourceInterface, {
|
|
1572
|
+
trustContext: conversation.trustContext,
|
|
1573
|
+
});
|
|
1433
1574
|
|
|
1434
1575
|
const assistantMsg = createAssistantMessage(cannedGreeting);
|
|
1435
1576
|
const persistedAssistant = await addMessage(
|
|
1436
1577
|
mapping.conversationId,
|
|
1437
1578
|
"assistant",
|
|
1438
1579
|
JSON.stringify(assistantMsg.content),
|
|
1439
|
-
channelMeta,
|
|
1580
|
+
{ metadata: channelMeta },
|
|
1440
1581
|
);
|
|
1441
1582
|
conversation.getMessages().push(assistantMsg);
|
|
1442
1583
|
|
|
@@ -1482,7 +1623,7 @@ export async function handleSendMessage(
|
|
|
1482
1623
|
persistedAssistant.id,
|
|
1483
1624
|
);
|
|
1484
1625
|
publishConversationMessagesChanged(conversationId, originClientId);
|
|
1485
|
-
conversation.
|
|
1626
|
+
conversation.setProcessing(false);
|
|
1486
1627
|
silentlyWithLog(
|
|
1487
1628
|
conversation.drainQueue(),
|
|
1488
1629
|
"canned-greeting queue drain",
|
|
@@ -1498,8 +1639,8 @@ export async function handleSendMessage(
|
|
|
1498
1639
|
cleanupDeferred = true;
|
|
1499
1640
|
return response;
|
|
1500
1641
|
} finally {
|
|
1501
|
-
if (!cleanupDeferred && conversation.
|
|
1502
|
-
conversation.
|
|
1642
|
+
if (!cleanupDeferred && conversation.isProcessing()) {
|
|
1643
|
+
conversation.setProcessing(false);
|
|
1503
1644
|
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1504
1645
|
}
|
|
1505
1646
|
}
|
|
@@ -1580,25 +1721,22 @@ export async function handleSendMessage(
|
|
|
1580
1721
|
if (conversation.isProcessing()) {
|
|
1581
1722
|
// Queue the message so it's processed when the current turn completes
|
|
1582
1723
|
const requestId = crypto.randomUUID();
|
|
1583
|
-
const enqueueResult = conversation.enqueueMessage(
|
|
1584
|
-
contentAfterScan,
|
|
1724
|
+
const enqueueResult = conversation.enqueueMessage({
|
|
1725
|
+
content: contentAfterScan,
|
|
1585
1726
|
attachments,
|
|
1586
|
-
broadcastMessage,
|
|
1727
|
+
onEvent: broadcastMessage,
|
|
1587
1728
|
requestId,
|
|
1588
|
-
|
|
1589
|
-
undefined, // currentPage
|
|
1590
|
-
{
|
|
1729
|
+
metadata: {
|
|
1591
1730
|
userMessageChannel: sourceChannel,
|
|
1592
1731
|
assistantMessageChannel: sourceChannel,
|
|
1593
1732
|
userMessageInterface: sourceInterface,
|
|
1594
1733
|
assistantMessageInterface: sourceInterface,
|
|
1595
1734
|
...(body.automated === true ? { automated: true } : {}),
|
|
1596
1735
|
},
|
|
1597
|
-
|
|
1598
|
-
undefined, // displayContent
|
|
1736
|
+
isInteractive,
|
|
1599
1737
|
transport,
|
|
1600
1738
|
clientMessageId,
|
|
1601
|
-
);
|
|
1739
|
+
});
|
|
1602
1740
|
if (enqueueResult.rejected) {
|
|
1603
1741
|
return new RouteResponse(
|
|
1604
1742
|
JSON.stringify({ accepted: false, error: "queue_full" }),
|
|
@@ -1715,56 +1853,43 @@ export async function handleSendMessage(
|
|
|
1715
1853
|
const slashResult = await resolveSlash(rawContent, slashContext);
|
|
1716
1854
|
|
|
1717
1855
|
if (slashResult.kind === "unknown") {
|
|
1718
|
-
conversation.
|
|
1856
|
+
conversation.setProcessing(true);
|
|
1719
1857
|
let cleanupDeferred = false;
|
|
1720
1858
|
try {
|
|
1721
|
-
const
|
|
1722
|
-
const imageSourcePaths: Record<string, string> = {};
|
|
1723
|
-
for (let i = 0; i < attachments.length; i++) {
|
|
1724
|
-
const a = attachments[i];
|
|
1725
|
-
if (a.filePath && a.mimeType.toLowerCase().startsWith("image/")) {
|
|
1726
|
-
imageSourcePaths[`${i}:${a.filename}`] = a.filePath;
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
const channelMeta = {
|
|
1730
|
-
...provenance,
|
|
1859
|
+
const slashMeta = {
|
|
1731
1860
|
userMessageChannel: sourceChannel,
|
|
1732
1861
|
assistantMessageChannel: sourceChannel,
|
|
1733
1862
|
userMessageInterface: sourceInterface,
|
|
1734
1863
|
assistantMessageInterface: sourceInterface,
|
|
1735
1864
|
...(body.automated === true ? { automated: true } : {}),
|
|
1736
|
-
...(Object.keys(imageSourcePaths).length > 0
|
|
1737
|
-
? { imageSourcePaths }
|
|
1738
|
-
: {}),
|
|
1739
1865
|
};
|
|
1740
|
-
const
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
)
|
|
1748
|
-
|
|
1866
|
+
const persisted = await persistQueuedMessageBody(conversation, {
|
|
1867
|
+
content: rawContent,
|
|
1868
|
+
attachments,
|
|
1869
|
+
requestId: crypto.randomUUID(),
|
|
1870
|
+
metadata: slashMeta,
|
|
1871
|
+
clientMessageId,
|
|
1872
|
+
});
|
|
1873
|
+
if (persisted.deduplicated) {
|
|
1874
|
+
return {
|
|
1875
|
+
accepted: true,
|
|
1876
|
+
messageId: persisted.id,
|
|
1877
|
+
conversationId: mapping.conversationId,
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1749
1880
|
|
|
1881
|
+
const channelMeta = buildChannelMetadata(sourceChannel, sourceInterface, {
|
|
1882
|
+
trustContext: conversation.trustContext,
|
|
1883
|
+
});
|
|
1750
1884
|
const assistantMsg = createAssistantMessage(slashResult.message);
|
|
1751
1885
|
const persistedAssistant = await addMessage(
|
|
1752
1886
|
mapping.conversationId,
|
|
1753
1887
|
"assistant",
|
|
1754
1888
|
JSON.stringify(assistantMsg.content),
|
|
1755
|
-
channelMeta,
|
|
1889
|
+
{ metadata: channelMeta },
|
|
1756
1890
|
);
|
|
1757
1891
|
conversation.getMessages().push(assistantMsg);
|
|
1758
1892
|
|
|
1759
|
-
setConversationOriginChannelIfUnset(
|
|
1760
|
-
mapping.conversationId,
|
|
1761
|
-
sourceChannel,
|
|
1762
|
-
);
|
|
1763
|
-
setConversationOriginInterfaceIfUnset(
|
|
1764
|
-
mapping.conversationId,
|
|
1765
|
-
sourceInterface,
|
|
1766
|
-
);
|
|
1767
|
-
|
|
1768
1893
|
// Snapshot model info now so the deferred callback cannot observe
|
|
1769
1894
|
// a config change from a concurrent request.
|
|
1770
1895
|
const modelInfoEvent = isModelSlashCommand(rawContent)
|
|
@@ -1809,7 +1934,7 @@ export async function handleSendMessage(
|
|
|
1809
1934
|
persistedAssistant.id,
|
|
1810
1935
|
);
|
|
1811
1936
|
publishConversationMessagesChanged(conversationId, originClientId);
|
|
1812
|
-
conversation.
|
|
1937
|
+
conversation.setProcessing(false);
|
|
1813
1938
|
silentlyWithLog(conversation.drainQueue(), "slash-command queue drain");
|
|
1814
1939
|
}, 0);
|
|
1815
1940
|
|
|
@@ -1818,43 +1943,52 @@ export async function handleSendMessage(
|
|
|
1818
1943
|
} finally {
|
|
1819
1944
|
// No-op for the slash-command early-return path (handled inside
|
|
1820
1945
|
// setTimeout above), but still needed for error paths.
|
|
1821
|
-
if (!cleanupDeferred && conversation.
|
|
1822
|
-
conversation.
|
|
1946
|
+
if (!cleanupDeferred && conversation.isProcessing()) {
|
|
1947
|
+
conversation.setProcessing(false);
|
|
1823
1948
|
silentlyWithLog(conversation.drainQueue(), "error-path queue drain");
|
|
1824
1949
|
}
|
|
1825
1950
|
}
|
|
1826
1951
|
}
|
|
1827
1952
|
|
|
1828
1953
|
if (slashResult.kind === "compact") {
|
|
1829
|
-
conversation.
|
|
1830
|
-
const
|
|
1831
|
-
const channelMeta = {
|
|
1832
|
-
...provenance,
|
|
1954
|
+
conversation.setProcessing(true);
|
|
1955
|
+
const slashMeta = {
|
|
1833
1956
|
userMessageChannel: sourceChannel,
|
|
1834
1957
|
assistantMessageChannel: sourceChannel,
|
|
1835
1958
|
userMessageInterface: sourceInterface,
|
|
1836
1959
|
assistantMessageInterface: sourceInterface,
|
|
1837
1960
|
};
|
|
1838
|
-
|
|
1839
|
-
let persisted: Awaited<ReturnType<typeof addMessage>>;
|
|
1961
|
+
let persisted: Awaited<ReturnType<typeof persistQueuedMessageBody>>;
|
|
1840
1962
|
try {
|
|
1841
|
-
persisted = await
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1963
|
+
persisted = await persistQueuedMessageBody(conversation, {
|
|
1964
|
+
content: rawContent,
|
|
1965
|
+
attachments,
|
|
1966
|
+
requestId: crypto.randomUUID(),
|
|
1967
|
+
metadata: slashMeta,
|
|
1968
|
+
clientMessageId,
|
|
1969
|
+
});
|
|
1847
1970
|
} catch (err) {
|
|
1848
1971
|
// The fire-and-forget compaction below owns clearing `processing`, but a
|
|
1849
1972
|
// throw from this initial persist never reaches it — reset here so the
|
|
1850
1973
|
// conversation isn't stranded in queued mode.
|
|
1851
|
-
conversation.
|
|
1974
|
+
conversation.setProcessing(false);
|
|
1852
1975
|
silentlyWithLog(conversation.drainQueue(), "compact-command queue drain");
|
|
1853
1976
|
throw err;
|
|
1854
1977
|
}
|
|
1855
|
-
|
|
1978
|
+
if (persisted.deduplicated) {
|
|
1979
|
+
conversation.setProcessing(false);
|
|
1980
|
+
silentlyWithLog(conversation.drainQueue(), "compact-dedup queue drain");
|
|
1981
|
+
return {
|
|
1982
|
+
accepted: true,
|
|
1983
|
+
messageId: persisted.id,
|
|
1984
|
+
conversationId: mapping.conversationId,
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1856
1987
|
|
|
1857
1988
|
const conversationId = mapping.conversationId;
|
|
1989
|
+
const channelMeta = buildChannelMetadata(sourceChannel, sourceInterface, {
|
|
1990
|
+
trustContext: conversation.trustContext,
|
|
1991
|
+
});
|
|
1858
1992
|
|
|
1859
1993
|
// Fire-and-forget: return 202 immediately, run compaction async.
|
|
1860
1994
|
// forceCompact() makes an LLM call that can exceed the client's
|
|
@@ -1870,14 +2004,8 @@ export async function handleSendMessage(
|
|
|
1870
2004
|
clientMessageId,
|
|
1871
2005
|
});
|
|
1872
2006
|
publishConversationMessagesChanged(conversationId, originClientId);
|
|
1873
|
-
conversation.emitActivityState(
|
|
1874
|
-
|
|
1875
|
-
"context_compacting",
|
|
1876
|
-
"assistant_turn",
|
|
1877
|
-
);
|
|
1878
|
-
const result = await conversation.forceCompact({
|
|
1879
|
-
targetInputTokensOverride: slashResult.targetInputTokensOverride,
|
|
1880
|
-
});
|
|
2007
|
+
conversation.emitActivityState("thinking", "context_compacting");
|
|
2008
|
+
const result = await conversation.forceCompact();
|
|
1881
2009
|
const responseText = formatCompactResult(result);
|
|
1882
2010
|
|
|
1883
2011
|
const assistantMsg = createAssistantMessage(responseText);
|
|
@@ -1885,7 +2013,7 @@ export async function handleSendMessage(
|
|
|
1885
2013
|
conversationId,
|
|
1886
2014
|
"assistant",
|
|
1887
2015
|
JSON.stringify(assistantMsg.content),
|
|
1888
|
-
channelMeta,
|
|
2016
|
+
{ metadata: channelMeta },
|
|
1889
2017
|
);
|
|
1890
2018
|
assistantMessagePersisted = true;
|
|
1891
2019
|
conversation.getMessages().push(assistantMsg);
|
|
@@ -1914,7 +2042,7 @@ export async function handleSendMessage(
|
|
|
1914
2042
|
retryable: true,
|
|
1915
2043
|
});
|
|
1916
2044
|
} finally {
|
|
1917
|
-
conversation.
|
|
2045
|
+
conversation.setProcessing(false);
|
|
1918
2046
|
silentlyWithLog(
|
|
1919
2047
|
conversation.drainQueue(),
|
|
1920
2048
|
"compact-command queue drain",
|
|
@@ -1930,30 +2058,37 @@ export async function handleSendMessage(
|
|
|
1930
2058
|
}
|
|
1931
2059
|
|
|
1932
2060
|
if (slashResult.kind === "clean") {
|
|
1933
|
-
conversation.
|
|
2061
|
+
conversation.setProcessing(true);
|
|
1934
2062
|
const conversationId = mapping.conversationId;
|
|
1935
2063
|
// Outer try/finally guarantees the processing flag is cleared (and the
|
|
1936
2064
|
// queue drained) on every failure path — including a throw from the
|
|
1937
2065
|
// initial user-message persist below, which would otherwise leave the
|
|
1938
2066
|
// conversation stuck in queued mode indefinitely.
|
|
1939
2067
|
try {
|
|
1940
|
-
const
|
|
1941
|
-
const channelMeta = {
|
|
1942
|
-
...provenance,
|
|
2068
|
+
const slashMeta = {
|
|
1943
2069
|
userMessageChannel: sourceChannel,
|
|
1944
2070
|
assistantMessageChannel: sourceChannel,
|
|
1945
2071
|
userMessageInterface: sourceInterface,
|
|
1946
2072
|
assistantMessageInterface: sourceInterface,
|
|
1947
2073
|
};
|
|
1948
|
-
const
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
);
|
|
1955
|
-
|
|
2074
|
+
const persisted = await persistQueuedMessageBody(conversation, {
|
|
2075
|
+
content: rawContent,
|
|
2076
|
+
attachments,
|
|
2077
|
+
requestId: crypto.randomUUID(),
|
|
2078
|
+
metadata: slashMeta,
|
|
2079
|
+
clientMessageId,
|
|
2080
|
+
});
|
|
2081
|
+
if (persisted.deduplicated) {
|
|
2082
|
+
return {
|
|
2083
|
+
accepted: true,
|
|
2084
|
+
messageId: persisted.id,
|
|
2085
|
+
conversationId,
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
1956
2088
|
|
|
2089
|
+
const channelMeta = buildChannelMetadata(sourceChannel, sourceInterface, {
|
|
2090
|
+
trustContext: conversation.trustContext,
|
|
2091
|
+
});
|
|
1957
2092
|
let assistantMessagePersisted = false;
|
|
1958
2093
|
try {
|
|
1959
2094
|
broadcastMessage({
|
|
@@ -1973,7 +2108,7 @@ export async function handleSendMessage(
|
|
|
1973
2108
|
conversationId,
|
|
1974
2109
|
"assistant",
|
|
1975
2110
|
JSON.stringify(assistantMsg.content),
|
|
1976
|
-
channelMeta,
|
|
2111
|
+
{ metadata: channelMeta },
|
|
1977
2112
|
);
|
|
1978
2113
|
assistantMessagePersisted = true;
|
|
1979
2114
|
conversation.getMessages().push(assistantMsg);
|
|
@@ -2009,7 +2144,7 @@ export async function handleSendMessage(
|
|
|
2009
2144
|
conversationId,
|
|
2010
2145
|
};
|
|
2011
2146
|
} finally {
|
|
2012
|
-
conversation.
|
|
2147
|
+
conversation.setProcessing(false);
|
|
2013
2148
|
silentlyWithLog(conversation.drainQueue(), "clean-command queue drain");
|
|
2014
2149
|
}
|
|
2015
2150
|
}
|
|
@@ -2017,16 +2152,22 @@ export async function handleSendMessage(
|
|
|
2017
2152
|
const resolvedContent = slashResult.content;
|
|
2018
2153
|
|
|
2019
2154
|
const requestId = crypto.randomUUID();
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2155
|
+
const persistResult = await conversation.persistUserMessage({
|
|
2156
|
+
content: resolvedContent,
|
|
2157
|
+
attachments,
|
|
2158
|
+
requestId,
|
|
2159
|
+
metadata: body.automated === true ? { automated: true } : undefined,
|
|
2160
|
+
clientMessageId,
|
|
2161
|
+
});
|
|
2162
|
+
|
|
2163
|
+
const messageId = persistResult.id;
|
|
2164
|
+
|
|
2165
|
+
if (persistResult.deduplicated) {
|
|
2166
|
+
return {
|
|
2167
|
+
accepted: true,
|
|
2168
|
+
messageId,
|
|
2169
|
+
conversationId: mapping.conversationId,
|
|
2170
|
+
};
|
|
2030
2171
|
}
|
|
2031
2172
|
|
|
2032
2173
|
broadcastMessage({
|
|
@@ -2041,7 +2182,8 @@ export async function handleSendMessage(
|
|
|
2041
2182
|
|
|
2042
2183
|
// Fire-and-forget the agent loop; events flow to the hub via broadcastMessage.
|
|
2043
2184
|
conversation
|
|
2044
|
-
.runAgentLoop(resolvedContent, messageId,
|
|
2185
|
+
.runAgentLoop(resolvedContent, messageId, {
|
|
2186
|
+
onEvent: broadcastMessage,
|
|
2045
2187
|
isInteractive,
|
|
2046
2188
|
isUserMessage: true,
|
|
2047
2189
|
})
|
|
@@ -2088,8 +2230,8 @@ async function generateLlmSuggestion(
|
|
|
2088
2230
|
"",
|
|
2089
2231
|
"CRITICAL — write from the USER'S perspective only, NEVER from the assistant's:",
|
|
2090
2232
|
"- The suggestion is what the USER will type into the chat input",
|
|
2091
|
-
|
|
2092
|
-
|
|
2233
|
+
'- Use first-person "I" only if the user has used it in their prior messages',
|
|
2234
|
+
'- NEVER start with phrases like "I can help", "Here\'s what", "Let me", "I\'d suggest" — those are assistant-voice',
|
|
2093
2235
|
"- Think: if you were the user reading the assistant's reply, what question or follow-up would you ask next?",
|
|
2094
2236
|
"",
|
|
2095
2237
|
"Output only the reply text inside the requested tags — no preamble, no commentary.",
|
|
@@ -2119,9 +2261,10 @@ async function generateLlmSuggestion(
|
|
|
2119
2261
|
// tokens here would be wasteful.
|
|
2120
2262
|
const response = await provider.sendMessage(
|
|
2121
2263
|
[{ role: "user", content: [{ type: "text", text: userPrompt }] }],
|
|
2122
|
-
[], // no tools
|
|
2123
|
-
systemPrompt,
|
|
2124
2264
|
{
|
|
2265
|
+
tools: [],
|
|
2266
|
+
// no tools
|
|
2267
|
+
systemPrompt,
|
|
2125
2268
|
config: {
|
|
2126
2269
|
callSite: "replySuggestion",
|
|
2127
2270
|
max_tokens: 60,
|
|
@@ -2342,6 +2485,47 @@ function handleSearchConversations({
|
|
|
2342
2485
|
return { query, results };
|
|
2343
2486
|
}
|
|
2344
2487
|
|
|
2488
|
+
// ---------------------------------------------------------------------------
|
|
2489
|
+
// Metadata helpers
|
|
2490
|
+
// ---------------------------------------------------------------------------
|
|
2491
|
+
|
|
2492
|
+
/**
|
|
2493
|
+
* Assemble the standard channel metadata object for message persistence.
|
|
2494
|
+
*
|
|
2495
|
+
* Combines provenance (trust context), channel/interface routing, and
|
|
2496
|
+
* optional per-message fields (automated flag, image source paths) into the
|
|
2497
|
+
* Record that `addMessage` stores in the `metadata` column.
|
|
2498
|
+
*/
|
|
2499
|
+
function buildChannelMetadata(
|
|
2500
|
+
sourceChannel: string,
|
|
2501
|
+
sourceInterface: string,
|
|
2502
|
+
opts?: {
|
|
2503
|
+
trustContext?: Parameters<typeof provenanceFromTrustContext>[0];
|
|
2504
|
+
provenanceOverride?: Record<string, unknown>;
|
|
2505
|
+
automated?: boolean;
|
|
2506
|
+
attachments?: ReadonlyArray<{
|
|
2507
|
+
filename: string;
|
|
2508
|
+
mimeType: string;
|
|
2509
|
+
filePath?: string;
|
|
2510
|
+
}>;
|
|
2511
|
+
},
|
|
2512
|
+
): Record<string, unknown> {
|
|
2513
|
+
const provenance =
|
|
2514
|
+
opts?.provenanceOverride ?? provenanceFromTrustContext(opts?.trustContext);
|
|
2515
|
+
const imageSourcePaths = opts?.attachments
|
|
2516
|
+
? extractImageSourcePaths(opts.attachments)
|
|
2517
|
+
: undefined;
|
|
2518
|
+
return {
|
|
2519
|
+
...provenance,
|
|
2520
|
+
userMessageChannel: sourceChannel,
|
|
2521
|
+
assistantMessageChannel: sourceChannel,
|
|
2522
|
+
userMessageInterface: sourceInterface,
|
|
2523
|
+
assistantMessageInterface: sourceInterface,
|
|
2524
|
+
...(opts?.automated ? { automated: true } : {}),
|
|
2525
|
+
...(imageSourcePaths ? { imageSourcePaths } : {}),
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2345
2529
|
// ---------------------------------------------------------------------------
|
|
2346
2530
|
// Module-level state
|
|
2347
2531
|
// ---------------------------------------------------------------------------
|
|
@@ -2372,12 +2556,54 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2372
2556
|
operationId: "messages_get",
|
|
2373
2557
|
endpoint: "messages",
|
|
2374
2558
|
method: "GET",
|
|
2559
|
+
policy: {
|
|
2560
|
+
requiredScopes: ["chat.read"],
|
|
2561
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
2562
|
+
},
|
|
2375
2563
|
summary: "List messages",
|
|
2376
2564
|
description:
|
|
2377
2565
|
"Return messages for a conversation, including attachments and interface file metadata.",
|
|
2378
2566
|
tags: ["messages"],
|
|
2567
|
+
queryParams: [
|
|
2568
|
+
{
|
|
2569
|
+
name: "conversationId",
|
|
2570
|
+
type: "string",
|
|
2571
|
+
required: false,
|
|
2572
|
+
description:
|
|
2573
|
+
"Conversation UUID. One of conversationId or conversationKey is required.",
|
|
2574
|
+
},
|
|
2575
|
+
{
|
|
2576
|
+
name: "conversationKey",
|
|
2577
|
+
type: "string",
|
|
2578
|
+
required: false,
|
|
2579
|
+
description:
|
|
2580
|
+
"Channel/external conversation key. One of conversationId or conversationKey is required.",
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
name: "page",
|
|
2584
|
+
type: "string",
|
|
2585
|
+
required: false,
|
|
2586
|
+
description:
|
|
2587
|
+
"When set to 'latest', returns the most recent page of messages with pagination metadata.",
|
|
2588
|
+
},
|
|
2589
|
+
{
|
|
2590
|
+
name: "beforeTimestamp",
|
|
2591
|
+
type: "integer",
|
|
2592
|
+
required: false,
|
|
2593
|
+
description:
|
|
2594
|
+
"Return messages older than this timestamp (ms since epoch). Used for paging older history.",
|
|
2595
|
+
},
|
|
2596
|
+
{
|
|
2597
|
+
name: "limit",
|
|
2598
|
+
type: "integer",
|
|
2599
|
+
required: false,
|
|
2600
|
+
description: "Maximum number of messages to return.",
|
|
2601
|
+
},
|
|
2602
|
+
],
|
|
2379
2603
|
responseBody: z.object({
|
|
2380
|
-
messages: z
|
|
2604
|
+
messages: z
|
|
2605
|
+
.array(ConversationMessageSchema)
|
|
2606
|
+
.describe("Array of message objects"),
|
|
2381
2607
|
hasMore: z
|
|
2382
2608
|
.boolean()
|
|
2383
2609
|
.optional()
|
|
@@ -2394,6 +2620,13 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2394
2620
|
.nullable()
|
|
2395
2621
|
.optional()
|
|
2396
2622
|
.describe("ID of the oldest message in this page"),
|
|
2623
|
+
seq: z
|
|
2624
|
+
.number()
|
|
2625
|
+
.nullable()
|
|
2626
|
+
.optional()
|
|
2627
|
+
.describe(
|
|
2628
|
+
"Global SSE `seq` of the last event whose content is durably persisted for this conversation in the current daemon process. A client can align this snapshot with the `/events` stream by applying only events with `seq` greater than this value. Null when no events have been persisted in this process (cold conversation, after a daemon restart, or when the conversation has aged out of the in-memory map) — clients should cold-start in that case. Absent on older daemons that predate this field.",
|
|
2629
|
+
),
|
|
2397
2630
|
}),
|
|
2398
2631
|
handler: (args) => handleListMessages(args),
|
|
2399
2632
|
},
|
|
@@ -2401,23 +2634,70 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2401
2634
|
operationId: "messages_post",
|
|
2402
2635
|
endpoint: "messages",
|
|
2403
2636
|
method: "POST",
|
|
2637
|
+
policy: {
|
|
2638
|
+
requiredScopes: ["chat.write"],
|
|
2639
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
2640
|
+
},
|
|
2404
2641
|
summary: "Send a message",
|
|
2405
2642
|
description:
|
|
2406
2643
|
"Send a user message to a conversation and trigger the assistant response.",
|
|
2407
2644
|
tags: ["messages"],
|
|
2408
2645
|
responseStatus: "202",
|
|
2409
2646
|
requestBody: z.object({
|
|
2410
|
-
|
|
2647
|
+
conversationId: z
|
|
2648
|
+
.string()
|
|
2649
|
+
.nullable()
|
|
2650
|
+
.optional()
|
|
2651
|
+
.describe(
|
|
2652
|
+
"Internal conversation id (0.8.6+ strict lookup). Omit both id and key to mint a new conversation server-side.",
|
|
2653
|
+
),
|
|
2654
|
+
conversationKey: z.string().nullable().optional(),
|
|
2411
2655
|
content: z.string().describe("Message text content"),
|
|
2412
2656
|
attachments: z
|
|
2413
2657
|
.array(z.unknown())
|
|
2414
|
-
.describe("Optional file attachments")
|
|
2658
|
+
.describe("Optional inline file attachments")
|
|
2659
|
+
.optional(),
|
|
2660
|
+
attachmentIds: z
|
|
2661
|
+
.array(z.string())
|
|
2662
|
+
.describe("Ids of previously uploaded attachments to attach")
|
|
2415
2663
|
.optional(),
|
|
2664
|
+
sourceChannel: z
|
|
2665
|
+
.string()
|
|
2666
|
+
.describe('Originating channel id (e.g. "vellum")'),
|
|
2667
|
+
interface: z
|
|
2668
|
+
.string()
|
|
2669
|
+
.describe('Originating interface id (e.g. "vellum")'),
|
|
2416
2670
|
conversationType: z.string().optional(),
|
|
2417
2671
|
slashCommand: z.string().optional(),
|
|
2418
2672
|
clientTimezone: z.string().optional(),
|
|
2419
2673
|
inferenceProfile: z.string().nullable().optional(),
|
|
2420
2674
|
riskThreshold: z.enum(VALID_RISK_THRESHOLDS).optional(),
|
|
2675
|
+
onboarding: z
|
|
2676
|
+
.object({
|
|
2677
|
+
tools: z.array(z.string()),
|
|
2678
|
+
tasks: z.array(z.string()),
|
|
2679
|
+
tone: z.string(),
|
|
2680
|
+
userName: z.string().optional(),
|
|
2681
|
+
assistantName: z.string().optional(),
|
|
2682
|
+
googleConnected: z.boolean().optional(),
|
|
2683
|
+
googleScopes: z.array(z.string()).optional(),
|
|
2684
|
+
priorAssistants: z.array(z.string()).optional(),
|
|
2685
|
+
cohort: z.string().optional(),
|
|
2686
|
+
websiteUrl: z.string().optional(),
|
|
2687
|
+
contentSourceUrl: z.string().optional(),
|
|
2688
|
+
bootstrapTemplate: z.string().optional(),
|
|
2689
|
+
initialMessage: z.string().optional(),
|
|
2690
|
+
skills: z.array(z.string()).optional(),
|
|
2691
|
+
})
|
|
2692
|
+
.describe("PreChat onboarding context, sent on the first message only")
|
|
2693
|
+
.optional(),
|
|
2694
|
+
}),
|
|
2695
|
+
responseBody: z.object({
|
|
2696
|
+
accepted: z.boolean(),
|
|
2697
|
+
conversationId: z.string().optional(),
|
|
2698
|
+
messageId: z.string().optional(),
|
|
2699
|
+
queued: z.boolean().optional(),
|
|
2700
|
+
requestId: z.string().optional(),
|
|
2421
2701
|
}),
|
|
2422
2702
|
handler: async (args) =>
|
|
2423
2703
|
handleSendMessage(args, {
|
|
@@ -2433,6 +2713,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2433
2713
|
operationId: "search_get",
|
|
2434
2714
|
endpoint: "search",
|
|
2435
2715
|
method: "GET",
|
|
2716
|
+
policy: {
|
|
2717
|
+
requiredScopes: ["chat.read"],
|
|
2718
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
2719
|
+
},
|
|
2436
2720
|
summary: "Search conversations",
|
|
2437
2721
|
description: "Full-text search across all conversations.",
|
|
2438
2722
|
tags: ["conversations"],
|
|
@@ -2446,6 +2730,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2446
2730
|
operationId: "suggestion_get",
|
|
2447
2731
|
endpoint: "suggestion",
|
|
2448
2732
|
method: "GET",
|
|
2733
|
+
policy: {
|
|
2734
|
+
requiredScopes: ["chat.read"],
|
|
2735
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
2736
|
+
},
|
|
2449
2737
|
summary: "Get reply suggestion",
|
|
2450
2738
|
description:
|
|
2451
2739
|
"Return an LLM-generated follow-up suggestion for the most recent assistant message.",
|