@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
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
AgentLoop,
|
|
18
18
|
AgentLoopExitReason,
|
|
19
19
|
CheckpointDecision,
|
|
20
|
-
|
|
20
|
+
MidLoopCompaction,
|
|
21
21
|
} from "../agent/loop.js";
|
|
22
22
|
import { createAssistantMessage } from "../agent/message-types.js";
|
|
23
23
|
import type {
|
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
TurnChannelContext,
|
|
27
27
|
TurnInterfaceContext,
|
|
28
28
|
} from "../channels/types.js";
|
|
29
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
29
30
|
import {
|
|
30
31
|
contextWindowConfigFromEffective,
|
|
31
32
|
type EffectiveContextWindow,
|
|
@@ -59,6 +60,7 @@ import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
|
59
60
|
import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
60
61
|
import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
|
|
61
62
|
import {
|
|
63
|
+
deleteMessageById,
|
|
62
64
|
getConversation,
|
|
63
65
|
getConversationOriginChannel,
|
|
64
66
|
getConversationOriginInterface,
|
|
@@ -79,7 +81,10 @@ import {
|
|
|
79
81
|
} from "../memory/conversation-title-service.js";
|
|
80
82
|
import { isBackgroundConversationType } from "../memory/conversation-types.js";
|
|
81
83
|
import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
82
|
-
import {
|
|
84
|
+
import {
|
|
85
|
+
backfillMessageIdOnLogs,
|
|
86
|
+
recordSyntheticAgentErrorMessageLog,
|
|
87
|
+
} from "../memory/llm-request-log-store.js";
|
|
83
88
|
import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
|
|
84
89
|
import { enqueueMemoryRetrospectiveOnCompaction } from "../memory/memory-retrospective-enqueue.js";
|
|
85
90
|
import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
|
|
@@ -91,28 +96,24 @@ import {
|
|
|
91
96
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
92
97
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
93
98
|
import type { UserPromptSubmitContext } from "../plugin-api/types.js";
|
|
94
|
-
import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
|
|
95
|
-
import {
|
|
99
|
+
import { defaultCompactionTerminal } from "../plugins/defaults/compaction/terminal.js";
|
|
100
|
+
import { deepRepairHistory } from "../plugins/defaults/history-repair/terminal.js";
|
|
96
101
|
import {
|
|
97
102
|
asDefaultGraphPayload,
|
|
98
103
|
type DefaultMemoryRetrievalDeps,
|
|
99
104
|
type GraphMemoryPayload,
|
|
100
105
|
runDefaultMemoryRetrieval,
|
|
101
|
-
} from "../plugins/defaults/memory-retrieval.js";
|
|
102
|
-
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
103
|
-
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate.js";
|
|
104
|
-
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate.js";
|
|
106
|
+
} from "../plugins/defaults/memory-retrieval/register.js";
|
|
107
|
+
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence/terminal.js";
|
|
108
|
+
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate/terminal.js";
|
|
109
|
+
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate/terminal.js";
|
|
105
110
|
import { DEFAULT_TIMEOUTS, runHook, runPipeline } from "../plugins/pipeline.js";
|
|
106
111
|
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
107
112
|
import type {
|
|
108
|
-
CircuitBreakerArgs,
|
|
109
|
-
CircuitBreakerResult,
|
|
110
113
|
CompactionArgs,
|
|
111
114
|
CompactionResult,
|
|
112
115
|
EstimateArgs,
|
|
113
116
|
EstimateResult,
|
|
114
|
-
HistoryRepairArgs,
|
|
115
|
-
HistoryRepairResult,
|
|
116
117
|
MemoryArgs,
|
|
117
118
|
MemoryResult,
|
|
118
119
|
OverflowReduceArgs,
|
|
@@ -123,11 +124,6 @@ import type {
|
|
|
123
124
|
TurnContext as PluginTurnContext,
|
|
124
125
|
} from "../plugins/types.js";
|
|
125
126
|
import { PluginExecutionError, PluginTimeoutError } from "../plugins/types.js";
|
|
126
|
-
import {
|
|
127
|
-
hasProactiveArtifactCompleted,
|
|
128
|
-
runProactiveArtifactJob,
|
|
129
|
-
tryClaimProactiveArtifactTrigger,
|
|
130
|
-
} from "../proactive-artifact/index.js";
|
|
131
127
|
import type {
|
|
132
128
|
ContentBlock,
|
|
133
129
|
Message,
|
|
@@ -206,7 +202,6 @@ import {
|
|
|
206
202
|
} from "./date-context.js";
|
|
207
203
|
import { getDiskPressureStatus } from "./disk-pressure-guard.js";
|
|
208
204
|
import { classifyDiskPressureTurnPolicy } from "./disk-pressure-policy.js";
|
|
209
|
-
import { deepRepairHistory } from "./history-repair.js";
|
|
210
205
|
import type {
|
|
211
206
|
DynamicPageSurfaceData,
|
|
212
207
|
ServerMessage,
|
|
@@ -216,16 +211,37 @@ import type {
|
|
|
216
211
|
} from "./message-protocol.js";
|
|
217
212
|
import type { MemoryRecalled } from "./message-types/memory.js";
|
|
218
213
|
import type { ConfirmationStateChanged } from "./message-types/messages.js";
|
|
219
|
-
import {
|
|
220
|
-
conversationMetadataSyncTag,
|
|
221
|
-
SYNC_TAGS,
|
|
222
|
-
} from "./message-types/sync.js";
|
|
214
|
+
import { conversationMetadataSyncTag } from "./message-types/sync.js";
|
|
223
215
|
import { parseActualTokensFromError } from "./parse-actual-tokens-from-error.js";
|
|
224
216
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
225
217
|
import type { TrustContext } from "./trust-context.js";
|
|
226
218
|
import { stripHistoricalWebSearchResults } from "./web-search-history.js";
|
|
227
219
|
|
|
228
220
|
const log = getLogger("conversation-agent-loop");
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Best-effort persistence of the history-stripped marker after an
|
|
224
|
+
* injection-strip event (compaction / overflow recovery). The marker is a
|
|
225
|
+
* durability hint, not turn-critical state — a transient SQLite write failure
|
|
226
|
+
* (SQLITE_BUSY, disk-full, read-only FS) must not abort the turn. Logs a
|
|
227
|
+
* warning and continues on failure, preserving the long-standing non-fatal
|
|
228
|
+
* contract for this metadata write.
|
|
229
|
+
*/
|
|
230
|
+
function markHistoryStrippedBestEffort(
|
|
231
|
+
conversationId: string,
|
|
232
|
+
strippedAt: number,
|
|
233
|
+
logger: ReturnType<typeof getLogger>,
|
|
234
|
+
): void {
|
|
235
|
+
try {
|
|
236
|
+
setConversationHistoryStrippedAt(conversationId, strippedAt);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
logger.warn(
|
|
239
|
+
{ err },
|
|
240
|
+
"Failed to persist history-stripped marker after compaction strip (non-fatal)",
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
229
245
|
const DISK_PRESSURE_ERROR_CODE = "DISK_SPACE_CRITICAL" as const;
|
|
230
246
|
const DISK_PRESSURE_ERROR_CATEGORY = "disk_pressure";
|
|
231
247
|
|
|
@@ -251,154 +267,6 @@ function formatDiskPressureBlockedMessage(): string {
|
|
|
251
267
|
return "Storage is critically low, so background processes are paused and remote messages are ignored until the guardian frees enough space. Remote senders should try again later.";
|
|
252
268
|
}
|
|
253
269
|
|
|
254
|
-
// ── Compaction circuit-breaker pipeline helpers ─────────────────────
|
|
255
|
-
//
|
|
256
|
-
// The circuit-breaker behavior (3 consecutive summary-LLM failures trips a
|
|
257
|
-
// 1-hour cooldown) is now implemented by the `circuitBreaker` plugin
|
|
258
|
-
// pipeline. The default plugin (`plugins/defaults/circuit-breaker.ts`)
|
|
259
|
-
// replicates the legacy threshold/cooldown constants and event-emission
|
|
260
|
-
// semantics exactly — it operates on the `consecutiveCompactionFailures` /
|
|
261
|
-
// `compactionCircuitOpenUntil` fields the conversation still owns so the
|
|
262
|
-
// dev-only playground routes (`POST /playground/reset-compaction-circuit`,
|
|
263
|
-
// `POST /playground/inject-compaction-failures`) continue to read and
|
|
264
|
-
// mutate those fields directly.
|
|
265
|
-
//
|
|
266
|
-
// The helpers below build the pipeline inputs and invoke the runner. They
|
|
267
|
-
// are the sole entry points the rest of the daemon uses to query or update
|
|
268
|
-
// the compaction circuit.
|
|
269
|
-
|
|
270
|
-
/** Circuit-breaker key for a specific conversation's compaction pipeline. */
|
|
271
|
-
function compactionCircuitKey(conversationId: string): string {
|
|
272
|
-
return `compaction:${conversationId}`;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Build the minimal {@link TurnContext} the pipeline runner requires. Called
|
|
277
|
-
* both from inside the agent loop (where turn identifiers are available) and
|
|
278
|
-
* from non-turn invocations like `Conversation.forceCompact` (which falls
|
|
279
|
-
* back to stable placeholders so the runner's log records still carry the
|
|
280
|
-
* conversation identifier).
|
|
281
|
-
*/
|
|
282
|
-
function buildCircuitTurnContext(ctx: {
|
|
283
|
-
readonly conversationId: string;
|
|
284
|
-
currentRequestId?: string;
|
|
285
|
-
currentTurnTrustContext?: TrustContext;
|
|
286
|
-
trustContext?: TrustContext;
|
|
287
|
-
turnCount: number;
|
|
288
|
-
}): PluginTurnContext {
|
|
289
|
-
const trust: TrustContext =
|
|
290
|
-
ctx.currentTurnTrustContext ?? ctx.trustContext ?? FALLBACK_TURN_TRUST;
|
|
291
|
-
return {
|
|
292
|
-
requestId: ctx.currentRequestId ?? "circuit-breaker",
|
|
293
|
-
conversationId: ctx.conversationId,
|
|
294
|
-
turnIndex: ctx.turnCount,
|
|
295
|
-
trust,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Run the `circuitBreaker` pipeline for the compaction circuit on this
|
|
301
|
-
* conversation. When `outcome` is provided, state is updated (and transition
|
|
302
|
-
* events emit via `onEvent`); when omitted the call is query-only.
|
|
303
|
-
*
|
|
304
|
-
* Returns the post-call decision from the pipeline. Callers gate auto-paths
|
|
305
|
-
* on `!result.open` and admit forced paths regardless of the decision.
|
|
306
|
-
*/
|
|
307
|
-
async function runCompactionCircuitPipeline(
|
|
308
|
-
ctx: {
|
|
309
|
-
readonly conversationId: string;
|
|
310
|
-
consecutiveCompactionFailures: number;
|
|
311
|
-
compactionCircuitOpenUntil: number | null;
|
|
312
|
-
currentRequestId?: string;
|
|
313
|
-
currentTurnTrustContext?: TrustContext;
|
|
314
|
-
trustContext?: TrustContext;
|
|
315
|
-
turnCount: number;
|
|
316
|
-
},
|
|
317
|
-
args: {
|
|
318
|
-
outcome?: "success" | "failure";
|
|
319
|
-
onEvent?: (msg: ServerMessage) => void;
|
|
320
|
-
},
|
|
321
|
-
): Promise<CircuitBreakerResult> {
|
|
322
|
-
const turnContext = buildCircuitTurnContext(ctx);
|
|
323
|
-
return runPipeline<CircuitBreakerArgs, CircuitBreakerResult>(
|
|
324
|
-
"circuitBreaker",
|
|
325
|
-
getMiddlewaresFor("circuitBreaker"),
|
|
326
|
-
async (terminalArgs) => {
|
|
327
|
-
// No plugin in the chain produced a decision. This should be
|
|
328
|
-
// unreachable in production because the default plugin registers a
|
|
329
|
-
// `circuitBreaker` middleware that always returns a decision, but we
|
|
330
|
-
// defensively derive the state here so test setups that intentionally
|
|
331
|
-
// omit the default plugin still get a sensible response.
|
|
332
|
-
const openUntil = terminalArgs.state.compactionCircuitOpenUntil;
|
|
333
|
-
const now = Date.now();
|
|
334
|
-
if (openUntil !== null && now < openUntil) {
|
|
335
|
-
return { open: true, cooldownRemainingMs: openUntil - now };
|
|
336
|
-
}
|
|
337
|
-
return { open: false };
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
key: compactionCircuitKey(ctx.conversationId),
|
|
341
|
-
// Pass the ctx directly as the mutable state container. The
|
|
342
|
-
// `CircuitBreakerArgs.state` shape deliberately matches the subset of
|
|
343
|
-
// fields the conversation owns so plugins mutate the same object the
|
|
344
|
-
// playground routes read and write.
|
|
345
|
-
state: ctx,
|
|
346
|
-
...(args.outcome !== undefined ? { outcome: args.outcome } : {}),
|
|
347
|
-
...(args.onEvent ? { onEvent: args.onEvent } : {}),
|
|
348
|
-
},
|
|
349
|
-
turnContext,
|
|
350
|
-
DEFAULT_TIMEOUTS.circuitBreaker,
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Query-only: is the compaction circuit breaker currently open for this
|
|
356
|
-
* conversation? Thin wrapper around {@link runCompactionCircuitPipeline}
|
|
357
|
-
* with no outcome. Async because the pipeline runner is async, but the
|
|
358
|
-
* default plugin resolves synchronously on its microtask.
|
|
359
|
-
*/
|
|
360
|
-
async function isCompactionCircuitOpen(ctx: {
|
|
361
|
-
readonly conversationId: string;
|
|
362
|
-
consecutiveCompactionFailures: number;
|
|
363
|
-
compactionCircuitOpenUntil: number | null;
|
|
364
|
-
currentRequestId?: string;
|
|
365
|
-
currentTurnTrustContext?: TrustContext;
|
|
366
|
-
trustContext?: TrustContext;
|
|
367
|
-
turnCount: number;
|
|
368
|
-
}): Promise<boolean> {
|
|
369
|
-
const decision = await runCompactionCircuitPipeline(ctx, {});
|
|
370
|
-
return decision.open;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Update the compaction circuit breaker with the outcome of a `maybeCompact`
|
|
375
|
-
* call and emit any transition event. A `summaryFailed` value of `undefined`
|
|
376
|
-
* means the summary LLM never ran (early return) — callers must guard with
|
|
377
|
-
* `summaryFailed !== undefined` before invoking this helper so early-return
|
|
378
|
-
* paths don't silently reset the 3-strike counter.
|
|
379
|
-
*
|
|
380
|
-
* The default plugin handles threshold-based tripping and cooldown reset;
|
|
381
|
-
* see `plugins/defaults/circuit-breaker.ts` for the canonical semantics.
|
|
382
|
-
*/
|
|
383
|
-
export async function trackCompactionOutcome(
|
|
384
|
-
ctx: {
|
|
385
|
-
readonly conversationId: string;
|
|
386
|
-
consecutiveCompactionFailures: number;
|
|
387
|
-
compactionCircuitOpenUntil: number | null;
|
|
388
|
-
currentRequestId?: string;
|
|
389
|
-
currentTurnTrustContext?: TrustContext;
|
|
390
|
-
trustContext?: TrustContext;
|
|
391
|
-
turnCount: number;
|
|
392
|
-
},
|
|
393
|
-
summaryFailed: boolean,
|
|
394
|
-
onEvent: (msg: ServerMessage) => void,
|
|
395
|
-
): Promise<void> {
|
|
396
|
-
await runCompactionCircuitPipeline(ctx, {
|
|
397
|
-
outcome: summaryFailed ? "failure" : "success",
|
|
398
|
-
onEvent,
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
270
|
// ── Plugin pipeline helpers ──────────────────────────────────────────
|
|
403
271
|
//
|
|
404
272
|
// Canonical {@link PluginTurnContext} builder threaded into every
|
|
@@ -459,6 +327,28 @@ function buildPluginTurnContext(
|
|
|
459
327
|
|
|
460
328
|
// ── Context Interface ────────────────────────────────────────────────
|
|
461
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Per-surface entry tracked on the current turn. Inline shape kept stable so
|
|
332
|
+
* routes and persistence helpers can consume it via a named import instead of
|
|
333
|
+
* `infer`-extracting from {@link AgentLoopConversationContext}.
|
|
334
|
+
*/
|
|
335
|
+
export interface AssistantSurface {
|
|
336
|
+
surfaceId: string;
|
|
337
|
+
surfaceType: SurfaceType;
|
|
338
|
+
title?: string;
|
|
339
|
+
data: SurfaceData;
|
|
340
|
+
actions?: Array<{
|
|
341
|
+
id: string;
|
|
342
|
+
label: string;
|
|
343
|
+
style?: string;
|
|
344
|
+
data?: Record<string, unknown>;
|
|
345
|
+
}>;
|
|
346
|
+
display?: string;
|
|
347
|
+
persistent?: boolean;
|
|
348
|
+
/** Id of the tool call that produced this surface (the `ui_show` proxy tool). Persisted so app previews can gate on the tool result's arrival rather than whole-turn streaming state. */
|
|
349
|
+
toolCallId?: string;
|
|
350
|
+
}
|
|
351
|
+
|
|
462
352
|
export interface AgentLoopConversationContext {
|
|
463
353
|
readonly conversationId: string;
|
|
464
354
|
messages: Message[];
|
|
@@ -482,10 +372,6 @@ export interface AgentLoopConversationContext {
|
|
|
482
372
|
* happened just before this turn).
|
|
483
373
|
*/
|
|
484
374
|
pendingPostCompactReinject: boolean;
|
|
485
|
-
/** Tracks consecutive compaction failures (summary LLM call threw). */
|
|
486
|
-
consecutiveCompactionFailures: number;
|
|
487
|
-
/** Timestamp (ms since epoch) until which the circuit breaker is open. */
|
|
488
|
-
compactionCircuitOpenUntil: number | null;
|
|
489
375
|
|
|
490
376
|
readonly graphMemory: ConversationGraphMemory;
|
|
491
377
|
|
|
@@ -508,15 +394,7 @@ export interface AgentLoopConversationContext {
|
|
|
508
394
|
pendingSurfaceActions: Map<string, { surfaceType: SurfaceType }>;
|
|
509
395
|
surfaceActionRequestIds: Set<string>;
|
|
510
396
|
approvedViaPromptThisTurn?: boolean;
|
|
511
|
-
currentTurnSurfaces:
|
|
512
|
-
surfaceId: string;
|
|
513
|
-
surfaceType: SurfaceType;
|
|
514
|
-
title?: string;
|
|
515
|
-
data: SurfaceData;
|
|
516
|
-
actions?: Array<{ id: string; label: string; style?: string }>;
|
|
517
|
-
display?: string;
|
|
518
|
-
persistent?: boolean;
|
|
519
|
-
}>;
|
|
397
|
+
currentTurnSurfaces: AssistantSurface[];
|
|
520
398
|
|
|
521
399
|
workingDir: string;
|
|
522
400
|
workspaceTopLevelContext: string | null;
|
|
@@ -541,12 +419,6 @@ export interface AgentLoopConversationContext {
|
|
|
541
419
|
* turn start.
|
|
542
420
|
*/
|
|
543
421
|
toolRoutedProfile?: string;
|
|
544
|
-
/**
|
|
545
|
-
* True when the user has explicitly selected an inference profile for this
|
|
546
|
-
* conversation (via the composer profile picker). When set, tool-based
|
|
547
|
-
* auto-routing is suppressed — the user's explicit choice takes precedence.
|
|
548
|
-
*/
|
|
549
|
-
hasExplicitProfileOverride?: boolean;
|
|
550
422
|
commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
551
423
|
trustContext?: TrustContext;
|
|
552
424
|
/** Task-run scope for the current turn. Cleared at turn end so queued/drained turns don't inherit it. */
|
|
@@ -600,9 +472,11 @@ export interface AgentLoopConversationContext {
|
|
|
600
472
|
| "message_complete"
|
|
601
473
|
| "generation_cancelled"
|
|
602
474
|
| "error_terminal",
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
475
|
+
options?: {
|
|
476
|
+
anchor?: "assistant_turn" | "user_turn" | "global";
|
|
477
|
+
requestId?: string;
|
|
478
|
+
statusText?: string;
|
|
479
|
+
},
|
|
606
480
|
): void;
|
|
607
481
|
emitConfirmationStateChanged(
|
|
608
482
|
params: ConfirmationStateChanged extends {
|
|
@@ -620,7 +494,6 @@ export interface AgentLoopConversationContext {
|
|
|
620
494
|
onConfirmationOutcome?: (
|
|
621
495
|
requestId: string,
|
|
622
496
|
state: string,
|
|
623
|
-
toolName?: string,
|
|
624
497
|
toolUseId?: string,
|
|
625
498
|
) => void;
|
|
626
499
|
|
|
@@ -724,8 +597,6 @@ export async function runAgentLoopImpl(
|
|
|
724
597
|
options?.overrideProfile ??
|
|
725
598
|
getConversationOverrideProfileFromRow(turnStartConversation);
|
|
726
599
|
|
|
727
|
-
ctx.hasExplicitProfileOverride = !!userExplicitOverride;
|
|
728
|
-
|
|
729
600
|
const config = getConfig();
|
|
730
601
|
|
|
731
602
|
// Tool-based auto-routing: the switch_inference_profile tool lets the model
|
|
@@ -746,12 +617,14 @@ export async function runAgentLoopImpl(
|
|
|
746
617
|
llm: config.llm,
|
|
747
618
|
callSite: turnCallSite,
|
|
748
619
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
620
|
+
selectionSeed: ctx.conversationId,
|
|
749
621
|
});
|
|
750
622
|
let currentEffectiveContextWindow: EffectiveContextWindow =
|
|
751
623
|
effectiveContextWindow;
|
|
752
624
|
let currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
753
625
|
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
754
626
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
627
|
+
selectionSeed: ctx.conversationId,
|
|
755
628
|
}).contextWindow,
|
|
756
629
|
currentEffectiveContextWindow,
|
|
757
630
|
);
|
|
@@ -770,10 +643,12 @@ export async function runAgentLoopImpl(
|
|
|
770
643
|
llm: config.llm,
|
|
771
644
|
callSite: turnCallSite,
|
|
772
645
|
overrideProfile: currentOverrideProfile,
|
|
646
|
+
selectionSeed: ctx.conversationId,
|
|
773
647
|
});
|
|
774
648
|
currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
775
649
|
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
776
650
|
overrideProfile: currentOverrideProfile,
|
|
651
|
+
selectionSeed: ctx.conversationId,
|
|
777
652
|
}).contextWindow,
|
|
778
653
|
currentEffectiveContextWindow,
|
|
779
654
|
);
|
|
@@ -833,6 +708,25 @@ export async function runAgentLoopImpl(
|
|
|
833
708
|
preflightBudget: Math.floor(providerMaxTokens * (1 - safetyMargin)),
|
|
834
709
|
};
|
|
835
710
|
};
|
|
711
|
+
/**
|
|
712
|
+
* The agent loop's window into the orchestrator's current effective
|
|
713
|
+
* context window. The loop reads `maxInputTokens` for tool-result
|
|
714
|
+
* truncation and `overflowRecovery` for its mid-loop budget gate, applying
|
|
715
|
+
* the long-history safety-margin bump itself off its own running history.
|
|
716
|
+
* Resolved fresh on each access so a mid-turn profile change is reflected.
|
|
717
|
+
*/
|
|
718
|
+
const resolveContextWindow = (): {
|
|
719
|
+
maxInputTokens: number;
|
|
720
|
+
overflowRecovery: { enabled: boolean; safetyMarginRatio: number };
|
|
721
|
+
} => {
|
|
722
|
+
refreshCurrentProfileState();
|
|
723
|
+
const { enabled, safetyMarginRatio } =
|
|
724
|
+
currentEffectiveContextWindow.overflowRecovery;
|
|
725
|
+
return {
|
|
726
|
+
maxInputTokens: currentEffectiveContextWindow.maxInputTokens,
|
|
727
|
+
overflowRecovery: { enabled, safetyMarginRatio },
|
|
728
|
+
};
|
|
729
|
+
};
|
|
836
730
|
|
|
837
731
|
// Initial value for `createToolExecutor` to read into
|
|
838
732
|
// `ToolContext.overrideProfile`. `resolveCurrentOverrideProfile` refreshes
|
|
@@ -942,7 +836,10 @@ export async function runAgentLoopImpl(
|
|
|
942
836
|
{ reason: diskPressureDecision.reason },
|
|
943
837
|
"Blocked turn during disk pressure cleanup mode",
|
|
944
838
|
);
|
|
945
|
-
ctx.emitActivityState("idle", "error_terminal",
|
|
839
|
+
ctx.emitActivityState("idle", "error_terminal", {
|
|
840
|
+
anchor: "global",
|
|
841
|
+
requestId: reqId,
|
|
842
|
+
});
|
|
946
843
|
ctx.traceEmitter.emit("request_error", message, {
|
|
947
844
|
requestId: reqId,
|
|
948
845
|
status: "error",
|
|
@@ -1028,10 +925,7 @@ export async function runAgentLoopImpl(
|
|
|
1028
925
|
});
|
|
1029
926
|
onEvent({
|
|
1030
927
|
type: "sync_changed",
|
|
1031
|
-
tags: [
|
|
1032
|
-
SYNC_TAGS.conversationsList,
|
|
1033
|
-
conversationMetadataSyncTag(ctx.conversationId),
|
|
1034
|
-
],
|
|
928
|
+
tags: [conversationMetadataSyncTag(ctx.conversationId)],
|
|
1035
929
|
});
|
|
1036
930
|
},
|
|
1037
931
|
};
|
|
@@ -1197,14 +1091,12 @@ export async function runAgentLoopImpl(
|
|
|
1197
1091
|
);
|
|
1198
1092
|
// Skip auto-compaction while the circuit breaker is open. Force paths
|
|
1199
1093
|
// and user-initiated /compact bypass this check.
|
|
1200
|
-
const autoCompactAllowed =
|
|
1094
|
+
const autoCompactAllowed =
|
|
1095
|
+
!(await ctx.agentLoop.compactionCircuit.isOpen(ctx));
|
|
1201
1096
|
if (compactCheck.needed && autoCompactAllowed) {
|
|
1202
|
-
ctx.emitActivityState(
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
"assistant_turn",
|
|
1206
|
-
reqId,
|
|
1207
|
-
);
|
|
1097
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
1098
|
+
requestId: reqId,
|
|
1099
|
+
});
|
|
1208
1100
|
}
|
|
1209
1101
|
const compactionOptions = {
|
|
1210
1102
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
@@ -1212,6 +1104,7 @@ export async function runAgentLoopImpl(
|
|
|
1212
1104
|
conversationOriginChannel:
|
|
1213
1105
|
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
1214
1106
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1107
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
1215
1108
|
};
|
|
1216
1109
|
let compacted: Awaited<
|
|
1217
1110
|
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
@@ -1244,7 +1137,11 @@ export async function runAgentLoopImpl(
|
|
|
1244
1137
|
{ err, phase: "start-of-turn-compaction" },
|
|
1245
1138
|
"Compaction pipeline timed out — skipping compaction this turn",
|
|
1246
1139
|
);
|
|
1247
|
-
await
|
|
1140
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1141
|
+
ctx,
|
|
1142
|
+
true,
|
|
1143
|
+
onEvent,
|
|
1144
|
+
);
|
|
1248
1145
|
compacted = null;
|
|
1249
1146
|
} else {
|
|
1250
1147
|
throw err;
|
|
@@ -1257,7 +1154,11 @@ export async function runAgentLoopImpl(
|
|
|
1257
1154
|
// path) — treating those as "successful" compactions would silently reset
|
|
1258
1155
|
// the 3-strike counter and break the invariant.
|
|
1259
1156
|
if (compacted && compacted.summaryFailed !== undefined) {
|
|
1260
|
-
await
|
|
1157
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1158
|
+
ctx,
|
|
1159
|
+
compacted.summaryFailed,
|
|
1160
|
+
onEvent,
|
|
1161
|
+
);
|
|
1261
1162
|
}
|
|
1262
1163
|
if (compacted?.compacted) {
|
|
1263
1164
|
await applySuccessfulCompaction(
|
|
@@ -1272,12 +1173,7 @@ export async function runAgentLoopImpl(
|
|
|
1272
1173
|
|
|
1273
1174
|
// Register confirmation outcome tracker so the agent loop can link
|
|
1274
1175
|
// confirmation decisions to tool_use_ids for persistence.
|
|
1275
|
-
ctx.onConfirmationOutcome = (
|
|
1276
|
-
requestId,
|
|
1277
|
-
confirmationState,
|
|
1278
|
-
toolName,
|
|
1279
|
-
toolUseId,
|
|
1280
|
-
) => {
|
|
1176
|
+
ctx.onConfirmationOutcome = (requestId, confirmationState, toolUseId) => {
|
|
1281
1177
|
if (confirmationState === "pending") {
|
|
1282
1178
|
// Use the toolUseId passed from the prompter (which knows which tool
|
|
1283
1179
|
// requested confirmation) instead of the ambient state.currentToolUseId,
|
|
@@ -1294,7 +1190,7 @@ export async function runAgentLoopImpl(
|
|
|
1294
1190
|
const resolvedId =
|
|
1295
1191
|
state.requestIdToToolUseId.get(requestId) ?? toolUseId;
|
|
1296
1192
|
if (resolvedId) {
|
|
1297
|
-
const name = state.toolUseIdToName.get(resolvedId) ??
|
|
1193
|
+
const name = state.toolUseIdToName.get(resolvedId) ?? "";
|
|
1298
1194
|
// Build a friendly label from the tool name
|
|
1299
1195
|
const label =
|
|
1300
1196
|
TOOL_FRIENDLY_LABEL[name] ??
|
|
@@ -1737,8 +1633,21 @@ export async function runAgentLoopImpl(
|
|
|
1737
1633
|
// to the reduced `ctx.messages`.
|
|
1738
1634
|
let reducerCompacted = compactedThisTurn;
|
|
1739
1635
|
|
|
1636
|
+
// memory-v3-live: route the turn's `<memory>` block to the v3 injector.
|
|
1637
|
+
// When on, runtime assembly suppresses v2's `<memory>` injection (only
|
|
1638
|
+
// when the v3 injector actually produced a block — otherwise v2 stays as a
|
|
1639
|
+
// fallback) and the provider anchors its long-TTL cache breakpoint on the
|
|
1640
|
+
// most recent STABLE user message, since the latest user message now
|
|
1641
|
+
// carries the volatile per-turn memory block. Flag off → bit-for-bit
|
|
1642
|
+
// identical to today's v2 path.
|
|
1643
|
+
const memoryV3Live = isAssistantFeatureFlagEnabled(
|
|
1644
|
+
"memory-v3-live",
|
|
1645
|
+
getConfig(),
|
|
1646
|
+
);
|
|
1647
|
+
|
|
1740
1648
|
// Shared injection options — reused whenever we need to re-inject after reduction.
|
|
1741
1649
|
const injectionOpts = {
|
|
1650
|
+
suppressV2MemoryForV3: memoryV3Live,
|
|
1742
1651
|
diskPressureContext,
|
|
1743
1652
|
activeSurface,
|
|
1744
1653
|
activeDocuments,
|
|
@@ -1960,6 +1869,7 @@ export async function runAgentLoopImpl(
|
|
|
1960
1869
|
options: {
|
|
1961
1870
|
...(opts ?? {}),
|
|
1962
1871
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1872
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
1963
1873
|
},
|
|
1964
1874
|
},
|
|
1965
1875
|
buildPluginTurnContext(ctx, reqId),
|
|
@@ -1973,7 +1883,11 @@ export async function runAgentLoopImpl(
|
|
|
1973
1883
|
{ err, phase: "overflow-reducer-forced-compaction" },
|
|
1974
1884
|
"Compaction pipeline timed out — falling through to next reducer tier",
|
|
1975
1885
|
);
|
|
1976
|
-
await
|
|
1886
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1887
|
+
ctx,
|
|
1888
|
+
true,
|
|
1889
|
+
onEvent,
|
|
1890
|
+
);
|
|
1977
1891
|
return {
|
|
1978
1892
|
messages: msgs,
|
|
1979
1893
|
compacted: false,
|
|
@@ -1995,12 +1909,9 @@ export async function runAgentLoopImpl(
|
|
|
1995
1909
|
}
|
|
1996
1910
|
},
|
|
1997
1911
|
emitActivityState: () => {
|
|
1998
|
-
ctx.emitActivityState(
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
"assistant_turn",
|
|
2002
|
-
reqId,
|
|
2003
|
-
);
|
|
1912
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
1913
|
+
requestId: reqId,
|
|
1914
|
+
});
|
|
2004
1915
|
},
|
|
2005
1916
|
onCompactionResult: async (result, compactedBasis) => {
|
|
2006
1917
|
// Track circuit-breaker state whenever the reducer invoked
|
|
@@ -2013,7 +1924,11 @@ export async function runAgentLoopImpl(
|
|
|
2013
1924
|
// truncation-only path, etc.) that shouldn't influence the
|
|
2014
1925
|
// breaker.
|
|
2015
1926
|
if (result.summaryFailed !== undefined) {
|
|
2016
|
-
await
|
|
1927
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1928
|
+
ctx,
|
|
1929
|
+
result.summaryFailed,
|
|
1930
|
+
onEvent,
|
|
1931
|
+
);
|
|
2017
1932
|
}
|
|
2018
1933
|
if (result.compacted) {
|
|
2019
1934
|
await applySuccessfulCompaction(result, compactedBasis);
|
|
@@ -2107,55 +2022,7 @@ export async function runAgentLoopImpl(
|
|
|
2107
2022
|
}
|
|
2108
2023
|
}
|
|
2109
2024
|
|
|
2110
|
-
// Pre-run repair — routed through the `historyRepair` plugin pipeline so
|
|
2111
|
-
// plugins can observe or override repair behavior. The default plugin's
|
|
2112
|
-
// middleware is a passthrough; the actual repair runs in the terminal
|
|
2113
|
-
// (`defaultHistoryRepairTerminal`).
|
|
2114
2025
|
let preRepairMessages = runMessages;
|
|
2115
|
-
let preRunRepair: HistoryRepairResult | null = null;
|
|
2116
|
-
try {
|
|
2117
|
-
preRunRepair = await runPipeline<HistoryRepairArgs, HistoryRepairResult>(
|
|
2118
|
-
"historyRepair",
|
|
2119
|
-
getMiddlewaresFor("historyRepair"),
|
|
2120
|
-
async (args) => defaultHistoryRepairTerminal(args),
|
|
2121
|
-
{ history: runMessages, provider: ctx.provider.name },
|
|
2122
|
-
buildPluginTurnContext(ctx, reqId),
|
|
2123
|
-
DEFAULT_TIMEOUTS.historyRepair,
|
|
2124
|
-
);
|
|
2125
|
-
} catch (err) {
|
|
2126
|
-
if (err instanceof PluginTimeoutError) {
|
|
2127
|
-
// Pipeline exceeded its budget — likely a misbehaving third-party
|
|
2128
|
-
// middleware. Degrade gracefully by proceeding with the un-repaired
|
|
2129
|
-
// history rather than turn-fatal-erroring; un-repaired history is
|
|
2130
|
-
// strictly better than no turn at all, and the provider call itself
|
|
2131
|
-
// will still error visibly if the drift is unrecoverable.
|
|
2132
|
-
rlog.warn(
|
|
2133
|
-
{ err, phase: "pre_run" },
|
|
2134
|
-
"historyRepair pipeline timed out — proceeding with un-repaired history",
|
|
2135
|
-
);
|
|
2136
|
-
} else {
|
|
2137
|
-
throw err;
|
|
2138
|
-
}
|
|
2139
|
-
}
|
|
2140
|
-
if (preRunRepair !== null) {
|
|
2141
|
-
// Always adopt the pipeline's output history — a user `historyRepair`
|
|
2142
|
-
// middleware may rewrite `messages` (e.g. provider-specific
|
|
2143
|
-
// normalization) without incrementing any of the built-in repair
|
|
2144
|
-
// counters. Gating the assignment on `stats` would silently discard
|
|
2145
|
-
// those edits and send the un-rewritten history to the provider.
|
|
2146
|
-
runMessages = preRunRepair.messages;
|
|
2147
|
-
if (
|
|
2148
|
-
preRunRepair.stats.assistantToolResultsMigrated > 0 ||
|
|
2149
|
-
preRunRepair.stats.missingToolResultsInserted > 0 ||
|
|
2150
|
-
preRunRepair.stats.orphanToolResultsDowngraded > 0 ||
|
|
2151
|
-
preRunRepair.stats.consecutiveSameRoleMerged > 0
|
|
2152
|
-
) {
|
|
2153
|
-
rlog.warn(
|
|
2154
|
-
{ phase: "pre_run", ...preRunRepair.stats },
|
|
2155
|
-
"Repaired runtime history before provider call",
|
|
2156
|
-
);
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
2026
|
|
|
2160
2027
|
// Replace historical web_search_tool_result blocks with text summaries.
|
|
2161
2028
|
// The opaque `encrypted_content` tokens Anthropic attaches to each result
|
|
@@ -2172,12 +2039,12 @@ export async function runAgentLoopImpl(
|
|
|
2172
2039
|
}
|
|
2173
2040
|
|
|
2174
2041
|
// user-prompt-submit hook: plugins may transform `runMessages` right
|
|
2175
|
-
// before the agent loop receives them. Fires once per user turn at
|
|
2176
|
-
//
|
|
2177
|
-
//
|
|
2178
|
-
//
|
|
2179
|
-
//
|
|
2180
|
-
//
|
|
2042
|
+
// before the agent loop receives them. Fires once per user turn at the
|
|
2043
|
+
// primary `agentLoop.run` only — the re-entry / retry calls further down
|
|
2044
|
+
// in this function do not refire it (they're not new user submissions).
|
|
2045
|
+
// Plugins may mutate `ctx.latestMessages` in place OR return a new
|
|
2046
|
+
// context with a fresh array; `runHook` forwards whichever the chain
|
|
2047
|
+
// settles on. Order is plugin registration order.
|
|
2181
2048
|
//
|
|
2182
2049
|
// Fires BEFORE `preRunHistoryLength` is captured so the boundary
|
|
2183
2050
|
// between pre-existing and hook-emitted messages — consumed by the
|
|
@@ -2188,6 +2055,7 @@ export async function runAgentLoopImpl(
|
|
|
2188
2055
|
conversationId: ctx.conversationId,
|
|
2189
2056
|
originalMessages: ctx.messages,
|
|
2190
2057
|
latestMessages: runMessages,
|
|
2058
|
+
logger: rlog,
|
|
2191
2059
|
};
|
|
2192
2060
|
const finalUserPromptCtx = await runHook(
|
|
2193
2061
|
HOOKS.USER_PROMPT_SUBMIT,
|
|
@@ -2211,41 +2079,16 @@ export async function runAgentLoopImpl(
|
|
|
2211
2079
|
turnChannelContext: capturedTurnChannelContext,
|
|
2212
2080
|
turnInterfaceContext: capturedTurnInterfaceContext,
|
|
2213
2081
|
};
|
|
2214
|
-
const eventHandler = (event: AgentEvent) =>
|
|
2082
|
+
const eventHandler = (event: AgentEvent): Promise<void> =>
|
|
2215
2083
|
dispatchAgentEvent(state, deps, event);
|
|
2216
2084
|
emitTerminalExit = async (reason: AgentLoopExitReason): Promise<void> => {
|
|
2217
2085
|
await eventHandler({ type: "agent_loop_exit", reason });
|
|
2218
2086
|
};
|
|
2219
2087
|
|
|
2220
|
-
const onCheckpoint = async (
|
|
2221
|
-
checkpoint: CheckpointInfo,
|
|
2222
|
-
): Promise<CheckpointDecision> => {
|
|
2223
|
-
state.currentTurnToolNames = [];
|
|
2224
|
-
|
|
2088
|
+
const onCheckpoint = async (): Promise<CheckpointDecision> => {
|
|
2225
2089
|
if (ctx.canHandoffAtCheckpoint()) {
|
|
2226
|
-
|
|
2227
|
-
pendingCheckpointYield = "handoff";
|
|
2228
|
-
return "yield";
|
|
2090
|
+
return "handoff";
|
|
2229
2091
|
}
|
|
2230
|
-
|
|
2231
|
-
// Mid-loop token budget check: estimate current context size and
|
|
2232
|
-
// yield if we're approaching the preflight budget. This lets the
|
|
2233
|
-
// conversation-agent-loop run compaction before the provider rejects.
|
|
2234
|
-
if (overflowRecovery.enabled) {
|
|
2235
|
-
const midLoopThreshold =
|
|
2236
|
-
resolveCurrentContextBudget().preflightBudget * 0.85;
|
|
2237
|
-
const estimated = await runTokenEstimatePipeline(checkpoint.history);
|
|
2238
|
-
if (estimated > midLoopThreshold) {
|
|
2239
|
-
rlog.warn(
|
|
2240
|
-
{ phase: "mid-loop", estimated, threshold: midLoopThreshold },
|
|
2241
|
-
"Token estimate approaching budget — yielding for compaction",
|
|
2242
|
-
);
|
|
2243
|
-
yieldedForBudget = true;
|
|
2244
|
-
pendingCheckpointYield = "budget";
|
|
2245
|
-
return "yield";
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
|
|
2249
2092
|
return "continue";
|
|
2250
2093
|
};
|
|
2251
2094
|
|
|
@@ -2261,19 +2104,120 @@ export async function runAgentLoopImpl(
|
|
|
2261
2104
|
// and overwrites `turnIndex` with its own tool-use iteration counter.
|
|
2262
2105
|
const loopTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
2263
2106
|
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2107
|
+
// Hooks for the loop-owned mid-loop compaction. The agent loop owns the
|
|
2108
|
+
// trigger (its budget gate), the `compaction` pipeline call, the result
|
|
2109
|
+
// interpretation (circuit-breaker bookkeeping + the exhaustion decision),
|
|
2110
|
+
// and the inline continue; these callbacks bridge the durable / injection
|
|
2111
|
+
// state the loop is intentionally blind to. Durable persistence and
|
|
2112
|
+
// re-injection stay orchestrator-supplied for now.
|
|
2113
|
+
const midLoopCompaction: MidLoopCompaction = {
|
|
2114
|
+
prepare: (history) => {
|
|
2115
|
+
// Strip injected context so the compactor summarizes the raw
|
|
2116
|
+
// persistent messages, and commit the stripped set to durable state.
|
|
2117
|
+
const rawHistory = stripInjectionsForCompaction(history);
|
|
2118
|
+
ctx.messages = rawHistory;
|
|
2119
|
+
markHistoryStrippedBestEffort(ctx.conversationId, Date.now(), rlog);
|
|
2120
|
+
return {
|
|
2121
|
+
rawHistory,
|
|
2122
|
+
options: {
|
|
2123
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
2124
|
+
force: true,
|
|
2125
|
+
targetInputTokensOverride:
|
|
2126
|
+
resolveCurrentContextBudget().preflightBudget,
|
|
2127
|
+
conversationOriginChannel:
|
|
2128
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
2129
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2130
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
2131
|
+
},
|
|
2132
|
+
};
|
|
2133
|
+
},
|
|
2134
|
+
applyResult: async (result, rawHistory) => {
|
|
2135
|
+
await applySuccessfulCompaction(result, rawHistory);
|
|
2136
|
+
reducerCompacted = true;
|
|
2137
|
+
shouldInjectWorkspace = true;
|
|
2138
|
+
},
|
|
2139
|
+
reinject: async () => {
|
|
2140
|
+
// stripInjectionsForCompaction() unconditionally removed the existing
|
|
2141
|
+
// NOW.md block, so re-inject the current content regardless of whether
|
|
2142
|
+
// compaction actually ran.
|
|
2143
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
2144
|
+
...injectionOpts,
|
|
2145
|
+
pkbContext: currentPkbContent,
|
|
2146
|
+
memoryV2Static: currentMemoryV2Static,
|
|
2147
|
+
nowScratchpad: currentNowContent,
|
|
2148
|
+
workspaceTopLevelContext: shouldInjectWorkspace
|
|
2149
|
+
? ctx.workspaceTopLevelContext
|
|
2150
|
+
: null,
|
|
2151
|
+
// Suppress the chronological-transcript snapshot once the reducer
|
|
2152
|
+
// has collapsed `ctx.messages`; the captured snapshot reflects the
|
|
2153
|
+
// full persisted transcript and would overwrite compaction.
|
|
2154
|
+
slackChronologicalMessages: reducerCompacted
|
|
2155
|
+
? null
|
|
2156
|
+
: injectionOpts.slackChronologicalMessages,
|
|
2157
|
+
mode: currentInjectionMode,
|
|
2158
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
2159
|
+
});
|
|
2160
|
+
runMessages = injection.messages;
|
|
2161
|
+
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
2162
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
2163
|
+
}
|
|
2164
|
+
const midLoopCompactStrip =
|
|
2165
|
+
stripHistoricalWebSearchResults(runMessages);
|
|
2166
|
+
if (midLoopCompactStrip.stats.blocksStripped > 0) {
|
|
2167
|
+
rlog.info(
|
|
2168
|
+
{ phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
|
|
2169
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
2170
|
+
);
|
|
2171
|
+
runMessages = midLoopCompactStrip.messages;
|
|
2172
|
+
}
|
|
2173
|
+
preRepairMessages = runMessages;
|
|
2174
|
+
preRunHistoryLength = runMessages.length;
|
|
2175
|
+
return runMessages;
|
|
2176
|
+
},
|
|
2177
|
+
};
|
|
2178
|
+
|
|
2179
|
+
/**
|
|
2180
|
+
* Shared closure: runs the agent loop with the orchestrator's turn
|
|
2181
|
+
* context and maps the loop's returned checkpoint pause-reason into the
|
|
2182
|
+
* orchestrator's yield bookkeeping. Returns the updated history so call
|
|
2183
|
+
* sites consume it exactly as before. Pass `compaction` only for the
|
|
2184
|
+
* primary run, where the loop compacts in place when its budget gate
|
|
2185
|
+
* trips; reruns omit it and keep yielding for budget.
|
|
2186
|
+
*/
|
|
2187
|
+
const runAgentLoop = async (
|
|
2188
|
+
msgs: Message[],
|
|
2189
|
+
compaction?: MidLoopCompaction,
|
|
2190
|
+
): Promise<Message[]> => {
|
|
2191
|
+
const { history, exitReason } = await ctx.agentLoop.run(
|
|
2192
|
+
msgs,
|
|
2193
|
+
eventHandler,
|
|
2194
|
+
{
|
|
2195
|
+
signal: abortController.signal,
|
|
2196
|
+
requestId: reqId,
|
|
2197
|
+
onCheckpoint,
|
|
2198
|
+
callSite: turnCallSite,
|
|
2199
|
+
turnContext: loopTurnCtx,
|
|
2200
|
+
overrideProfile: turnOverrideProfile,
|
|
2201
|
+
resolveOverrideProfile: resolveCurrentOverrideProfile,
|
|
2202
|
+
resolveContextWindow,
|
|
2203
|
+
compaction,
|
|
2204
|
+
// memory-v3-live: the latest user message carries the volatile v3
|
|
2205
|
+
// `<memory>` block, so anchor the provider's long-TTL cache breakpoint
|
|
2206
|
+
// on the most recent stable message instead.
|
|
2207
|
+
mutableLatestUserMessage: memoryV3Live,
|
|
2208
|
+
},
|
|
2209
|
+
);
|
|
2210
|
+
if (exitReason === "handoff") {
|
|
2211
|
+
yieldedForHandoff = true;
|
|
2212
|
+
pendingCheckpointYield = "handoff";
|
|
2213
|
+
} else if (exitReason === "budget") {
|
|
2214
|
+
yieldedForBudget = true;
|
|
2215
|
+
pendingCheckpointYield = "budget";
|
|
2216
|
+
}
|
|
2217
|
+
return history;
|
|
2218
|
+
};
|
|
2219
|
+
|
|
2220
|
+
let updatedHistory = await runAgentLoop(runMessages, midLoopCompaction);
|
|
2277
2221
|
|
|
2278
2222
|
rlog.info(
|
|
2279
2223
|
{ resultMessageCount: updatedHistory.length },
|
|
@@ -2285,167 +2229,16 @@ export async function runAgentLoopImpl(
|
|
|
2285
2229
|
pendingCheckpointYield = null;
|
|
2286
2230
|
}
|
|
2287
2231
|
|
|
2288
|
-
//
|
|
2289
|
-
//
|
|
2290
|
-
//
|
|
2291
|
-
//
|
|
2292
|
-
//
|
|
2293
|
-
//
|
|
2294
|
-
let midLoopCompactAttempts = 0;
|
|
2295
|
-
while (
|
|
2296
|
-
yieldedForBudget &&
|
|
2297
|
-
midLoopCompactAttempts <
|
|
2298
|
-
resolveCurrentContextBudget().overflowRecovery.maxAttempts &&
|
|
2299
|
-
!state.contextTooLargeDetected &&
|
|
2300
|
-
!abortController.signal.aborted
|
|
2301
|
-
) {
|
|
2302
|
-
midLoopCompactAttempts++;
|
|
2303
|
-
yieldedForBudget = false;
|
|
2304
|
-
pendingCheckpointYield = null;
|
|
2305
|
-
|
|
2306
|
-
rlog.info(
|
|
2307
|
-
{ phase: "mid-loop-compact" },
|
|
2308
|
-
"Running compaction after checkpoint yield",
|
|
2309
|
-
);
|
|
2310
|
-
|
|
2311
|
-
// Strip injected context from updated history before compacting,
|
|
2312
|
-
// so we compact the "raw" persistent messages.
|
|
2313
|
-
const rawHistory = stripInjectionsForCompaction(updatedHistory);
|
|
2314
|
-
ctx.messages = rawHistory;
|
|
2315
|
-
setConversationHistoryStrippedAt(ctx.conversationId, Date.now());
|
|
2316
|
-
|
|
2317
|
-
ctx.emitActivityState(
|
|
2318
|
-
"thinking",
|
|
2319
|
-
"context_compacting",
|
|
2320
|
-
"assistant_turn",
|
|
2321
|
-
reqId,
|
|
2322
|
-
"Compacting context",
|
|
2323
|
-
);
|
|
2324
|
-
let midLoopCompact: Awaited<
|
|
2325
|
-
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2326
|
-
>;
|
|
2327
|
-
try {
|
|
2328
|
-
midLoopCompact = (await runPipeline<CompactionArgs, CompactionResult>(
|
|
2329
|
-
"compaction",
|
|
2330
|
-
getMiddlewaresFor("compaction"),
|
|
2331
|
-
(args) =>
|
|
2332
|
-
defaultCompactionTerminal(args, buildPluginTurnContext(ctx, reqId)),
|
|
2333
|
-
{
|
|
2334
|
-
messages: ctx.messages,
|
|
2335
|
-
signal: abortController.signal,
|
|
2336
|
-
options: {
|
|
2337
|
-
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
2338
|
-
force: true,
|
|
2339
|
-
targetInputTokensOverride:
|
|
2340
|
-
resolveCurrentContextBudget().preflightBudget,
|
|
2341
|
-
conversationOriginChannel:
|
|
2342
|
-
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
2343
|
-
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2344
|
-
},
|
|
2345
|
-
},
|
|
2346
|
-
buildPluginTurnContext(ctx, reqId),
|
|
2347
|
-
DEFAULT_TIMEOUTS.compaction,
|
|
2348
|
-
)) as Awaited<ReturnType<typeof ctx.contextWindowManager.maybeCompact>>;
|
|
2349
|
-
} catch (err) {
|
|
2350
|
-
if (err instanceof PluginTimeoutError) {
|
|
2351
|
-
// Mid-loop compaction timed out. Record the failure for the
|
|
2352
|
-
// circuit breaker and escalate to the convergence loop's more
|
|
2353
|
-
// aggressive reducer tiers (tool-result truncation, media
|
|
2354
|
-
// stubbing, injection downgrade) by flipping the overflow flag
|
|
2355
|
-
// and breaking out of the mid-loop retry. The existing
|
|
2356
|
-
// "exhausted all attempts" block further down handles the
|
|
2357
|
-
// escalation.
|
|
2358
|
-
rlog.warn(
|
|
2359
|
-
{ err, phase: "mid-loop-compact" },
|
|
2360
|
-
"Compaction pipeline timed out — escalating to convergence loop",
|
|
2361
|
-
);
|
|
2362
|
-
await trackCompactionOutcome(ctx, true, onEvent);
|
|
2363
|
-
state.contextTooLargeDetected = true;
|
|
2364
|
-
break;
|
|
2365
|
-
}
|
|
2366
|
-
throw err;
|
|
2367
|
-
}
|
|
2368
|
-
// `force: true` bypasses the cooldown/threshold gates but early returns
|
|
2369
|
-
// for "no eligible messages" / "insufficient messages" still leave
|
|
2370
|
-
// `summaryFailed` undefined. Only track when the summary LLM actually ran.
|
|
2371
|
-
if (midLoopCompact.summaryFailed !== undefined) {
|
|
2372
|
-
await trackCompactionOutcome(
|
|
2373
|
-
ctx,
|
|
2374
|
-
midLoopCompact.summaryFailed,
|
|
2375
|
-
onEvent,
|
|
2376
|
-
);
|
|
2377
|
-
}
|
|
2378
|
-
if (midLoopCompact.compacted) {
|
|
2379
|
-
await applySuccessfulCompaction(midLoopCompact, rawHistory);
|
|
2380
|
-
reducerCompacted = true;
|
|
2381
|
-
shouldInjectWorkspace = true;
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
|
-
// Re-inject runtime context and re-enter the agent loop.
|
|
2385
|
-
// stripInjectionsForCompaction() unconditionally removed the existing
|
|
2386
|
-
// NOW.md block from ctx.messages above, so we must always re-inject
|
|
2387
|
-
// the current content regardless of whether compaction actually ran.
|
|
2388
|
-
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
2389
|
-
...injectionOpts,
|
|
2390
|
-
pkbContext: currentPkbContent,
|
|
2391
|
-
memoryV2Static: currentMemoryV2Static,
|
|
2392
|
-
nowScratchpad: currentNowContent,
|
|
2393
|
-
workspaceTopLevelContext: shouldInjectWorkspace
|
|
2394
|
-
? ctx.workspaceTopLevelContext
|
|
2395
|
-
: null,
|
|
2396
|
-
// Suppress the chronological-transcript snapshot once the reducer
|
|
2397
|
-
// has collapsed `ctx.messages`; the captured snapshot reflects the
|
|
2398
|
-
// full persisted transcript and would overwrite compaction.
|
|
2399
|
-
slackChronologicalMessages: reducerCompacted
|
|
2400
|
-
? null
|
|
2401
|
-
: injectionOpts.slackChronologicalMessages,
|
|
2402
|
-
mode: currentInjectionMode,
|
|
2403
|
-
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
2404
|
-
});
|
|
2405
|
-
runMessages = injection.messages;
|
|
2406
|
-
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
2407
|
-
ctx.graphMemory.retrackCachedNodes();
|
|
2408
|
-
}
|
|
2409
|
-
const midLoopCompactStrip = stripHistoricalWebSearchResults(runMessages);
|
|
2410
|
-
if (midLoopCompactStrip.stats.blocksStripped > 0) {
|
|
2411
|
-
rlog.info(
|
|
2412
|
-
{ phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
|
|
2413
|
-
"Converted historical web_search_tool_result blocks to text summaries",
|
|
2414
|
-
);
|
|
2415
|
-
runMessages = midLoopCompactStrip.messages;
|
|
2416
|
-
}
|
|
2417
|
-
preRepairMessages = runMessages;
|
|
2418
|
-
preRunHistoryLength = runMessages.length;
|
|
2419
|
-
|
|
2420
|
-
updatedHistory = await ctx.agentLoop.run(
|
|
2421
|
-
runMessages,
|
|
2422
|
-
eventHandler,
|
|
2423
|
-
abortController.signal,
|
|
2424
|
-
reqId,
|
|
2425
|
-
onCheckpoint,
|
|
2426
|
-
turnCallSite,
|
|
2427
|
-
loopTurnCtx,
|
|
2428
|
-
turnOverrideProfile,
|
|
2429
|
-
resolveCurrentMaxInputTokens(),
|
|
2430
|
-
resolveCurrentOverrideProfile,
|
|
2431
|
-
resolveCurrentMaxInputTokens,
|
|
2432
|
-
);
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
|
-
// If mid-loop compaction exhausted all attempts but the agent loop
|
|
2436
|
-
// still yielded (yieldedForBudget is true), the turn is incomplete.
|
|
2437
|
-
// Escalate to the convergence loop's more aggressive reducer tiers
|
|
2438
|
-
// (tool-result truncation, media stubbing, injection downgrade)
|
|
2439
|
-
// instead of silently treating an incomplete turn as done.
|
|
2232
|
+
// The loop compacts in place when its budget gate trips and only yields
|
|
2233
|
+
// `exitReason = "budget"` when that inline compaction timed out or
|
|
2234
|
+
// exhausted its retry budget (the `reinject` hook has already restored
|
|
2235
|
+
// runtime context for the productive case). Escalate to the convergence
|
|
2236
|
+
// loop's more aggressive reducer tiers so a half-finished turn doesn't
|
|
2237
|
+
// reach the user.
|
|
2440
2238
|
if (yieldedForBudget && !abortController.signal.aborted) {
|
|
2441
2239
|
rlog.warn(
|
|
2442
|
-
{
|
|
2443
|
-
|
|
2444
|
-
midLoopCompactAttempts,
|
|
2445
|
-
maxAttempts:
|
|
2446
|
-
resolveCurrentContextBudget().overflowRecovery.maxAttempts,
|
|
2447
|
-
},
|
|
2448
|
-
"Mid-loop compaction exhausted all attempts — escalating to convergence loop",
|
|
2240
|
+
{ phase: "mid-loop-compact" },
|
|
2241
|
+
"Inline compaction could not get under budget — escalating to convergence loop",
|
|
2449
2242
|
);
|
|
2450
2243
|
state.contextTooLargeDetected = true;
|
|
2451
2244
|
}
|
|
@@ -2459,15 +2252,15 @@ export async function runAgentLoopImpl(
|
|
|
2459
2252
|
{ phase: "retry" },
|
|
2460
2253
|
"Provider ordering error detected, attempting one-shot deep-repair retry",
|
|
2461
2254
|
);
|
|
2462
|
-
// Design note: deep-repair intentionally
|
|
2463
|
-
//
|
|
2464
|
-
//
|
|
2465
|
-
//
|
|
2466
|
-
// the original drift. Plugins can
|
|
2467
|
-
// pre-run repair via the
|
|
2468
|
-
//
|
|
2469
|
-
//
|
|
2470
|
-
//
|
|
2255
|
+
// Design note: deep-repair intentionally stays a direct call rather
|
|
2256
|
+
// than running through the `user-prompt-submit` hook chain. Deep-repair
|
|
2257
|
+
// is a recovery-only path triggered by a provider ordering error — it
|
|
2258
|
+
// must be deterministic and unaffected by user hooks that might have
|
|
2259
|
+
// caused (or be unable to recover from) the original drift. Plugins can
|
|
2260
|
+
// already observe / transform the pre-run repair via the
|
|
2261
|
+
// `user-prompt-submit` hook (the default history-repair plugin runs
|
|
2262
|
+
// `repairHistory` there); widening that surface to deep-repair is
|
|
2263
|
+
// intentionally deferred until there's a concrete plugin-level use case.
|
|
2471
2264
|
const retryRepair = deepRepairHistory(runMessages);
|
|
2472
2265
|
runMessages = retryRepair.messages;
|
|
2473
2266
|
const retryStrip = stripHistoricalWebSearchResults(runMessages);
|
|
@@ -2477,19 +2270,7 @@ export async function runAgentLoopImpl(
|
|
|
2477
2270
|
state.orderingErrorDetected = false;
|
|
2478
2271
|
state.deferredOrderingError = null;
|
|
2479
2272
|
|
|
2480
|
-
updatedHistory = await
|
|
2481
|
-
runMessages,
|
|
2482
|
-
eventHandler,
|
|
2483
|
-
abortController.signal,
|
|
2484
|
-
reqId,
|
|
2485
|
-
onCheckpoint,
|
|
2486
|
-
turnCallSite,
|
|
2487
|
-
loopTurnCtx,
|
|
2488
|
-
turnOverrideProfile,
|
|
2489
|
-
resolveCurrentMaxInputTokens(),
|
|
2490
|
-
resolveCurrentOverrideProfile,
|
|
2491
|
-
resolveCurrentMaxInputTokens,
|
|
2492
|
-
);
|
|
2273
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2493
2274
|
|
|
2494
2275
|
if (state.orderingErrorDetected) {
|
|
2495
2276
|
rlog.error(
|
|
@@ -2548,19 +2329,7 @@ export async function runAgentLoopImpl(
|
|
|
2548
2329
|
};
|
|
2549
2330
|
});
|
|
2550
2331
|
runMessages = ctx.messages;
|
|
2551
|
-
updatedHistory = await
|
|
2552
|
-
runMessages,
|
|
2553
|
-
eventHandler,
|
|
2554
|
-
abortController.signal,
|
|
2555
|
-
reqId,
|
|
2556
|
-
onCheckpoint,
|
|
2557
|
-
turnCallSite,
|
|
2558
|
-
loopTurnCtx,
|
|
2559
|
-
turnOverrideProfile,
|
|
2560
|
-
resolveCurrentMaxInputTokens(),
|
|
2561
|
-
resolveCurrentOverrideProfile,
|
|
2562
|
-
resolveCurrentMaxInputTokens,
|
|
2563
|
-
);
|
|
2332
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2564
2333
|
if (state.imageTooLargeDetected) {
|
|
2565
2334
|
rlog.error(
|
|
2566
2335
|
{ phase: "image-recovery" },
|
|
@@ -2596,7 +2365,7 @@ export async function runAgentLoopImpl(
|
|
|
2596
2365
|
|
|
2597
2366
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
2598
2367
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
2599
|
-
|
|
2368
|
+
markHistoryStrippedBestEffort(ctx.conversationId, Date.now(), rlog);
|
|
2600
2369
|
convergenceStripped = true;
|
|
2601
2370
|
preRepairMessages = updatedHistory;
|
|
2602
2371
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -2680,7 +2449,7 @@ export async function runAgentLoopImpl(
|
|
|
2680
2449
|
"Emergency mid-turn compaction succeeded — bypassing reducer tiers",
|
|
2681
2450
|
);
|
|
2682
2451
|
if (emergencyResult.summaryFailed !== undefined) {
|
|
2683
|
-
await
|
|
2452
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2684
2453
|
ctx,
|
|
2685
2454
|
emergencyResult.summaryFailed,
|
|
2686
2455
|
onEvent,
|
|
@@ -2721,12 +2490,9 @@ export async function runAgentLoopImpl(
|
|
|
2721
2490
|
"Context too large — applying next reducer tier",
|
|
2722
2491
|
);
|
|
2723
2492
|
|
|
2724
|
-
ctx.emitActivityState(
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
"assistant_turn",
|
|
2728
|
-
reqId,
|
|
2729
|
-
);
|
|
2493
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
2494
|
+
requestId: reqId,
|
|
2495
|
+
});
|
|
2730
2496
|
const convergenceCompactionBasis = ctx.messages;
|
|
2731
2497
|
const step = await reduceContextOverflow(
|
|
2732
2498
|
convergenceCompactionBasis,
|
|
@@ -2742,6 +2508,7 @@ export async function runAgentLoopImpl(
|
|
|
2742
2508
|
ctx.contextWindowManager.maybeCompact(msgs, signal!, {
|
|
2743
2509
|
...(opts ?? {}),
|
|
2744
2510
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2511
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
2745
2512
|
}),
|
|
2746
2513
|
abortController.signal,
|
|
2747
2514
|
);
|
|
@@ -2758,7 +2525,7 @@ export async function runAgentLoopImpl(
|
|
|
2758
2525
|
step.compactionResult &&
|
|
2759
2526
|
step.compactionResult.summaryFailed !== undefined
|
|
2760
2527
|
) {
|
|
2761
|
-
await
|
|
2528
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2762
2529
|
ctx,
|
|
2763
2530
|
step.compactionResult.summaryFailed,
|
|
2764
2531
|
onEvent,
|
|
@@ -2808,19 +2575,7 @@ export async function runAgentLoopImpl(
|
|
|
2808
2575
|
state.contextTooLargeDetected = false;
|
|
2809
2576
|
yieldedForBudget = false;
|
|
2810
2577
|
|
|
2811
|
-
updatedHistory = await
|
|
2812
|
-
runMessages,
|
|
2813
|
-
eventHandler,
|
|
2814
|
-
abortController.signal,
|
|
2815
|
-
reqId,
|
|
2816
|
-
onCheckpoint,
|
|
2817
|
-
turnCallSite,
|
|
2818
|
-
loopTurnCtx,
|
|
2819
|
-
turnOverrideProfile,
|
|
2820
|
-
resolveCurrentMaxInputTokens(),
|
|
2821
|
-
resolveCurrentOverrideProfile,
|
|
2822
|
-
resolveCurrentMaxInputTokens,
|
|
2823
|
-
);
|
|
2578
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2824
2579
|
|
|
2825
2580
|
// If the rerun still yields at checkpoint, the turn is still
|
|
2826
2581
|
// incomplete — continue reducing through the remaining tiers
|
|
@@ -2841,7 +2596,7 @@ export async function runAgentLoopImpl(
|
|
|
2841
2596
|
// pre-rerun messages.
|
|
2842
2597
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
2843
2598
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
2844
|
-
|
|
2599
|
+
markHistoryStrippedBestEffort(ctx.conversationId, Date.now(), rlog);
|
|
2845
2600
|
convergenceStripped = true;
|
|
2846
2601
|
preRepairMessages = updatedHistory;
|
|
2847
2602
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -2861,12 +2616,9 @@ export async function runAgentLoopImpl(
|
|
|
2861
2616
|
|
|
2862
2617
|
if (action === "auto_compress_latest_turn") {
|
|
2863
2618
|
// Auto-compress without asking — users opt out via the "drop" policy.
|
|
2864
|
-
ctx.emitActivityState(
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
"assistant_turn",
|
|
2868
|
-
reqId,
|
|
2869
|
-
);
|
|
2619
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
2620
|
+
requestId: reqId,
|
|
2621
|
+
});
|
|
2870
2622
|
let emergencyCompact: Awaited<
|
|
2871
2623
|
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2872
2624
|
> | null = null;
|
|
@@ -2908,7 +2660,11 @@ export async function runAgentLoopImpl(
|
|
|
2908
2660
|
{ err, phase: "emergency-compaction" },
|
|
2909
2661
|
"Emergency compaction pipeline timed out — continuing with overflow fallback",
|
|
2910
2662
|
);
|
|
2911
|
-
await
|
|
2663
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2664
|
+
ctx,
|
|
2665
|
+
true,
|
|
2666
|
+
onEvent,
|
|
2667
|
+
);
|
|
2912
2668
|
emergencyCompact = null;
|
|
2913
2669
|
} else {
|
|
2914
2670
|
throw err;
|
|
@@ -2920,7 +2676,7 @@ export async function runAgentLoopImpl(
|
|
|
2920
2676
|
emergencyCompact &&
|
|
2921
2677
|
emergencyCompact.summaryFailed !== undefined
|
|
2922
2678
|
) {
|
|
2923
|
-
await
|
|
2679
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2924
2680
|
ctx,
|
|
2925
2681
|
emergencyCompact.summaryFailed,
|
|
2926
2682
|
onEvent,
|
|
@@ -2964,19 +2720,7 @@ export async function runAgentLoopImpl(
|
|
|
2964
2720
|
preRunHistoryLength = runMessages.length;
|
|
2965
2721
|
state.contextTooLargeDetected = false;
|
|
2966
2722
|
|
|
2967
|
-
updatedHistory = await
|
|
2968
|
-
runMessages,
|
|
2969
|
-
eventHandler,
|
|
2970
|
-
abortController.signal,
|
|
2971
|
-
reqId,
|
|
2972
|
-
onCheckpoint,
|
|
2973
|
-
turnCallSite,
|
|
2974
|
-
loopTurnCtx,
|
|
2975
|
-
turnOverrideProfile,
|
|
2976
|
-
resolveCurrentMaxInputTokens(),
|
|
2977
|
-
resolveCurrentOverrideProfile,
|
|
2978
|
-
resolveCurrentMaxInputTokens,
|
|
2979
|
-
);
|
|
2723
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2980
2724
|
}
|
|
2981
2725
|
// action === "fail_gracefully" falls through to the final error below
|
|
2982
2726
|
}
|
|
@@ -3110,8 +2854,12 @@ export async function runAgentLoopImpl(
|
|
|
3110
2854
|
assistantMessageInterface:
|
|
3111
2855
|
capturedTurnInterfaceContext.assistantMessageInterface,
|
|
3112
2856
|
};
|
|
2857
|
+
let yieldNoticePersistedId: string | null = null;
|
|
3113
2858
|
try {
|
|
3114
|
-
await runPipeline<
|
|
2859
|
+
const yieldPersistResult = (await runPipeline<
|
|
2860
|
+
PersistArgs,
|
|
2861
|
+
PersistResult
|
|
2862
|
+
>(
|
|
3115
2863
|
"persistence",
|
|
3116
2864
|
getMiddlewaresFor("persistence"),
|
|
3117
2865
|
defaultPersistenceTerminal,
|
|
@@ -3124,7 +2872,8 @@ export async function runAgentLoopImpl(
|
|
|
3124
2872
|
},
|
|
3125
2873
|
buildPluginTurnContext(ctx, reqId),
|
|
3126
2874
|
DEFAULT_TIMEOUTS.persistence,
|
|
3127
|
-
);
|
|
2875
|
+
)) as PersistAddResult;
|
|
2876
|
+
yieldNoticePersistedId = yieldPersistResult.message.id;
|
|
3128
2877
|
} catch (err) {
|
|
3129
2878
|
// Non-fatal — a DB hiccup must not escalate a budget-yield exit into
|
|
3130
2879
|
// a turn-level throw. The live SSE event was already emitted, so the
|
|
@@ -3134,6 +2883,48 @@ export async function runAgentLoopImpl(
|
|
|
3134
2883
|
"Failed to persist budget_yield_unrecovered notice (non-fatal)",
|
|
3135
2884
|
);
|
|
3136
2885
|
}
|
|
2886
|
+
// Record a synthetic `llm_request_logs` row for the yield so the
|
|
2887
|
+
// inspector's call rail surfaces a clickable, distinctly-rendered
|
|
2888
|
+
// entry for the failure itself. Without this row, the loop yields
|
|
2889
|
+
// silently — the user sees the notice in chat but the inspector
|
|
2890
|
+
// call list ends at the last actual LLM call with no way to scope
|
|
2891
|
+
// the "what compactions led to this failure?" question to the
|
|
2892
|
+
// yield event.
|
|
2893
|
+
//
|
|
2894
|
+
// Recorded *before* emitTerminalExit so the synthetic row exists
|
|
2895
|
+
// by the time the dispatcher's post-loop hook runs. The row
|
|
2896
|
+
// already carries `agent_loop_exit_reason` at insert time, so
|
|
2897
|
+
// `setAgentLoopExitReasonOnLatestLog`'s IS NULL guard skips it
|
|
2898
|
+
// and stamps the prior real mainAgent call instead — preserving
|
|
2899
|
+
// the existing "latest LLM call carries the exit reason"
|
|
2900
|
+
// invariant other consumers depend on.
|
|
2901
|
+
//
|
|
2902
|
+
// `preparedRequest` snapshots the best-known LLM request state
|
|
2903
|
+
// at yield time — `updatedHistory` (the conversation state the
|
|
2904
|
+
// next call would have been built from) plus the input-token
|
|
2905
|
+
// budget that just failed. Mirrors the role of `request_payload`
|
|
2906
|
+
// on real LLM-call rows; the notice text lives on
|
|
2907
|
+
// `response_payload`.
|
|
2908
|
+
if (yieldNoticePersistedId !== null && budgetYieldClassification) {
|
|
2909
|
+
try {
|
|
2910
|
+
recordSyntheticAgentErrorMessageLog({
|
|
2911
|
+
conversationId: ctx.conversationId,
|
|
2912
|
+
messageId: yieldNoticePersistedId,
|
|
2913
|
+
exitReason: "budget_yield_unrecovered",
|
|
2914
|
+
noticeText: budgetYieldClassification.userMessage,
|
|
2915
|
+
preparedRequest: {
|
|
2916
|
+
messages: updatedHistory,
|
|
2917
|
+
maxInputTokensBudget: resolveCurrentMaxInputTokens() ?? null,
|
|
2918
|
+
},
|
|
2919
|
+
createdAt: Date.now(),
|
|
2920
|
+
});
|
|
2921
|
+
} catch (err) {
|
|
2922
|
+
rlog.warn(
|
|
2923
|
+
{ err },
|
|
2924
|
+
"Failed to record budget_yield_unrecovered synthetic call log (non-fatal)",
|
|
2925
|
+
);
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
3137
2928
|
await emitTerminalExit?.("budget_yield_unrecovered");
|
|
3138
2929
|
}
|
|
3139
2930
|
|
|
@@ -3154,6 +2945,34 @@ export async function runAgentLoopImpl(
|
|
|
3154
2945
|
!abortController.signal.aborted &&
|
|
3155
2946
|
!yieldedForHandoff
|
|
3156
2947
|
) {
|
|
2948
|
+
// Drop any reservation stranded by the failed LLM call before
|
|
2949
|
+
// inserting the synthetic error message. The B3 pre-allocation
|
|
2950
|
+
// path reserves an empty assistant row at `llm_call_started`;
|
|
2951
|
+
// when the call exits through the provider-error branch (no
|
|
2952
|
+
// `message_complete`), `assistantRowAwaitingFinalization` stays
|
|
2953
|
+
// true. Without this delete the transcript would carry both the
|
|
2954
|
+
// empty reserved row AND the error message — and downstream sync
|
|
2955
|
+
// (`syncLastAssistantMessageToDisk`) would mis-target the empty
|
|
2956
|
+
// row. After delete we set `lastAssistantMessageId` to the new
|
|
2957
|
+
// error row's id so the post-loop emission paths still point at
|
|
2958
|
+
// a real message.
|
|
2959
|
+
if (
|
|
2960
|
+
state.assistantRowAwaitingFinalization &&
|
|
2961
|
+
state.lastAssistantMessageId
|
|
2962
|
+
) {
|
|
2963
|
+
// Direct `deleteMessageById` (not via the `persistence` pipeline):
|
|
2964
|
+
// see the same rationale on the matching cleanup in
|
|
2965
|
+
// `handleLlmCallStarted` — an unfinalized reservation has no
|
|
2966
|
+
// observable history for plugins.
|
|
2967
|
+
try {
|
|
2968
|
+
deleteMessageById(state.lastAssistantMessageId);
|
|
2969
|
+
} catch (err) {
|
|
2970
|
+
rlog.warn(
|
|
2971
|
+
{ err, messageId: state.lastAssistantMessageId },
|
|
2972
|
+
"Failed to clean up stranded reserved assistant row on provider-error path (non-fatal)",
|
|
2973
|
+
);
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
3157
2976
|
const errChannelMeta = {
|
|
3158
2977
|
...provenanceFromTrustContext(ctx.trustContext),
|
|
3159
2978
|
userMessageChannel: capturedTurnChannelContext.userMessageChannel,
|
|
@@ -3181,6 +3000,15 @@ export async function runAgentLoopImpl(
|
|
|
3181
3000
|
DEFAULT_TIMEOUTS.persistence,
|
|
3182
3001
|
)) as PersistAddResult;
|
|
3183
3002
|
persistedErrorAssistantMessage = true;
|
|
3003
|
+
// Repoint `lastAssistantMessageId` at the synthetic error row so the
|
|
3004
|
+
// post-loop sync, attachment resolution, and `message_complete`/
|
|
3005
|
+
// `generation_handoff` emissions all reference a real, persisted
|
|
3006
|
+
// message id. The previous reservation (if any) was already deleted
|
|
3007
|
+
// above. Mark finalization complete so the next LLM call in this run
|
|
3008
|
+
// (or a downstream handler) doesn't try to clean up an id that
|
|
3009
|
+
// already corresponds to a finalized row.
|
|
3010
|
+
state.lastAssistantMessageId = errorPersistResult.message.id;
|
|
3011
|
+
state.assistantRowAwaitingFinalization = false;
|
|
3184
3012
|
newMessages.push(errorAssistantMessage);
|
|
3185
3013
|
// Pipe the just-assigned message id into any orphaned LLM request log
|
|
3186
3014
|
// row(s) for this turn. The success path links rows via
|
|
@@ -3282,7 +3110,10 @@ export async function runAgentLoopImpl(
|
|
|
3282
3110
|
// so the client can re-enable the UI without delay.
|
|
3283
3111
|
if (abortController.signal.aborted) {
|
|
3284
3112
|
syncLastAssistantMessageToDisk();
|
|
3285
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3113
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3114
|
+
anchor: "global",
|
|
3115
|
+
requestId: reqId,
|
|
3116
|
+
});
|
|
3286
3117
|
ctx.traceEmitter.emit(
|
|
3287
3118
|
"generation_cancelled",
|
|
3288
3119
|
"Generation cancelled by user",
|
|
@@ -3326,7 +3157,10 @@ export async function runAgentLoopImpl(
|
|
|
3326
3157
|
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3327
3158
|
pendingCheckpointYield = null;
|
|
3328
3159
|
}
|
|
3329
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3160
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3161
|
+
anchor: "global",
|
|
3162
|
+
requestId: reqId,
|
|
3163
|
+
});
|
|
3330
3164
|
ctx.traceEmitter.emit(
|
|
3331
3165
|
"generation_cancelled",
|
|
3332
3166
|
"Generation cancelled by user",
|
|
@@ -3367,7 +3201,10 @@ export async function runAgentLoopImpl(
|
|
|
3367
3201
|
});
|
|
3368
3202
|
publishLoopMessagesChanged();
|
|
3369
3203
|
} else {
|
|
3370
|
-
ctx.emitActivityState("idle", "message_complete",
|
|
3204
|
+
ctx.emitActivityState("idle", "message_complete", {
|
|
3205
|
+
anchor: "global",
|
|
3206
|
+
requestId: reqId,
|
|
3207
|
+
});
|
|
3371
3208
|
ctx.traceEmitter.emit(
|
|
3372
3209
|
"message_complete",
|
|
3373
3210
|
"Message processing complete",
|
|
@@ -3390,42 +3227,6 @@ export async function runAgentLoopImpl(
|
|
|
3390
3227
|
: {}),
|
|
3391
3228
|
});
|
|
3392
3229
|
publishLoopMessagesChanged();
|
|
3393
|
-
|
|
3394
|
-
// Proactive artifact: fire once when the processed turn was the 4th user message.
|
|
3395
|
-
// Only trigger for real user-authored turns (not subagent/system messages).
|
|
3396
|
-
{
|
|
3397
|
-
const paConv = getConversation(ctx.conversationId);
|
|
3398
|
-
if (
|
|
3399
|
-
paConv &&
|
|
3400
|
-
paConv.conversationType === "standard" &&
|
|
3401
|
-
options?.isUserMessage
|
|
3402
|
-
) {
|
|
3403
|
-
void (async () => {
|
|
3404
|
-
try {
|
|
3405
|
-
if (hasProactiveArtifactCompleted()) return;
|
|
3406
|
-
const userMsg = getMessageById(
|
|
3407
|
-
userMessageId,
|
|
3408
|
-
ctx.conversationId,
|
|
3409
|
-
);
|
|
3410
|
-
if (!userMsg) return;
|
|
3411
|
-
if (!tryClaimProactiveArtifactTrigger(userMsg.createdAt))
|
|
3412
|
-
return;
|
|
3413
|
-
await runProactiveArtifactJob({
|
|
3414
|
-
conversationId: ctx.conversationId,
|
|
3415
|
-
userMessageCutoff: userMsg.createdAt,
|
|
3416
|
-
assistantMessageId: state.lastAssistantMessageId,
|
|
3417
|
-
suppressAppBuild: state.appBuildToolUsedThisRun,
|
|
3418
|
-
broadcastMessage,
|
|
3419
|
-
});
|
|
3420
|
-
} catch (err) {
|
|
3421
|
-
log.warn(
|
|
3422
|
-
{ err, conversationId: ctx.conversationId },
|
|
3423
|
-
"Proactive artifact trigger failed",
|
|
3424
|
-
);
|
|
3425
|
-
}
|
|
3426
|
-
})();
|
|
3427
|
-
}
|
|
3428
|
-
}
|
|
3429
3230
|
}
|
|
3430
3231
|
}
|
|
3431
3232
|
|
|
@@ -3446,10 +3247,7 @@ export async function runAgentLoopImpl(
|
|
|
3446
3247
|
});
|
|
3447
3248
|
onEvent({
|
|
3448
3249
|
type: "sync_changed",
|
|
3449
|
-
tags: [
|
|
3450
|
-
SYNC_TAGS.conversationsList,
|
|
3451
|
-
conversationMetadataSyncTag(ctx.conversationId),
|
|
3452
|
-
],
|
|
3250
|
+
tags: [conversationMetadataSyncTag(ctx.conversationId)],
|
|
3453
3251
|
});
|
|
3454
3252
|
},
|
|
3455
3253
|
signal: abortController.signal,
|
|
@@ -3465,7 +3263,10 @@ export async function runAgentLoopImpl(
|
|
|
3465
3263
|
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3466
3264
|
pendingCheckpointYield = null;
|
|
3467
3265
|
}
|
|
3468
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3266
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3267
|
+
anchor: "global",
|
|
3268
|
+
requestId: reqId,
|
|
3269
|
+
});
|
|
3469
3270
|
rlog.info("Generation cancelled by user");
|
|
3470
3271
|
ctx.traceEmitter.emit(
|
|
3471
3272
|
"generation_cancelled",
|
|
@@ -3481,7 +3282,10 @@ export async function runAgentLoopImpl(
|
|
|
3481
3282
|
});
|
|
3482
3283
|
publishLoopMessagesChanged();
|
|
3483
3284
|
} else {
|
|
3484
|
-
ctx.emitActivityState("idle", "error_terminal",
|
|
3285
|
+
ctx.emitActivityState("idle", "error_terminal", {
|
|
3286
|
+
anchor: "global",
|
|
3287
|
+
requestId: reqId,
|
|
3288
|
+
});
|
|
3485
3289
|
const message = err instanceof Error ? err.message : String(err);
|
|
3486
3290
|
const errorClass = err instanceof Error ? err.constructor.name : "Error";
|
|
3487
3291
|
rlog.error({ err }, "Conversation processing error");
|
|
@@ -3694,7 +3498,7 @@ export async function applyCompactionResult(
|
|
|
3694
3498
|
result.summaryText,
|
|
3695
3499
|
ctx.contextCompactedMessageCount,
|
|
3696
3500
|
);
|
|
3697
|
-
|
|
3501
|
+
markHistoryStrippedBestEffort(ctx.conversationId, compactedAt, log);
|
|
3698
3502
|
if (options.slackContextCompactionWatermarkTs) {
|
|
3699
3503
|
updateConversationSlackContextWatermark(
|
|
3700
3504
|
ctx.conversationId,
|