@vellumai/assistant 0.8.5 → 0.8.7
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 +1 -0
- package/bun.lock +11 -2
- package/bunfig.toml +6 -1
- package/docker-entrypoint.sh +8 -6
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +67 -31
- package/examples/plugins/echo/register.ts +4 -7
- 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/skill-host.ts +10 -3
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +5585 -469
- package/package.json +7 -3
- package/scripts/generate-openapi.ts +20 -13
- 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 +336 -42
- 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 +6 -4
- package/src/__tests__/agent-loop-thinking.test.ts +17 -12
- package/src/__tests__/agent-loop.test.ts +207 -341
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +5 -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-risk-options.test.ts +1 -0
- package/src/__tests__/anthropic-provider.test.ts +201 -55
- package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
- package/src/__tests__/app-control-flow.test.ts +5 -0
- package/src/__tests__/approval-cascade.test.ts +5 -11
- package/src/__tests__/approval-routes-http.test.ts +13 -15
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-event.test.ts +15 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -27
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- 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 +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +10 -14
- 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 +51 -22
- package/src/__tests__/channel-approvals.test.ts +3 -1
- 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__/circuit-breaker-pipeline.test.ts +3 -3
- package/src/__tests__/clawhub-files.test.ts +1 -0
- package/src/__tests__/compaction-events.test.ts +6 -17
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction-timeout-recovery.test.ts +37 -48
- package/src/__tests__/compaction-trail-store.test.ts +186 -0
- 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 +19 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +4 -2
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -27
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +464 -90
- package/src/__tests__/conversation-agent-loop.test.ts +1069 -64
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -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-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 +1 -0
- 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 +87 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +30 -7
- package/src/__tests__/conversation-process-callsite.test.ts +28 -30
- package/src/__tests__/conversation-provider-retry-repair.test.ts +58 -44
- package/src/__tests__/conversation-queue.test.ts +603 -455
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -20
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +35 -10
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +98 -22
- package/src/__tests__/conversation-runtime-workspace.test.ts +19 -1
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +120 -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-stream-state.test.ts +484 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +52 -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 +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- 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 +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +53 -22
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +32 -7
- 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 +61 -3
- package/src/__tests__/cu-unified-flow.test.ts +26 -1
- 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 +11 -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 +33 -42
- 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 +68 -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-pipeline.test.ts +127 -5
- 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__/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-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-outbound-http.test.ts +3 -2
- 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 +10 -7
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +3 -1
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/history-repair-hook.test.ts +161 -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-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 +1 -0
- 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 +154 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +51 -74
- 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 +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +4 -18
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
- package/src/__tests__/injector-v3-suppression.test.ts +220 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-attachments.test.ts +7 -8
- package/src/__tests__/list-messages-hidden-metadata.test.ts +93 -11
- package/src/__tests__/list-messages-page-latest.test.ts +0 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +36 -6
- package/src/__tests__/llm-call-pipeline.test.ts +21 -15
- 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 +45 -0
- 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-pipeline.test.ts +1 -1
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- 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 +44 -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 +13 -2
- package/src/__tests__/openai-provider.test.ts +74 -79
- 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 +2 -4
- package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
- package/src/__tests__/persistence-pipeline.test.ts +154 -27
- package/src/__tests__/persistence-secret-redaction.test.ts +85 -13
- package/src/__tests__/pipeline-runner.test.ts +2 -3
- package/src/__tests__/plugin-bootstrap.test.ts +60 -36
- 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 +7 -14
- 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 +49 -64
- 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__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +30 -23
- 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 +353 -0
- package/src/__tests__/schedule-routes.test.ts +80 -10
- package/src/__tests__/schedule-store.test.ts +83 -1
- package/src/__tests__/schedule-tools.test.ts +125 -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 +83 -43
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/shell-observability.test.ts +249 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +19 -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 +13 -5
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- 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 +92 -0
- package/src/__tests__/terminal-tools.test.ts +3 -24
- 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-pipeline.test.ts +1 -1
- package/src/__tests__/token-estimate-pipeline.test.ts +2 -4
- package/src/__tests__/tool-error-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execute-pipeline.test.ts +1 -1
- 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 +14 -11
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +9 -12
- package/src/__tests__/tool-result-truncation.test.ts +3 -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__/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 +50 -35
- 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__/prepare-agent-env.test.ts +143 -31
- package/src/acp/prepare-agent-env.ts +52 -11
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/compaction-circuit.ts +140 -0
- package/src/agent/loop.ts +489 -85
- 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-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-result.ts +129 -0
- package/src/api/events/tool-use-start.ts +30 -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 +482 -3
- package/src/api/requests/dictation.ts +45 -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 +6 -9
- package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
- package/src/avatar/__tests__/avatar-store.test.ts +193 -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 +4 -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 +184 -40
- 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 +365 -55
- 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 +2 -2
- package/src/config/assistant-feature-flags.ts +25 -44
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -3
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
- 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/call-site-defaults.ts +3 -8
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +42 -26
- 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 +1 -211
- package/src/config/schemas/call-site-catalog.ts +8 -15
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +92 -4
- package/src/config/schemas/memory-lifecycle.ts +24 -0
- package/src/config/schemas/memory-v2.ts +0 -227
- package/src/config/schemas/memory-v3.ts +39 -0
- package/src/config/schemas/memory.ts +6 -1
- package/src/config/schemas/services.ts +6 -2
- package/src/config/schemas/timeouts.ts +3 -1
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/compactor.ts +54 -31
- package/src/context/token-estimator.ts +29 -5
- package/src/context/tool-result-truncation.ts +1 -43
- package/src/context/window-manager.ts +138 -20
- package/src/credential-execution/executable-discovery.ts +40 -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 +3 -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__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- 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/config-watcher.ts +7 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +613 -155
- package/src/daemon/conversation-agent-loop.ts +409 -605
- package/src/daemon/conversation-error.ts +40 -12
- package/src/daemon/conversation-history.ts +22 -6
- package/src/daemon/conversation-launch.ts +4 -8
- package/src/daemon/conversation-lifecycle.ts +10 -38
- package/src/daemon/conversation-messaging.ts +83 -44
- package/src/daemon/conversation-notifiers.ts +7 -5
- package/src/daemon/conversation-process.ts +174 -116
- package/src/daemon/conversation-runtime-assembly.ts +76 -30
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-store.ts +6 -5
- package/src/daemon/conversation-surfaces.ts +124 -103
- package/src/daemon/conversation-tool-setup.ts +36 -48
- package/src/daemon/conversation.ts +111 -166
- 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 +46 -24
- package/src/daemon/first-greeting.ts +53 -13
- package/src/daemon/guardian-action-generators.ts +2 -2
- package/src/daemon/handlers/conversations.ts +6 -22
- package/src/daemon/handlers/shared.ts +10 -1
- package/src/daemon/handlers/skills.ts +15 -14
- 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 +40 -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/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 +47 -377
- 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 +2 -0
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/sync.ts +12 -25
- package/src/daemon/message-types/workspace.ts +3 -11
- package/src/daemon/process-message.ts +58 -55
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +28 -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/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +21 -1
- 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 +31 -0
- package/src/heartbeat/heartbeat-run-store.ts +31 -0
- package/src/heartbeat/heartbeat-service.ts +79 -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/feature-gate.ts +22 -0
- package/src/home/feed-types.ts +36 -221
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/__tests__/email-ipc.test.ts +0 -9
- package/src/ipc/gateway-client.test.ts +4 -1
- 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 +19 -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 +27 -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/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 +26 -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/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/db-connection.ts +29 -19
- package/src/memory/db-init.ts +12 -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-v2-routing.test.ts +2 -4
- package/src/memory/graph/consolidation.ts +8 -11
- package/src/memory/graph/conversation-graph-memory.ts +41 -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 +32 -32
- 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 +3 -1
- package/src/memory/jobs-worker.ts +63 -40
- 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 +10 -0
- 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/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/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +11 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +124 -0
- 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 +89 -9
- 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/memory/v3/__tests__/assign.test.ts +242 -0
- package/src/memory/v3/__tests__/capabilities.test.ts +118 -0
- package/src/memory/v3/__tests__/core.test.ts +39 -0
- package/src/memory/v3/__tests__/fixtures/eval-turns.json +36 -0
- package/src/memory/v3/__tests__/fixtures/live-turns.json +37 -0
- package/src/memory/v3/__tests__/health.test.ts +203 -0
- package/src/memory/v3/__tests__/live-integration.test.ts +330 -0
- package/src/memory/v3/__tests__/maintain-job.test.ts +288 -0
- package/src/memory/v3/__tests__/needle.test.ts +107 -0
- package/src/memory/v3/__tests__/orchestrate.test.ts +400 -0
- package/src/memory/v3/__tests__/reconcile.test.ts +274 -0
- package/src/memory/v3/__tests__/render-injection.test.ts +61 -0
- package/src/memory/v3/__tests__/router.test.ts +260 -0
- package/src/memory/v3/__tests__/selection-log-store.test.ts +179 -0
- package/src/memory/v3/__tests__/selector.test.ts +404 -0
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +414 -0
- package/src/memory/v3/__tests__/snapshot.test.ts +168 -0
- package/src/memory/v3/__tests__/tree.test.ts +192 -0
- package/src/memory/v3/__tests__/types.test.ts +54 -0
- package/src/memory/v3/__tests__/working-set-eviction.test.ts +106 -0
- package/src/memory/v3/__tests__/working-set-skeleton.test.ts +44 -0
- package/src/memory/v3/assign.ts +268 -0
- package/src/memory/v3/capabilities.ts +124 -0
- package/src/memory/v3/core.ts +26 -0
- package/src/memory/v3/data/README.md +84 -0
- package/src/memory/v3/data/assignments.json +5 -0
- package/src/memory/v3/data/core.json +1 -0
- package/src/memory/v3/data/leaves/domain-a/topic-x.md +9 -0
- package/src/memory/v3/data/leaves/domain-a/topic-y.md +9 -0
- package/src/memory/v3/data/leaves/domain-b/topic-z.md +9 -0
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +314 -0
- package/src/memory/v3/needle.ts +115 -0
- package/src/memory/v3/orchestrate.ts +114 -0
- package/src/memory/v3/page-content.ts +34 -0
- package/src/memory/v3/provider-blocks.ts +16 -0
- package/src/memory/v3/reconcile.ts +523 -0
- package/src/memory/v3/render-injection.ts +32 -0
- package/src/memory/v3/router.ts +184 -0
- package/src/memory/v3/selection-log-store.ts +84 -0
- package/src/memory/v3/selector.ts +211 -0
- package/src/memory/v3/shadow-plugin.ts +379 -0
- package/src/memory/v3/snapshot.ts +209 -0
- package/src/memory/v3/tree.ts +174 -0
- package/src/memory/v3/types.ts +46 -60
- package/src/memory/v3/working-set.ts +88 -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 +30 -8
- package/src/notifications/decision-engine.ts +10 -13
- 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/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 +42 -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/index.ts +2 -0
- package/src/plugin-api/types.ts +25 -3
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/circuit-breaker/package.json +15 -0
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +15 -0
- package/src/plugins/defaults/compaction/register.ts +35 -0
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +22 -0
- package/src/plugins/defaults/empty-response/package.json +15 -0
- package/src/plugins/defaults/empty-response/register.ts +28 -0
- package/src/plugins/defaults/empty-response/terminal.ts +106 -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 +29 -40
- package/src/plugins/defaults/injectors/package.json +15 -0
- package/src/plugins/defaults/{injectors.ts → injectors/register.ts} +16 -46
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +17 -0
- package/src/plugins/defaults/llm-call/package.json +15 -0
- package/src/plugins/defaults/{llm-call.ts → llm-call/register.ts} +6 -38
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +17 -0
- package/src/plugins/defaults/memory-retrieval/package.json +15 -0
- package/src/plugins/defaults/{memory-retrieval.ts → memory-retrieval/register.ts} +10 -48
- package/src/plugins/defaults/{overflow-reduce.ts → overflow-reduce/middlewares/overflowReduce.ts} +18 -77
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +19 -0
- package/src/plugins/defaults/persistence/package.json +15 -0
- package/src/plugins/defaults/persistence/register.ts +38 -0
- package/src/plugins/defaults/persistence/terminal.ts +83 -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/title-generate/terminal.ts +31 -0
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +23 -0
- package/src/plugins/defaults/token-estimate/package.json +15 -0
- package/src/plugins/defaults/token-estimate/register.ts +34 -0
- package/src/plugins/defaults/token-estimate/terminal.ts +40 -0
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +21 -0
- package/src/plugins/defaults/tool-error/package.json +15 -0
- package/src/plugins/defaults/tool-error/register.ts +35 -0
- package/src/plugins/defaults/tool-error/terminal.ts +47 -0
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +23 -0
- package/src/plugins/defaults/tool-execute/package.json +15 -0
- package/src/plugins/defaults/{tool-execute.ts → tool-execute/register.ts} +8 -46
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +23 -0
- package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +35 -0
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +113 -0
- package/src/plugins/defaults/tool-result-truncate/types.ts +22 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/pipeline.ts +0 -12
- package/src/plugins/types.ts +107 -102
- package/src/plugins/user-loader.ts +4 -3
- package/src/proactive-artifact/aux-message-injector.ts +0 -1
- package/src/proactive-artifact/job.test.ts +21 -8
- package/src/proactive-artifact/job.ts +3 -1
- package/src/prompts/__tests__/system-prompt.test.ts +4 -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-CONTENT-AUTOMATION.md +2 -2
- package/src/prompts/templates/BOOTSTRAP.md +10 -10
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +6 -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 +24 -5
- 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 +157 -7
- package/src/providers/openai/chat-completions-provider.ts +111 -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 +14 -14
- 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 +132 -26
- package/src/runtime/__tests__/background-job-runner.test.ts +2 -3
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/agent-wake.ts +93 -18
- package/src/runtime/assistant-event-hub.ts +2 -2
- 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 +3 -14
- 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/conversation-stream-state.ts +294 -0
- package/src/runtime/http-router.ts +19 -22
- package/src/runtime/http-types.ts +12 -6
- package/src/runtime/invite-instruction-generator.ts +3 -3
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/pending-interactions.ts +2 -2
- 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__/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 +98 -0
- 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-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-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/__tests__/tts-routes.test.ts +3 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/acp-routes.test.ts +97 -75
- package/src/runtime/routes/acp-routes.ts +29 -6
- package/src/runtime/routes/app-management-routes.ts +208 -28
- package/src/runtime/routes/app-routes.ts +25 -5
- package/src/runtime/routes/approval-routes.ts +16 -4
- package/src/runtime/routes/attachment-routes.ts +25 -1
- 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 +238 -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 +5 -0
- package/src/runtime/routes/browser-tabs-routes.ts +5 -0
- package/src/runtime/routes/btw-routes.ts +9 -5
- 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 +13 -5
- 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 +148 -51
- package/src/runtime/routes/conversation-routes.ts +259 -158
- package/src/runtime/routes/conversation-starter-routes.ts +22 -13
- package/src/runtime/routes/conversations-import-routes.ts +25 -7
- 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 +31 -11
- package/src/runtime/routes/domain-routes.ts +61 -28
- package/src/runtime/routes/email-routes.ts +33 -0
- package/src/runtime/routes/events-routes.ts +114 -9
- package/src/runtime/routes/filing-routes.ts +9 -4
- package/src/runtime/routes/gateway-log-routes.ts +5 -0
- 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 +25 -9
- 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 +5 -0
- 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 +5 -0
- 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 -16
- package/src/runtime/routes/identity-routes.ts +42 -11
- package/src/runtime/routes/image-generation-routes.ts +5 -0
- package/src/runtime/routes/inbound-message-handler.ts +15 -11
- 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 +2 -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 +30 -7
- package/src/runtime/routes/integrations/slack/channel.ts +19 -3
- package/src/runtime/routes/integrations/slack/share.ts +9 -2
- package/src/runtime/routes/integrations/telegram.ts +28 -9
- package/src/runtime/routes/integrations/twilio.ts +35 -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-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 +28 -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 +90 -36
- package/src/runtime/routes/memory-v3-routes.ts +283 -259
- 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 +33 -11
- 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 +35 -10
- package/src/runtime/routes/platform-routes.ts +21 -0
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +3 -2
- 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 +1 -1
- package/src/runtime/routes/playground/helpers.ts +0 -1
- 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 +5 -0
- package/src/runtime/routes/sanity-routes.ts +9 -2
- package/src/runtime/routes/schedule-routes.ts +137 -47
- package/src/runtime/routes/secret-routes.ts +17 -4
- 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 +133 -69
- 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 +65 -0
- package/src/runtime/routes/task-routes.ts +37 -0
- package/src/runtime/routes/telemetry-routes.ts +9 -0
- package/src/runtime/routes/trace-event-routes.ts +42 -1
- package/src/runtime/routes/trust-rules-routes.ts +5 -0
- package/src/runtime/routes/tts-routes.ts +13 -6
- package/src/runtime/routes/types.ts +17 -8
- 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 +71 -3
- 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 +9 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +8 -0
- package/src/runtime/routes/work-items-routes.ts +47 -19
- 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 +120 -9
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +4 -4
- package/src/runtime/services/analyze-conversation.ts +3 -6
- 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 +16 -1
- package/src/schedule/scheduler.ts +114 -16
- 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/user-message.ts +10 -16
- package/src/skills/catalog-files.ts +4 -1
- package/src/skills/clawhub-files.ts +2 -0
- package/src/skills/skillssh-files.ts +2 -0
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +16 -19
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/telemetry/types.ts +26 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +138 -1
- package/src/telemetry/usage-telemetry-reporter.ts +31 -0
- package/src/tools/acp/spawn.test.ts +88 -38
- package/src/tools/apps/definitions.ts +42 -24
- 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 -55
- 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 +34 -31
- 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.test.ts +211 -3
- 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.ts +215 -57
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +184 -118
- package/src/tools/schedule/create.ts +12 -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 +3 -0
- package/src/tools/system/avatar-generator.ts +13 -22
- package/src/tools/system/request-permission.ts +30 -27
- 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 +166 -94
- 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/platform.ts +15 -12
- package/src/work-items/work-item-runner.ts +7 -2
- 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/__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 +10 -0
- package/src/workspace/provider-commit-message-generator.ts +15 -17
- package/tsconfig.json +4 -1
- package/src/__tests__/history-repair-pipeline.test.ts +0 -396
- 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/message-types/disk-pressure.ts +0 -9
- package/src/email/feature-gate.ts +0 -23
- 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/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/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-result-truncate.ts +0 -84
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type pino from "pino";
|
|
10
|
+
import { v4 as uuid } from "uuid";
|
|
10
11
|
|
|
11
12
|
import type { AgentEvent } from "../agent/loop.js";
|
|
12
13
|
import type {
|
|
@@ -16,12 +17,16 @@ import type {
|
|
|
16
17
|
import { getConfig } from "../config/loader.js";
|
|
17
18
|
import { recordEstimate } from "../context/estimator-calibration.js";
|
|
18
19
|
import { getCalibrationProviderKey } from "../context/token-estimator.js";
|
|
20
|
+
import { projectAssistantMessage } from "../memory/conversation-attention-store.js";
|
|
19
21
|
import {
|
|
22
|
+
deleteMessageById,
|
|
20
23
|
getConversation,
|
|
21
24
|
getMessageById,
|
|
25
|
+
messageMetadataSchema,
|
|
22
26
|
provenanceFromTrustContext,
|
|
23
27
|
updateMessageContent,
|
|
24
28
|
} from "../memory/conversation-crud.js";
|
|
29
|
+
import { indexMessageNow } from "../memory/indexer.js";
|
|
25
30
|
import {
|
|
26
31
|
backfillMessageIdOnLogs,
|
|
27
32
|
buildProviderErrorResponsePayload,
|
|
@@ -36,19 +41,24 @@ import {
|
|
|
36
41
|
type SlackMessageMetadata,
|
|
37
42
|
writeSlackMetadata,
|
|
38
43
|
} from "../messaging/providers/slack/message-metadata.js";
|
|
39
|
-
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
44
|
+
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence/terminal.js";
|
|
40
45
|
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
41
46
|
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
42
47
|
import type {
|
|
43
|
-
PersistAddResult,
|
|
44
48
|
PersistArgs,
|
|
49
|
+
PersistReserveResult,
|
|
45
50
|
PersistResult,
|
|
46
51
|
TurnContext,
|
|
47
52
|
} from "../plugins/types.js";
|
|
48
53
|
import type { ContentBlock, ImageContent } from "../providers/types.js";
|
|
49
54
|
import { isContextOverflowError } from "../providers/types.js";
|
|
55
|
+
import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
|
|
50
56
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
51
57
|
import { extractDomain } from "../tools/network/domain-normalize.js";
|
|
58
|
+
import {
|
|
59
|
+
buildPricingUsage,
|
|
60
|
+
resolveStructuredPricing,
|
|
61
|
+
} from "../usage/pricing.js";
|
|
52
62
|
import { ProviderError } from "../util/errors.js";
|
|
53
63
|
import { faviconUrlForDomain } from "../util/favicon.js";
|
|
54
64
|
import { getLogger } from "../util/logger.js";
|
|
@@ -57,22 +67,38 @@ import {
|
|
|
57
67
|
cleanAssistantContent,
|
|
58
68
|
drainDirectiveDisplayBuffer,
|
|
59
69
|
} from "./assistant-attachments.js";
|
|
60
|
-
import type {
|
|
70
|
+
import type {
|
|
71
|
+
AgentLoopConversationContext,
|
|
72
|
+
AssistantSurface,
|
|
73
|
+
} from "./conversation-agent-loop.js";
|
|
61
74
|
import {
|
|
62
75
|
buildConversationErrorMessage,
|
|
63
76
|
classifyConversationError,
|
|
64
77
|
isContextTooLarge,
|
|
78
|
+
maxTokensReachedClassification,
|
|
65
79
|
} from "./conversation-error.js";
|
|
66
80
|
import { isProviderOrderingError } from "./conversation-slash.js";
|
|
67
81
|
import { resolveTurnTimezoneContext } from "./date-context.js";
|
|
68
|
-
import type {
|
|
82
|
+
import type {
|
|
83
|
+
CardSurfaceData,
|
|
84
|
+
ServerMessage,
|
|
85
|
+
SurfaceAction,
|
|
86
|
+
UiSurfaceShow,
|
|
87
|
+
} from "./message-protocol.js";
|
|
88
|
+
import { conversationMetadataSyncTag } from "./message-types/sync.js";
|
|
69
89
|
import type {
|
|
70
90
|
WebSearchMetadata,
|
|
71
91
|
WebSearchResultItem,
|
|
72
92
|
} from "./message-types/web-activity.js";
|
|
93
|
+
import { FALLBACK_TURN_TRUST } from "./trust-context.js";
|
|
73
94
|
|
|
74
95
|
const log = getLogger("agent-loop-handlers");
|
|
75
96
|
|
|
97
|
+
// ── Partial-persistence tunables ─────────────────────────────────────
|
|
98
|
+
// Debounce for mid-turn `updateContent` writes from text deltas.
|
|
99
|
+
// Indexer + projector still fire ONLY at `handleMessageComplete`.
|
|
100
|
+
const PARTIAL_PERSIST_DEBOUNCE_MS = 1000;
|
|
101
|
+
|
|
76
102
|
/**
|
|
77
103
|
* Build a {@link TurnContext} from the handler's deps for pipeline logging
|
|
78
104
|
* and plugin attribution.
|
|
@@ -93,11 +119,10 @@ function buildHandlerTurnContext(deps: EventHandlerDeps): TurnContext {
|
|
|
93
119
|
requestId: deps.reqId,
|
|
94
120
|
conversationId: deps.ctx.conversationId,
|
|
95
121
|
turnIndex: deps.ctx.turnCount,
|
|
96
|
-
trust:
|
|
97
|
-
deps.ctx.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
},
|
|
122
|
+
trust:
|
|
123
|
+
deps.ctx.currentTurnTrustContext ??
|
|
124
|
+
deps.ctx.trustContext ??
|
|
125
|
+
FALLBACK_TURN_TRUST,
|
|
101
126
|
};
|
|
102
127
|
}
|
|
103
128
|
|
|
@@ -145,6 +170,21 @@ export interface EventHandlerState {
|
|
|
145
170
|
contextTooLargeError: unknown;
|
|
146
171
|
providerErrorUserMessage: string | null;
|
|
147
172
|
lastAssistantMessageId: string | undefined;
|
|
173
|
+
/**
|
|
174
|
+
* True when `handleLlmCallStarted` has reserved an empty assistant row
|
|
175
|
+
* that has NOT yet been finalized via `handleMessageComplete`
|
|
176
|
+
* (`op:"updateContent"` + indexing + projection). Used by error/retry
|
|
177
|
+
* paths to detect a stranded reservation that must be cleaned up
|
|
178
|
+
* before the next LLM call reserves a fresh row — without it, every
|
|
179
|
+
* retryable failure (overflow, ordering, image overflow) and every
|
|
180
|
+
* terminal provider rejection would leak an empty assistant bubble
|
|
181
|
+
* into the transcript and mispoint downstream sync/projection.
|
|
182
|
+
*
|
|
183
|
+
* Cleared by `handleMessageComplete` on successful finalize, and by
|
|
184
|
+
* the synthetic-error branch in `conversation-agent-loop.ts` after it
|
|
185
|
+
* absorbs the reserved row into the error message.
|
|
186
|
+
*/
|
|
187
|
+
assistantRowAwaitingFinalization: boolean;
|
|
148
188
|
readonly pendingToolResults: Map<string, PendingToolResult>;
|
|
149
189
|
readonly persistedToolUseIds: Set<string>;
|
|
150
190
|
readonly accumulatedDirectives: DirectiveRequest[];
|
|
@@ -153,7 +193,6 @@ export interface EventHandlerState {
|
|
|
153
193
|
readonly toolContentBlockToolNames: Map<number, string>;
|
|
154
194
|
readonly directiveWarnings: string[];
|
|
155
195
|
readonly toolUseIdToName: Map<string, string>;
|
|
156
|
-
currentTurnToolNames: string[];
|
|
157
196
|
/** Sticky for the whole run: this turn created/refreshed an app. */
|
|
158
197
|
appBuildToolUsedThisRun: boolean;
|
|
159
198
|
/** Tracks whether the first text delta has been emitted this turn for activity state transitions. */
|
|
@@ -207,6 +246,12 @@ export interface EventHandlerState {
|
|
|
207
246
|
readonly serverToolStartedAt: Map<string, number>;
|
|
208
247
|
/** Original input from server_tool_start, keyed by tool_use_id, so the complete handler can read the query. */
|
|
209
248
|
readonly serverToolInputs: Map<string, Record<string, unknown>>;
|
|
249
|
+
/** Active debounce timer for partial persistence; `undefined` when idle. */
|
|
250
|
+
pendingPartialFlushTimer: ReturnType<typeof setTimeout> | undefined;
|
|
251
|
+
/** In-flight partial flush write awaited at finalize to avoid overwrite races. */
|
|
252
|
+
pendingPartialFlushPromise: Promise<void> | undefined;
|
|
253
|
+
/** Running mirror of the in-flight assistant message's content. */
|
|
254
|
+
currentMessageContent: ContentBlock[];
|
|
210
255
|
}
|
|
211
256
|
|
|
212
257
|
/** Immutable context shared across event handlers within a single agent loop run. */
|
|
@@ -245,6 +290,7 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
245
290
|
contextTooLargeError: null,
|
|
246
291
|
providerErrorUserMessage: null,
|
|
247
292
|
lastAssistantMessageId: undefined,
|
|
293
|
+
assistantRowAwaitingFinalization: false,
|
|
248
294
|
pendingToolResults: new Map(),
|
|
249
295
|
persistedToolUseIds: new Set(),
|
|
250
296
|
accumulatedDirectives: [],
|
|
@@ -252,7 +298,6 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
252
298
|
toolContentBlockToolNames: new Map(),
|
|
253
299
|
directiveWarnings: [],
|
|
254
300
|
toolUseIdToName: new Map(),
|
|
255
|
-
currentTurnToolNames: [],
|
|
256
301
|
appBuildToolUsedThisRun: false,
|
|
257
302
|
firstTextDeltaEmitted: false,
|
|
258
303
|
firstThinkingDeltaEmitted: false,
|
|
@@ -266,9 +311,119 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
266
311
|
turnStartedAt: Date.now(),
|
|
267
312
|
serverToolStartedAt: new Map(),
|
|
268
313
|
serverToolInputs: new Map(),
|
|
314
|
+
pendingPartialFlushTimer: undefined,
|
|
315
|
+
pendingPartialFlushPromise: undefined,
|
|
316
|
+
currentMessageContent: [],
|
|
269
317
|
};
|
|
270
318
|
}
|
|
271
319
|
|
|
320
|
+
// ── Partial-persistence helpers ──────────────────────────────────────
|
|
321
|
+
|
|
322
|
+
/** Canonical persisted-content build: clean → append surfaces → redact. */
|
|
323
|
+
function buildPersistedAssistantContent(
|
|
324
|
+
rawBlocks: readonly ContentBlock[],
|
|
325
|
+
surfaces: readonly AssistantSurface[],
|
|
326
|
+
): ContentBlock[] {
|
|
327
|
+
const { cleanedContent } = cleanAssistantContent(rawBlocks);
|
|
328
|
+
const cleaned = cleanedContent as ContentBlock[];
|
|
329
|
+
const withSurfaces: ContentBlock[] = [...cleaned];
|
|
330
|
+
for (const surface of surfaces) {
|
|
331
|
+
withSurfaces.push({
|
|
332
|
+
type: "ui_surface",
|
|
333
|
+
surfaceId: surface.surfaceId,
|
|
334
|
+
surfaceType: surface.surfaceType,
|
|
335
|
+
title: surface.title,
|
|
336
|
+
data: surface.data,
|
|
337
|
+
actions: surface.actions,
|
|
338
|
+
display: surface.display,
|
|
339
|
+
...(surface.persistent ? { persistent: true } : {}),
|
|
340
|
+
...(surface.toolCallId ? { toolCallId: surface.toolCallId } : {}),
|
|
341
|
+
} as unknown as ContentBlock);
|
|
342
|
+
}
|
|
343
|
+
return withSurfaces.map((block) => {
|
|
344
|
+
if (block.type === "text") {
|
|
345
|
+
const tb = block as Extract<ContentBlock, { type: "text" }>;
|
|
346
|
+
return { ...tb, text: redactSecrets(tb.text) };
|
|
347
|
+
}
|
|
348
|
+
return block;
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Append a streamed text chunk to `state.currentMessageContent`, fusing into tail text block. */
|
|
353
|
+
function appendTextToCurrentMessage(
|
|
354
|
+
state: EventHandlerState,
|
|
355
|
+
text: string,
|
|
356
|
+
): void {
|
|
357
|
+
if (text.length === 0) return;
|
|
358
|
+
const tail = state.currentMessageContent.at(-1);
|
|
359
|
+
if (tail && tail.type === "text") {
|
|
360
|
+
tail.text = tail.text + text;
|
|
361
|
+
} else {
|
|
362
|
+
state.currentMessageContent.push({ type: "text", text });
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Reset partial-persist accumulator and any pending flush state. Idempotent. */
|
|
367
|
+
function resetPartialPersistAccumulator(state: EventHandlerState): void {
|
|
368
|
+
if (state.pendingPartialFlushTimer !== undefined) {
|
|
369
|
+
clearTimeout(state.pendingPartialFlushTimer);
|
|
370
|
+
state.pendingPartialFlushTimer = undefined;
|
|
371
|
+
}
|
|
372
|
+
state.currentMessageContent = [];
|
|
373
|
+
state.pendingPartialFlushPromise = undefined;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Flush `state.currentMessageContent` to the row via the persistence pipeline. */
|
|
377
|
+
async function flushAccumulatedContent(
|
|
378
|
+
state: EventHandlerState,
|
|
379
|
+
deps: EventHandlerDeps,
|
|
380
|
+
): Promise<void> {
|
|
381
|
+
const messageId = state.lastAssistantMessageId;
|
|
382
|
+
if (messageId === undefined) return;
|
|
383
|
+
if (state.currentMessageContent.length === 0) return;
|
|
384
|
+
|
|
385
|
+
const built = buildPersistedAssistantContent(state.currentMessageContent, []);
|
|
386
|
+
const contentJson = JSON.stringify(built);
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
390
|
+
"persistence",
|
|
391
|
+
getMiddlewaresFor("persistence"),
|
|
392
|
+
defaultPersistenceTerminal,
|
|
393
|
+
{
|
|
394
|
+
op: "updateContent",
|
|
395
|
+
messageId,
|
|
396
|
+
content: contentJson,
|
|
397
|
+
},
|
|
398
|
+
buildHandlerTurnContext(deps),
|
|
399
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
400
|
+
);
|
|
401
|
+
} catch (err) {
|
|
402
|
+
deps.rlog.warn(
|
|
403
|
+
{ err, messageId },
|
|
404
|
+
"partial flush of accumulated assistant content failed; finalize at message_complete will recover",
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** Schedule a debounced partial flush. First-scheduled wins; no-op when timer pending. */
|
|
410
|
+
function schedulePartialFlush(
|
|
411
|
+
state: EventHandlerState,
|
|
412
|
+
deps: EventHandlerDeps,
|
|
413
|
+
): void {
|
|
414
|
+
if (state.pendingPartialFlushTimer !== undefined) return;
|
|
415
|
+
state.pendingPartialFlushTimer = setTimeout(() => {
|
|
416
|
+
state.pendingPartialFlushTimer = undefined;
|
|
417
|
+
const flushPromise = flushAccumulatedContent(state, deps);
|
|
418
|
+
state.pendingPartialFlushPromise = flushPromise;
|
|
419
|
+
void flushPromise.finally(() => {
|
|
420
|
+
if (state.pendingPartialFlushPromise === flushPromise) {
|
|
421
|
+
state.pendingPartialFlushPromise = undefined;
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}, PARTIAL_PERSIST_DEBOUNCE_MS);
|
|
425
|
+
}
|
|
426
|
+
|
|
272
427
|
// ── Shared Helper ────────────────────────────────────────────────────
|
|
273
428
|
|
|
274
429
|
// providerNameOverride should be supplied when the caller already knows the
|
|
@@ -307,6 +462,9 @@ function emitLlmCallStartedIfNeeded(
|
|
|
307
462
|
// tools the client discards it (extractCodePreview only handles app tools),
|
|
308
463
|
// so we skip forwarding entirely to avoid transport/decode overhead.
|
|
309
464
|
const APP_TOOL_NAMES = new Set(["app_create"]);
|
|
465
|
+
const MAX_TOKENS_CONTINUE_PROMPT =
|
|
466
|
+
"Continue from where you stopped. Do not repeat content you've already sent.";
|
|
467
|
+
const MAX_TOKENS_SURFACE_COMPLETION_SUMMARY = "Continue";
|
|
310
468
|
|
|
311
469
|
// ── Friendly Tool Names ──────────────────────────────────────────────
|
|
312
470
|
|
|
@@ -389,6 +547,139 @@ function resolveAssistantReplyTimestampTimezone(
|
|
|
389
547
|
}).effectiveTimezone;
|
|
390
548
|
}
|
|
391
549
|
|
|
550
|
+
/**
|
|
551
|
+
* Assemble the metadata envelope written to the assistant message row.
|
|
552
|
+
*
|
|
553
|
+
* Stamped at reserve time (before `provider.sendMessage`) so the row carries
|
|
554
|
+
* channel provenance from the moment it lands in SQLite, mirroring the
|
|
555
|
+
* snapshot that handleMessageComplete used to compute at end-of-turn. All
|
|
556
|
+
* inputs (channel context, trust context, turnStartedAt) are stable across
|
|
557
|
+
* the LLM call, so building this once at reserve is equivalent to building
|
|
558
|
+
* it at complete. Slack reply rows further stamp a `slackMeta` sub-object —
|
|
559
|
+
* the `channelTs` field stays absent here and is back-filled by
|
|
560
|
+
* `deliverReplyViaCallback` after the gateway returns the ts.
|
|
561
|
+
*/
|
|
562
|
+
function buildAssistantChannelMetadata(
|
|
563
|
+
state: EventHandlerState,
|
|
564
|
+
deps: EventHandlerDeps,
|
|
565
|
+
): Record<string, unknown> {
|
|
566
|
+
const metadata: Record<string, unknown> = {
|
|
567
|
+
...provenanceFromTrustContext(deps.ctx.trustContext),
|
|
568
|
+
userMessageChannel: deps.turnChannelContext.userMessageChannel,
|
|
569
|
+
assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
|
|
570
|
+
userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
|
|
571
|
+
assistantMessageInterface:
|
|
572
|
+
deps.turnInterfaceContext.assistantMessageInterface,
|
|
573
|
+
sentAt: state.turnStartedAt,
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
if (deps.turnChannelContext.assistantMessageChannel === "slack") {
|
|
577
|
+
const channelId = deps.ctx.trustContext?.requesterChatId;
|
|
578
|
+
if (channelId) {
|
|
579
|
+
const threadTs = getThreadTs(deps.ctx.conversationId);
|
|
580
|
+
const timestampTimezone = resolveAssistantReplyTimestampTimezone(
|
|
581
|
+
deps.ctx,
|
|
582
|
+
);
|
|
583
|
+
const timestampTimezoneLabel = formatSlackTimezoneLabel(
|
|
584
|
+
timestampTimezone,
|
|
585
|
+
{ nowMs: state.turnStartedAt },
|
|
586
|
+
);
|
|
587
|
+
const partialSlackMeta: Partial<SlackMessageMetadata> = {
|
|
588
|
+
source: "slack",
|
|
589
|
+
eventKind: "message",
|
|
590
|
+
channelId,
|
|
591
|
+
...(threadTs ? { threadTs } : {}),
|
|
592
|
+
timestampTimezone,
|
|
593
|
+
...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
|
|
594
|
+
};
|
|
595
|
+
// `channelTs` is filled in by the post-send reconciliation step in
|
|
596
|
+
// `deliverReplyViaCallback`; cast through the Partial to satisfy
|
|
597
|
+
// the writer's type at this pre-send boundary.
|
|
598
|
+
metadata.slackMeta = writeSlackMetadata(
|
|
599
|
+
partialSlackMeta as SlackMessageMetadata,
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return metadata;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Reserve an empty assistant row for the LLM call about to begin, stash
|
|
609
|
+
* its id on `state.lastAssistantMessageId`, and announce the boundary on
|
|
610
|
+
* the wire via `assistant_turn_start`.
|
|
611
|
+
*
|
|
612
|
+
* Awaited so the row exists and the client has the anchor id BEFORE any
|
|
613
|
+
* streaming delta arrives — every subsequent `deps.onEvent` in this LLM
|
|
614
|
+
* call stamps `messageId: state.lastAssistantMessageId`, and
|
|
615
|
+
* `handleMessageComplete` flushes the final content to the same row via
|
|
616
|
+
* `op: "updateContent"` instead of inserting a fresh one.
|
|
617
|
+
*
|
|
618
|
+
* Multi-LLM-call agent turns (LLM call → tool execution → LLM call) emit
|
|
619
|
+
* one `llm_call_started` per call, so each LLM call reserves its own row.
|
|
620
|
+
* The read-path `findDisplayTurnEndIndex` collapses consecutive assistant
|
|
621
|
+
* rows for the merged history view, matching today's per-call DB layout.
|
|
622
|
+
*/
|
|
623
|
+
export async function handleLlmCallStarted(
|
|
624
|
+
state: EventHandlerState,
|
|
625
|
+
deps: EventHandlerDeps,
|
|
626
|
+
): Promise<void> {
|
|
627
|
+
// Clean up an orphaned reservation from a previous LLM call in this run
|
|
628
|
+
// that errored before `message_complete` could finalize it. This covers
|
|
629
|
+
// the retryable paths (overflow, ordering, image overflow) where the
|
|
630
|
+
// agent loop re-enters with a fresh `run()` and reserves another row;
|
|
631
|
+
// without this delete the failed-attempt row stays in the transcript as
|
|
632
|
+
// an empty assistant bubble. The finalized-row case is filtered out via
|
|
633
|
+
// the `assistantRowAwaitingFinalization` flag — `handleMessageComplete`
|
|
634
|
+
// clears it after the successful `updateContent`, so the previous call's
|
|
635
|
+
// committed row is never touched here.
|
|
636
|
+
//
|
|
637
|
+
// Direct `deleteMessageById` (not via the `persistence` pipeline) is
|
|
638
|
+
// intentional: a never-finalized reservation has no segments, no
|
|
639
|
+
// attachments, and no observable history — undoing it isn't a real
|
|
640
|
+
// persistence event for plugins to react to, so routing through the
|
|
641
|
+
// pipeline would only widen the mock surface for no observability win.
|
|
642
|
+
if (state.assistantRowAwaitingFinalization && state.lastAssistantMessageId) {
|
|
643
|
+
try {
|
|
644
|
+
deleteMessageById(state.lastAssistantMessageId);
|
|
645
|
+
} catch (err) {
|
|
646
|
+
// Non-fatal: a leaked empty row is preferable to a turn-level throw.
|
|
647
|
+
deps.rlog.warn(
|
|
648
|
+
{ err, messageId: state.lastAssistantMessageId },
|
|
649
|
+
"Failed to clean up stranded reserved assistant row before new reservation",
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const metadata = buildAssistantChannelMetadata(state, deps);
|
|
655
|
+
const reserveResult = (await runPipeline<PersistArgs, PersistResult>(
|
|
656
|
+
"persistence",
|
|
657
|
+
getMiddlewaresFor("persistence"),
|
|
658
|
+
defaultPersistenceTerminal,
|
|
659
|
+
{
|
|
660
|
+
op: "reserve",
|
|
661
|
+
conversationId: deps.ctx.conversationId,
|
|
662
|
+
role: "assistant",
|
|
663
|
+
metadata,
|
|
664
|
+
},
|
|
665
|
+
buildHandlerTurnContext(deps),
|
|
666
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
667
|
+
)) as PersistReserveResult;
|
|
668
|
+
state.lastAssistantMessageId = reserveResult.message.id;
|
|
669
|
+
state.assistantRowAwaitingFinalization = true;
|
|
670
|
+
// Fresh row → fresh accumulator. If an earlier (failed) LLM call
|
|
671
|
+
// within the same run left partial state behind, the
|
|
672
|
+
// `assistantRowAwaitingFinalization` cleanup above already deleted
|
|
673
|
+
// the orphan row, so the accumulator content would point at a
|
|
674
|
+
// non-existent id. Reset here so the new row starts from zero.
|
|
675
|
+
resetPartialPersistAccumulator(state);
|
|
676
|
+
deps.onEvent({
|
|
677
|
+
type: "assistant_turn_start",
|
|
678
|
+
messageId: reserveResult.message.id,
|
|
679
|
+
conversationId: deps.ctx.conversationId,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
|
|
392
683
|
// ── Individual Handlers ──────────────────────────────────────────────
|
|
393
684
|
|
|
394
685
|
function handleTextDelta(
|
|
@@ -405,20 +696,22 @@ function handleTextDelta(
|
|
|
405
696
|
if (drained.emitText.length > 0) {
|
|
406
697
|
if (!state.firstTextDeltaEmitted) {
|
|
407
698
|
state.firstTextDeltaEmitted = true;
|
|
408
|
-
deps.ctx.emitActivityState(
|
|
409
|
-
|
|
410
|
-
"
|
|
411
|
-
|
|
412
|
-
deps.reqId,
|
|
413
|
-
"Thinking",
|
|
414
|
-
);
|
|
699
|
+
deps.ctx.emitActivityState("streaming", "first_text_delta", {
|
|
700
|
+
requestId: deps.reqId,
|
|
701
|
+
statusText: "Thinking",
|
|
702
|
+
});
|
|
415
703
|
}
|
|
416
704
|
deps.onEvent({
|
|
417
705
|
type: "assistant_text_delta",
|
|
418
706
|
text: drained.emitText,
|
|
419
707
|
conversationId: deps.ctx.conversationId,
|
|
708
|
+
messageId: state.lastAssistantMessageId,
|
|
420
709
|
});
|
|
421
710
|
if (deps.shouldGenerateTitle) state.firstAssistantText += drained.emitText;
|
|
711
|
+
// Mirror the drained delta into state.currentMessageContent so partial
|
|
712
|
+
// flushes mid-turn see the same content the user is watching live.
|
|
713
|
+
appendTextToCurrentMessage(state, drained.emitText);
|
|
714
|
+
schedulePartialFlush(state, deps);
|
|
422
715
|
}
|
|
423
716
|
}
|
|
424
717
|
|
|
@@ -439,13 +732,10 @@ function handleThinkingDelta(
|
|
|
439
732
|
// assistantStatusText for every assistant_activity_state event.
|
|
440
733
|
if (lastToolName) {
|
|
441
734
|
const statusText = `Processing ${friendlyToolName(lastToolName)} results`;
|
|
442
|
-
deps.ctx.emitActivityState(
|
|
443
|
-
|
|
444
|
-
"thinking_delta",
|
|
445
|
-
"assistant_turn",
|
|
446
|
-
deps.reqId,
|
|
735
|
+
deps.ctx.emitActivityState("thinking", "thinking_delta", {
|
|
736
|
+
requestId: deps.reqId,
|
|
447
737
|
statusText,
|
|
448
|
-
);
|
|
738
|
+
});
|
|
449
739
|
}
|
|
450
740
|
}
|
|
451
741
|
if (!deps.ctx.streamThinking) return;
|
|
@@ -454,6 +744,7 @@ function handleThinkingDelta(
|
|
|
454
744
|
type: "assistant_thinking_delta",
|
|
455
745
|
thinking: event.thinking,
|
|
456
746
|
conversationId: deps.ctx.conversationId,
|
|
747
|
+
messageId: state.lastAssistantMessageId,
|
|
457
748
|
});
|
|
458
749
|
}
|
|
459
750
|
|
|
@@ -463,7 +754,6 @@ export function handleToolUse(
|
|
|
463
754
|
event: Extract<AgentEvent, { type: "tool_use" }>,
|
|
464
755
|
): void {
|
|
465
756
|
state.toolUseIdToName.set(event.id, event.name);
|
|
466
|
-
state.currentTurnToolNames.push(event.name);
|
|
467
757
|
if (event.name === "app_create" || event.name === "app_refresh") {
|
|
468
758
|
state.appBuildToolUsedThisRun = true;
|
|
469
759
|
}
|
|
@@ -471,24 +761,22 @@ export function handleToolUse(
|
|
|
471
761
|
state.currentToolUseId = event.id;
|
|
472
762
|
state.currentTurnToolUseIds.push(event.id);
|
|
473
763
|
const statusText = computeToolUseStatusText(event.name, event.input);
|
|
474
|
-
deps.ctx.emitActivityState(
|
|
475
|
-
|
|
476
|
-
"tool_use_start",
|
|
477
|
-
"assistant_turn",
|
|
478
|
-
deps.reqId,
|
|
764
|
+
deps.ctx.emitActivityState("tool_running", "tool_use_start", {
|
|
765
|
+
requestId: deps.reqId,
|
|
479
766
|
statusText,
|
|
480
|
-
);
|
|
767
|
+
});
|
|
481
768
|
deps.onEvent({
|
|
482
769
|
type: "tool_use_start",
|
|
483
770
|
toolName: event.name,
|
|
484
771
|
input: event.input,
|
|
485
772
|
conversationId: deps.ctx.conversationId,
|
|
486
773
|
toolUseId: event.id,
|
|
774
|
+
messageId: state.lastAssistantMessageId,
|
|
487
775
|
});
|
|
488
776
|
}
|
|
489
777
|
|
|
490
778
|
export function handleToolUsePreviewStart(
|
|
491
|
-
|
|
779
|
+
state: EventHandlerState,
|
|
492
780
|
deps: EventHandlerDeps,
|
|
493
781
|
event: Extract<AgentEvent, { type: "tool_use_preview_start" }>,
|
|
494
782
|
): void {
|
|
@@ -497,19 +785,17 @@ export function handleToolUsePreviewStart(
|
|
|
497
785
|
toolUseId: event.toolUseId,
|
|
498
786
|
toolName: event.toolName,
|
|
499
787
|
conversationId: deps.ctx.conversationId,
|
|
788
|
+
messageId: state.lastAssistantMessageId,
|
|
500
789
|
});
|
|
501
790
|
const statusText = `Preparing ${friendlyToolName(event.toolName)}...`;
|
|
502
|
-
deps.ctx.emitActivityState(
|
|
503
|
-
|
|
504
|
-
"preview_start",
|
|
505
|
-
"assistant_turn",
|
|
506
|
-
deps.reqId,
|
|
791
|
+
deps.ctx.emitActivityState("tool_running", "preview_start", {
|
|
792
|
+
requestId: deps.reqId,
|
|
507
793
|
statusText,
|
|
508
|
-
);
|
|
794
|
+
});
|
|
509
795
|
}
|
|
510
796
|
|
|
511
797
|
function handleToolOutputChunk(
|
|
512
|
-
|
|
798
|
+
state: EventHandlerState,
|
|
513
799
|
deps: EventHandlerDeps,
|
|
514
800
|
event: Extract<AgentEvent, { type: "tool_output_chunk" }>,
|
|
515
801
|
): void {
|
|
@@ -567,6 +853,7 @@ function handleToolOutputChunk(
|
|
|
567
853
|
chunk: event.chunk,
|
|
568
854
|
conversationId: deps.ctx.conversationId,
|
|
569
855
|
toolUseId: event.toolUseId,
|
|
856
|
+
messageId: state.lastAssistantMessageId,
|
|
570
857
|
subType: structured.subType,
|
|
571
858
|
subToolName: structured.subToolName,
|
|
572
859
|
subToolInput: structured.subToolInput,
|
|
@@ -579,12 +866,13 @@ function handleToolOutputChunk(
|
|
|
579
866
|
chunk: event.chunk,
|
|
580
867
|
conversationId: deps.ctx.conversationId,
|
|
581
868
|
toolUseId: event.toolUseId,
|
|
869
|
+
messageId: state.lastAssistantMessageId,
|
|
582
870
|
});
|
|
583
871
|
}
|
|
584
872
|
}
|
|
585
873
|
|
|
586
874
|
export function handleInputJsonDelta(
|
|
587
|
-
|
|
875
|
+
state: EventHandlerState,
|
|
588
876
|
deps: EventHandlerDeps,
|
|
589
877
|
event: Extract<AgentEvent, { type: "input_json_delta" }>,
|
|
590
878
|
): void {
|
|
@@ -598,6 +886,7 @@ export function handleInputJsonDelta(
|
|
|
598
886
|
content: event.accumulatedJson,
|
|
599
887
|
conversationId: deps.ctx.conversationId,
|
|
600
888
|
toolUseId: event.toolUseId,
|
|
889
|
+
messageId: state.lastAssistantMessageId,
|
|
601
890
|
});
|
|
602
891
|
}
|
|
603
892
|
|
|
@@ -690,13 +979,10 @@ export function handleToolResult(
|
|
|
690
979
|
const statusText = `Processing ${friendlyToolName(
|
|
691
980
|
state.lastCompletedToolName ?? "",
|
|
692
981
|
)} results`;
|
|
693
|
-
deps.ctx.emitActivityState(
|
|
694
|
-
|
|
695
|
-
"tool_result_received",
|
|
696
|
-
"assistant_turn",
|
|
697
|
-
deps.reqId,
|
|
982
|
+
deps.ctx.emitActivityState("thinking", "tool_result_received", {
|
|
983
|
+
requestId: deps.reqId,
|
|
698
984
|
statusText,
|
|
699
|
-
);
|
|
985
|
+
});
|
|
700
986
|
|
|
701
987
|
// Once all tools for this turn have completed, annotate the persisted
|
|
702
988
|
// assistant message with timing and confirmation metadata.
|
|
@@ -724,6 +1010,7 @@ export function handleToolResult(
|
|
|
724
1010
|
diff: event.diff,
|
|
725
1011
|
status: event.status,
|
|
726
1012
|
conversationId: deps.ctx.conversationId,
|
|
1013
|
+
messageId: state.lastAssistantMessageId,
|
|
727
1014
|
imageData: imageDataList?.[0],
|
|
728
1015
|
imageDataList,
|
|
729
1016
|
toolUseId: event.toolUseId,
|
|
@@ -827,6 +1114,7 @@ function annotatePersistedAssistantMessage(
|
|
|
827
1114
|
actions: surface.actions,
|
|
828
1115
|
display: surface.display,
|
|
829
1116
|
...(surface.persistent ? { persistent: true } : {}),
|
|
1117
|
+
...(surface.toolCallId ? { toolCallId: surface.toolCallId } : {}),
|
|
830
1118
|
} as unknown as ContentBlock);
|
|
831
1119
|
}
|
|
832
1120
|
modified = true;
|
|
@@ -903,6 +1191,69 @@ function handleError(
|
|
|
903
1191
|
}
|
|
904
1192
|
}
|
|
905
1193
|
|
|
1194
|
+
export function handleMaxTokensReached(
|
|
1195
|
+
_state: EventHandlerState,
|
|
1196
|
+
deps: EventHandlerDeps,
|
|
1197
|
+
event: Extract<AgentEvent, { type: "max_tokens_reached" }>,
|
|
1198
|
+
): void {
|
|
1199
|
+
const classified = maxTokensReachedClassification();
|
|
1200
|
+
const surfaceId = `max_tokens_${uuid()}`;
|
|
1201
|
+
const data: CardSurfaceData = {
|
|
1202
|
+
title: "Response limit reached",
|
|
1203
|
+
subtitle: "The partial response above was saved.",
|
|
1204
|
+
body: classified.userMessage,
|
|
1205
|
+
};
|
|
1206
|
+
const actions: SurfaceAction[] = [
|
|
1207
|
+
{
|
|
1208
|
+
id: "relay_prompt",
|
|
1209
|
+
label: "Continue",
|
|
1210
|
+
style: "primary",
|
|
1211
|
+
data: {
|
|
1212
|
+
prompt: MAX_TOKENS_CONTINUE_PROMPT,
|
|
1213
|
+
_completeSurface: true,
|
|
1214
|
+
_completionSummary: MAX_TOKENS_SURFACE_COMPLETION_SUMMARY,
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
];
|
|
1218
|
+
|
|
1219
|
+
deps.ctx.surfaceState.set(surfaceId, {
|
|
1220
|
+
surfaceType: "card",
|
|
1221
|
+
title: data.title,
|
|
1222
|
+
data,
|
|
1223
|
+
actions,
|
|
1224
|
+
});
|
|
1225
|
+
deps.ctx.currentTurnSurfaces.push({
|
|
1226
|
+
surfaceId,
|
|
1227
|
+
surfaceType: "card",
|
|
1228
|
+
title: data.title,
|
|
1229
|
+
data,
|
|
1230
|
+
actions,
|
|
1231
|
+
display: "inline",
|
|
1232
|
+
persistent: true,
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
deps.rlog.warn(
|
|
1236
|
+
{
|
|
1237
|
+
conversationId: deps.ctx.conversationId,
|
|
1238
|
+
stopReason: event.stopReason,
|
|
1239
|
+
surfaceId,
|
|
1240
|
+
},
|
|
1241
|
+
"Surfacing max-tokens continuation card",
|
|
1242
|
+
);
|
|
1243
|
+
|
|
1244
|
+
deps.onEvent({
|
|
1245
|
+
type: "ui_surface_show",
|
|
1246
|
+
conversationId: deps.ctx.conversationId,
|
|
1247
|
+
surfaceId,
|
|
1248
|
+
surfaceType: "card",
|
|
1249
|
+
title: data.title,
|
|
1250
|
+
data,
|
|
1251
|
+
actions,
|
|
1252
|
+
display: "inline",
|
|
1253
|
+
persistent: true,
|
|
1254
|
+
} as UiSurfaceShow);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
906
1257
|
export async function handleMessageComplete(
|
|
907
1258
|
state: EventHandlerState,
|
|
908
1259
|
deps: EventHandlerDeps,
|
|
@@ -911,12 +1262,36 @@ export async function handleMessageComplete(
|
|
|
911
1262
|
// Reset per-turn tool tracking for the new turn.
|
|
912
1263
|
state.currentTurnToolUseIds = [];
|
|
913
1264
|
|
|
1265
|
+
// Cancel any pending debounced partial flush and await an already
|
|
1266
|
+
// in-flight one before the authoritative `updateContent` below.
|
|
1267
|
+
// Without the timer-clear, a timer that fires during this handler
|
|
1268
|
+
// could double-write (idempotent in content but wastes a write) or
|
|
1269
|
+
// race ahead of the indexer/projector and serve a stale snapshot.
|
|
1270
|
+
// Without the await, a partial pipeline call that was dispatched a
|
|
1271
|
+
// moment before this handler can settle AFTER the final write and
|
|
1272
|
+
// overwrite the authoritative row.
|
|
1273
|
+
if (state.pendingPartialFlushTimer !== undefined) {
|
|
1274
|
+
clearTimeout(state.pendingPartialFlushTimer);
|
|
1275
|
+
state.pendingPartialFlushTimer = undefined;
|
|
1276
|
+
}
|
|
1277
|
+
if (state.pendingPartialFlushPromise !== undefined) {
|
|
1278
|
+
try {
|
|
1279
|
+
await state.pendingPartialFlushPromise;
|
|
1280
|
+
} catch {
|
|
1281
|
+
// The partial flush swallows its own pipeline errors via
|
|
1282
|
+
// `rlog.warn`; the `try`/`catch` here is defensive against
|
|
1283
|
+
// future changes that might surface them.
|
|
1284
|
+
}
|
|
1285
|
+
state.pendingPartialFlushPromise = undefined;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
914
1288
|
// Flush any remaining directive display buffer
|
|
915
1289
|
if (state.pendingDirectiveDisplayBuffer.length > 0) {
|
|
916
1290
|
deps.onEvent({
|
|
917
1291
|
type: "assistant_text_delta",
|
|
918
1292
|
text: state.pendingDirectiveDisplayBuffer,
|
|
919
1293
|
conversationId: deps.ctx.conversationId,
|
|
1294
|
+
messageId: state.lastAssistantMessageId,
|
|
920
1295
|
});
|
|
921
1296
|
if (deps.shouldGenerateTitle)
|
|
922
1297
|
state.firstAssistantText += state.pendingDirectiveDisplayBuffer;
|
|
@@ -980,13 +1355,14 @@ export async function handleMessageComplete(
|
|
|
980
1355
|
state.pendingToolResults.clear();
|
|
981
1356
|
}
|
|
982
1357
|
|
|
983
|
-
//
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
const
|
|
1358
|
+
// Accumulate directives + warnings from the assistant content for
|
|
1359
|
+
// downstream attachment processing. `cleanAssistantContent` is also
|
|
1360
|
+
// called inside {@link buildPersistedAssistantContent} below; running
|
|
1361
|
+
// it here separately is the cheapest way to keep the directive
|
|
1362
|
+
// side-effects local to this handler while letting the shared helper
|
|
1363
|
+
// own the persisted-content shape.
|
|
1364
|
+
const { directives: msgDirectives, warnings: msgWarnings } =
|
|
1365
|
+
cleanAssistantContent(event.message.content);
|
|
990
1366
|
state.accumulatedDirectives.push(...msgDirectives);
|
|
991
1367
|
state.directiveWarnings.push(...msgWarnings);
|
|
992
1368
|
if (msgDirectives.length > 0) {
|
|
@@ -1008,104 +1384,135 @@ export async function handleMessageComplete(
|
|
|
1008
1384
|
// are applied in handleToolResult after all tools for the turn complete,
|
|
1009
1385
|
// then the persisted message is updated via updateMessageContent.
|
|
1010
1386
|
|
|
1011
|
-
// Build content
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
data: surface.data,
|
|
1020
|
-
actions: surface.actions,
|
|
1021
|
-
display: surface.display,
|
|
1022
|
-
...(surface.persistent ? { persistent: true } : {}),
|
|
1023
|
-
} as unknown as ContentBlock);
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
const assistantChannelMetadata: Record<string, unknown> = {
|
|
1027
|
-
...provenanceFromTrustContext(deps.ctx.trustContext),
|
|
1028
|
-
userMessageChannel: deps.turnChannelContext.userMessageChannel,
|
|
1029
|
-
assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
|
|
1030
|
-
userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
|
|
1031
|
-
assistantMessageInterface:
|
|
1032
|
-
deps.turnInterfaceContext.assistantMessageInterface,
|
|
1033
|
-
sentAt: state.turnStartedAt,
|
|
1034
|
-
};
|
|
1387
|
+
// Build the canonical persisted content (cleaned + surfaces +
|
|
1388
|
+
// redacted) via the shared helper. The partial-persist flush uses
|
|
1389
|
+
// the same helper with `surfaces=[]` so a mid-turn snapshot lands in
|
|
1390
|
+
// the same shape as the finalize.
|
|
1391
|
+
const contentForPersistence = buildPersistedAssistantContent(
|
|
1392
|
+
event.message.content as ContentBlock[],
|
|
1393
|
+
deps.ctx.currentTurnSurfaces,
|
|
1394
|
+
);
|
|
1035
1395
|
|
|
1036
|
-
//
|
|
1037
|
-
//
|
|
1038
|
-
//
|
|
1039
|
-
//
|
|
1040
|
-
//
|
|
1041
|
-
//
|
|
1042
|
-
// `
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
const threadTs = getThreadTs(deps.ctx.conversationId);
|
|
1049
|
-
const timestampTimezone = resolveAssistantReplyTimestampTimezone(
|
|
1050
|
-
deps.ctx,
|
|
1051
|
-
);
|
|
1052
|
-
const timestampTimezoneLabel = formatSlackTimezoneLabel(
|
|
1053
|
-
timestampTimezone,
|
|
1054
|
-
{ nowMs: state.turnStartedAt },
|
|
1055
|
-
);
|
|
1056
|
-
const partialSlackMeta: Partial<SlackMessageMetadata> = {
|
|
1057
|
-
source: "slack",
|
|
1058
|
-
eventKind: "message",
|
|
1059
|
-
channelId,
|
|
1060
|
-
...(threadTs ? { threadTs } : {}),
|
|
1061
|
-
timestampTimezone,
|
|
1062
|
-
...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
|
|
1063
|
-
};
|
|
1064
|
-
assistantChannelMetadata.slackMeta = writeSlackMetadata(
|
|
1065
|
-
// `channelTs` is filled in by the post-send reconciliation step in
|
|
1066
|
-
// `deliverReplyViaCallback`; cast through the Partial to satisfy
|
|
1067
|
-
// the writer's type at this pre-send boundary.
|
|
1068
|
-
partialSlackMeta as SlackMessageMetadata,
|
|
1069
|
-
);
|
|
1070
|
-
}
|
|
1396
|
+
// The row was reserved at `llm_call_started` (with channel metadata
|
|
1397
|
+
// stamped at that point) and `state.lastAssistantMessageId` carries its
|
|
1398
|
+
// id. Flush the final content via `updateContent` instead of inserting a
|
|
1399
|
+
// new row. No `syncToDisk` flag here — the orchestrator separately
|
|
1400
|
+
// invokes `syncMessageToDisk` on `state.lastAssistantMessageId` after
|
|
1401
|
+
// the loop completes (see
|
|
1402
|
+
// `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
|
|
1403
|
+
const assistantMessageId = state.lastAssistantMessageId;
|
|
1404
|
+
if (!assistantMessageId) {
|
|
1405
|
+
throw new Error(
|
|
1406
|
+
"handleMessageComplete fired without a prior llm_call_started reserving an assistant row",
|
|
1407
|
+
);
|
|
1071
1408
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
// through unchanged. The live model history retains the original values.
|
|
1075
|
-
const contentForPersistence = contentWithSurfaces.map((block) => {
|
|
1076
|
-
if (block.type === "text") {
|
|
1077
|
-
const tb = block as Extract<ContentBlock, { type: "text" }>;
|
|
1078
|
-
return { ...tb, text: redactSecrets(tb.text) };
|
|
1079
|
-
}
|
|
1080
|
-
return block;
|
|
1081
|
-
});
|
|
1082
|
-
|
|
1083
|
-
// Route the assistant-message persistence through the `persistence`
|
|
1084
|
-
// pipeline. No `syncToDisk` here — the orchestrator separately invokes
|
|
1085
|
-
// `syncMessageToDisk` on `state.lastAssistantMessageId` after the loop
|
|
1086
|
-
// completes (see `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
|
|
1087
|
-
const assistantPersistResult = (await runPipeline<PersistArgs, PersistResult>(
|
|
1409
|
+
const contentJson = JSON.stringify(contentForPersistence);
|
|
1410
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
1088
1411
|
"persistence",
|
|
1089
1412
|
getMiddlewaresFor("persistence"),
|
|
1090
1413
|
defaultPersistenceTerminal,
|
|
1091
1414
|
{
|
|
1092
|
-
op: "
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
content: JSON.stringify(contentForPersistence),
|
|
1096
|
-
metadata: assistantChannelMetadata,
|
|
1415
|
+
op: "updateContent",
|
|
1416
|
+
messageId: assistantMessageId,
|
|
1417
|
+
content: contentJson,
|
|
1097
1418
|
},
|
|
1098
1419
|
buildHandlerTurnContext(deps),
|
|
1099
1420
|
DEFAULT_TIMEOUTS.persistence,
|
|
1100
|
-
)
|
|
1101
|
-
|
|
1102
|
-
|
|
1421
|
+
);
|
|
1422
|
+
state.assistantRowAwaitingFinalization = false;
|
|
1423
|
+
// Reset the partial-persist mirror so subsequent calls in this turn
|
|
1424
|
+
// start with an empty running view.
|
|
1425
|
+
state.currentMessageContent = [];
|
|
1426
|
+
|
|
1427
|
+
// ── Indexing + attention projection (restored from the pre-B3 `add` path) ──
|
|
1428
|
+
// `reserveMessage` + `updateMessageContent` are CRUD-only: they don't run
|
|
1429
|
+
// the memory indexer or the attention-cursor projector. The pre-B3 path
|
|
1430
|
+
// wrote the row via `addMessage`, which ran both as side-effects of the
|
|
1431
|
+
// insert. Calling them here keeps the assistant row's external state
|
|
1432
|
+
// (Qdrant segments, conversation attention cursor) in lockstep with the
|
|
1433
|
+
// finalized content. Both are non-fatal — a memory hiccup must not
|
|
1434
|
+
// escalate a successful generation into a turn-level throw. Indexing
|
|
1435
|
+
// intentionally fires AFTER `updateContent` succeeds so we never index
|
|
1436
|
+
// the empty reserved placeholder.
|
|
1437
|
+
const finalizedRow = getMessageById(
|
|
1438
|
+
assistantMessageId,
|
|
1439
|
+
deps.ctx.conversationId,
|
|
1440
|
+
);
|
|
1441
|
+
if (finalizedRow) {
|
|
1442
|
+
let provenanceTrustClass:
|
|
1443
|
+
| "guardian"
|
|
1444
|
+
| "trusted_contact"
|
|
1445
|
+
| "unknown"
|
|
1446
|
+
| undefined;
|
|
1447
|
+
let automated: boolean | undefined;
|
|
1448
|
+
if (finalizedRow.metadata) {
|
|
1449
|
+
try {
|
|
1450
|
+
const parsedMeta = messageMetadataSchema.safeParse(
|
|
1451
|
+
JSON.parse(finalizedRow.metadata),
|
|
1452
|
+
);
|
|
1453
|
+
if (parsedMeta.success) {
|
|
1454
|
+
provenanceTrustClass = parsedMeta.data.provenanceTrustClass;
|
|
1455
|
+
automated = parsedMeta.data.automated;
|
|
1456
|
+
}
|
|
1457
|
+
} catch {
|
|
1458
|
+
// Malformed metadata JSON — fall through with undefined fields,
|
|
1459
|
+
// matching the legacy behavior in `addMessage`.
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
try {
|
|
1463
|
+
await indexMessageNow(
|
|
1464
|
+
{
|
|
1465
|
+
messageId: assistantMessageId,
|
|
1466
|
+
conversationId: deps.ctx.conversationId,
|
|
1467
|
+
role: "assistant",
|
|
1468
|
+
content: contentJson,
|
|
1469
|
+
createdAt: finalizedRow.createdAt,
|
|
1470
|
+
scopeId: "default",
|
|
1471
|
+
provenanceTrustClass,
|
|
1472
|
+
automated,
|
|
1473
|
+
},
|
|
1474
|
+
getConfig().memory,
|
|
1475
|
+
);
|
|
1476
|
+
} catch (err) {
|
|
1477
|
+
deps.rlog.warn(
|
|
1478
|
+
{
|
|
1479
|
+
err,
|
|
1480
|
+
conversationId: deps.ctx.conversationId,
|
|
1481
|
+
messageId: assistantMessageId,
|
|
1482
|
+
},
|
|
1483
|
+
"Failed to index assistant message for memory (non-fatal)",
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
try {
|
|
1487
|
+
const attentionStateChanged = projectAssistantMessage({
|
|
1488
|
+
conversationId: deps.ctx.conversationId,
|
|
1489
|
+
messageId: assistantMessageId,
|
|
1490
|
+
messageAt: finalizedRow.createdAt,
|
|
1491
|
+
});
|
|
1492
|
+
if (attentionStateChanged) {
|
|
1493
|
+
void publishSyncInvalidation([
|
|
1494
|
+
conversationMetadataSyncTag(deps.ctx.conversationId),
|
|
1495
|
+
]);
|
|
1496
|
+
}
|
|
1497
|
+
} catch (err) {
|
|
1498
|
+
deps.rlog.warn(
|
|
1499
|
+
{
|
|
1500
|
+
err,
|
|
1501
|
+
conversationId: deps.ctx.conversationId,
|
|
1502
|
+
messageId: assistantMessageId,
|
|
1503
|
+
},
|
|
1504
|
+
"Failed to project assistant message for attention tracking (non-fatal)",
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1103
1508
|
|
|
1104
1509
|
// Backfill message_id on all LLM request logs from this turn.
|
|
1105
1510
|
// The agent loop is single-threaded per conversation, so all rows with
|
|
1106
|
-
// message_id IS NULL belong to the current turn.
|
|
1511
|
+
// message_id IS NULL belong to the current turn. The reserved id was
|
|
1512
|
+
// available before the LLM call ran but the logs are inserted DURING
|
|
1513
|
+
// the call, so the sweep still runs here.
|
|
1107
1514
|
try {
|
|
1108
|
-
backfillMessageIdOnLogs(deps.ctx.conversationId,
|
|
1515
|
+
backfillMessageIdOnLogs(deps.ctx.conversationId, assistantMessageId);
|
|
1109
1516
|
} catch (err) {
|
|
1110
1517
|
deps.rlog.warn(
|
|
1111
1518
|
{ err },
|
|
@@ -1114,7 +1521,10 @@ export async function handleMessageComplete(
|
|
|
1114
1521
|
}
|
|
1115
1522
|
|
|
1116
1523
|
try {
|
|
1117
|
-
backfillMemoryRecallLogMessageId(
|
|
1524
|
+
backfillMemoryRecallLogMessageId(
|
|
1525
|
+
deps.ctx.conversationId,
|
|
1526
|
+
assistantMessageId,
|
|
1527
|
+
);
|
|
1118
1528
|
} catch (err) {
|
|
1119
1529
|
deps.rlog.warn(
|
|
1120
1530
|
{ err },
|
|
@@ -1125,7 +1535,7 @@ export async function handleMessageComplete(
|
|
|
1125
1535
|
try {
|
|
1126
1536
|
backfillMemoryV2ActivationMessageId(
|
|
1127
1537
|
deps.ctx.conversationId,
|
|
1128
|
-
|
|
1538
|
+
assistantMessageId,
|
|
1129
1539
|
);
|
|
1130
1540
|
} catch (err) {
|
|
1131
1541
|
deps.rlog.warn(
|
|
@@ -1136,8 +1546,10 @@ export async function handleMessageComplete(
|
|
|
1136
1546
|
|
|
1137
1547
|
deps.ctx.currentTurnSurfaces = [];
|
|
1138
1548
|
|
|
1139
|
-
// Emit trace event
|
|
1140
|
-
|
|
1549
|
+
// Emit trace event. Char count is computed from the cleaned +
|
|
1550
|
+
// redacted text blocks (UI surface blocks filtered out via the
|
|
1551
|
+
// type guard) — same shape as what was just persisted.
|
|
1552
|
+
const charCount = contentForPersistence
|
|
1141
1553
|
.filter(
|
|
1142
1554
|
(b): b is Extract<ContentBlock, { type: "text" }> => b.type === "text",
|
|
1143
1555
|
)
|
|
@@ -1236,6 +1648,36 @@ function handleUsage(
|
|
|
1236
1648
|
},
|
|
1237
1649
|
);
|
|
1238
1650
|
state.llmCallStartedEmitted = false;
|
|
1651
|
+
|
|
1652
|
+
// Emit a lightweight per-call usage progress event so clients can show
|
|
1653
|
+
// live-updating token/cost metrics. This is a UI hint only — no DB writes.
|
|
1654
|
+
const pricingUsage = buildPricingUsage({
|
|
1655
|
+
providerName,
|
|
1656
|
+
model: event.model,
|
|
1657
|
+
inputTokens: event.inputTokens,
|
|
1658
|
+
outputTokens: event.outputTokens,
|
|
1659
|
+
cacheCreationInputTokens: event.cacheCreationInputTokens,
|
|
1660
|
+
cacheReadInputTokens: event.cacheReadInputTokens,
|
|
1661
|
+
rawResponse: event.rawResponse,
|
|
1662
|
+
});
|
|
1663
|
+
const pricing = resolveStructuredPricing(
|
|
1664
|
+
providerName,
|
|
1665
|
+
event.model,
|
|
1666
|
+
pricingUsage,
|
|
1667
|
+
);
|
|
1668
|
+
const estimatedCost =
|
|
1669
|
+
pricing.pricingStatus === "priced" && pricing.estimatedCostUsd != null
|
|
1670
|
+
? pricing.estimatedCostUsd
|
|
1671
|
+
: 0;
|
|
1672
|
+
|
|
1673
|
+
deps.onEvent({
|
|
1674
|
+
type: "usage_progress",
|
|
1675
|
+
conversationId: deps.ctx.conversationId,
|
|
1676
|
+
inputTokens: event.inputTokens,
|
|
1677
|
+
outputTokens: event.outputTokens,
|
|
1678
|
+
estimatedCost,
|
|
1679
|
+
model: event.model,
|
|
1680
|
+
});
|
|
1239
1681
|
}
|
|
1240
1682
|
|
|
1241
1683
|
/**
|
|
@@ -1295,6 +1737,9 @@ export async function dispatchAgentEvent(
|
|
|
1295
1737
|
): Promise<void> {
|
|
1296
1738
|
try {
|
|
1297
1739
|
switch (event.type) {
|
|
1740
|
+
case "llm_call_started":
|
|
1741
|
+
await handleLlmCallStarted(state, deps);
|
|
1742
|
+
break;
|
|
1298
1743
|
case "text_delta":
|
|
1299
1744
|
handleTextDelta(state, deps, event);
|
|
1300
1745
|
break;
|
|
@@ -1320,13 +1765,10 @@ export async function dispatchAgentEvent(
|
|
|
1320
1765
|
const query =
|
|
1321
1766
|
typeof event.input.query === "string" ? event.input.query : "";
|
|
1322
1767
|
const statusText = formatSearchStatusText(event.name, query);
|
|
1323
|
-
deps.ctx.emitActivityState(
|
|
1324
|
-
|
|
1325
|
-
"tool_use_start",
|
|
1326
|
-
"assistant_turn",
|
|
1327
|
-
deps.reqId,
|
|
1768
|
+
deps.ctx.emitActivityState("tool_running", "tool_use_start", {
|
|
1769
|
+
requestId: deps.reqId,
|
|
1328
1770
|
statusText,
|
|
1329
|
-
);
|
|
1771
|
+
});
|
|
1330
1772
|
state.serverToolStartedAt.set(event.toolUseId, Date.now());
|
|
1331
1773
|
state.serverToolInputs.set(event.toolUseId, event.input);
|
|
1332
1774
|
deps.onEvent({
|
|
@@ -1335,17 +1777,15 @@ export async function dispatchAgentEvent(
|
|
|
1335
1777
|
input: event.input,
|
|
1336
1778
|
conversationId: deps.ctx.conversationId,
|
|
1337
1779
|
toolUseId: event.toolUseId,
|
|
1780
|
+
messageId: state.lastAssistantMessageId,
|
|
1338
1781
|
});
|
|
1339
1782
|
break;
|
|
1340
1783
|
}
|
|
1341
1784
|
case "server_tool_complete": {
|
|
1342
|
-
deps.ctx.emitActivityState(
|
|
1343
|
-
|
|
1344
|
-
"
|
|
1345
|
-
|
|
1346
|
-
deps.reqId,
|
|
1347
|
-
"Thinking",
|
|
1348
|
-
);
|
|
1785
|
+
deps.ctx.emitActivityState("streaming", "tool_result_received", {
|
|
1786
|
+
requestId: deps.reqId,
|
|
1787
|
+
statusText: "Thinking",
|
|
1788
|
+
});
|
|
1349
1789
|
|
|
1350
1790
|
// Prefer `resolvedInput` (Anthropic's accumulated server-tool input,
|
|
1351
1791
|
// populated on content_block_stop) over the input captured at
|
|
@@ -1414,13 +1854,31 @@ export async function dispatchAgentEvent(
|
|
|
1414
1854
|
isError: event.isError,
|
|
1415
1855
|
conversationId: deps.ctx.conversationId,
|
|
1416
1856
|
toolUseId: event.toolUseId,
|
|
1857
|
+
messageId: state.lastAssistantMessageId,
|
|
1417
1858
|
...(metadata ? { activityMetadata: { webSearch: metadata } } : {}),
|
|
1418
1859
|
});
|
|
1419
1860
|
break;
|
|
1420
1861
|
}
|
|
1862
|
+
case "context_compacting":
|
|
1863
|
+
deps.ctx.emitActivityState("thinking", "context_compacting", {
|
|
1864
|
+
requestId: deps.reqId,
|
|
1865
|
+
statusText: "Compacting context",
|
|
1866
|
+
});
|
|
1867
|
+
break;
|
|
1868
|
+
case "compaction_circuit_open":
|
|
1869
|
+
case "compaction_circuit_closed":
|
|
1870
|
+
// Circuit-breaker transitions are already in wire-contract shape
|
|
1871
|
+
// (a subset of ServerMessage), so forward them to the client sink
|
|
1872
|
+
// unchanged. They drive the client's "auto-compaction paused"
|
|
1873
|
+
// banner.
|
|
1874
|
+
deps.onEvent(event);
|
|
1875
|
+
break;
|
|
1421
1876
|
case "error":
|
|
1422
1877
|
handleError(state, deps, event);
|
|
1423
1878
|
break;
|
|
1879
|
+
case "max_tokens_reached":
|
|
1880
|
+
handleMaxTokensReached(state, deps, event);
|
|
1881
|
+
break;
|
|
1424
1882
|
case "provider_error":
|
|
1425
1883
|
handleProviderError(deps, event);
|
|
1426
1884
|
break;
|