@vellumai/assistant 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -2
- package/docker-entrypoint.sh +0 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +1492 -100
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +302 -33
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +2 -1
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-token-estimator.test.ts +91 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
- package/src/__tests__/conversation-agent-loop.test.ts +188 -129
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +324 -0
- package/src/__tests__/conversation-lifecycle.test.ts +53 -12
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +7 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/injector-chain.test.ts +2 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +161 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +151 -0
- package/src/__tests__/openai-responses-provider.test.ts +118 -16
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -5
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +161 -124
- package/src/__tests__/terminal-tools.test.ts +12 -2
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +89 -53
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +94 -10
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +65 -20
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/browser/operations.ts +15 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +483 -0
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/commands/notifications.ts +24 -2
- package/src/cli/program.ts +2 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +24 -12
- package/src/config/call-site-defaults.ts +20 -0
- package/src/config/feature-flag-registry.json +115 -3
- package/src/config/llm-resolver.ts +16 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
- package/src/config/schemas/call-site-catalog.ts +35 -0
- package/src/config/schemas/llm.ts +14 -0
- package/src/config/schemas/memory-v2.ts +294 -1
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +60 -1
- package/src/context/token-estimator.ts +47 -4
- package/src/context/window-manager.ts +25 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
- package/src/daemon/conversation-agent-loop.ts +307 -88
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +149 -118
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +145 -84
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +70 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +54 -32
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/config-a2a.ts +160 -0
- package/src/daemon/handlers/config-model.test.ts +2 -0
- package/src/daemon/handlers/conversations.ts +90 -3
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +5 -5
- package/src/daemon/host-file-proxy.ts +5 -5
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +11 -11
- package/src/daemon/lifecycle.ts +40 -23
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +14 -9
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +66 -7
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +69 -12
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/daemon/trust-context.ts +6 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +6 -1
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +85 -0
- package/src/home/suggested-prompts.ts +168 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +191 -100
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +26 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +68 -15
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +11 -3
- package/src/memory/memory-retrospective-job.ts +413 -18
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +41 -14
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +34 -0
- package/src/memory/migrations/registry.ts +58 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/infrastructure.ts +22 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +158 -112
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +660 -4
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +42 -25
- package/src/memory/v2/page-index.ts +209 -7
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +369 -62
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/messaging/providers/index.ts +7 -1
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/emit-signal.ts +38 -50
- package/src/notifications/home-feed-side-effect.ts +60 -30
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +8 -5
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +6 -3
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +100 -20
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/system-prompt.test.ts +46 -2
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +69 -19
- package/src/prompts/system-prompt.ts +118 -216
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +10 -2
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +281 -9
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +159 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/adapter-factory.ts +18 -1
- package/src/providers/inference/auth.ts +3 -3
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/resolve-auth.ts +49 -6
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +91 -1
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +63 -23
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +86 -23
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +152 -56
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +43 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-types.ts +7 -6
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +50 -8
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +147 -2
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +196 -31
- package/src/runtime/routes/conversation-routes.ts +472 -425
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +17 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +20 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
- package/src/runtime/routes/integrations/a2a.ts +60 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +427 -0
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +188 -0
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
- package/src/tools/browser/browser-execution.ts +106 -0
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
- package/src/tools/browser/cdp-client/factory.ts +171 -4
- package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
- package/src/tools/browser/cdp-client/types.ts +101 -0
- package/src/tools/browser/pinned-tabs.ts +146 -0
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +187 -2
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +216 -73
- package/src/tools/network/web-search.ts +216 -98
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +31 -98
- package/src/tools/ui-surface/definitions.ts +9 -23
- package/src/types/onboarding-context.ts +4 -0
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -7
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/prompts/cache-boundary.ts +0 -8
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -15,6 +15,7 @@ import { optimizeImageForTransport } from "../agent/image-optimize.js";
|
|
|
15
15
|
import type {
|
|
16
16
|
AgentEvent,
|
|
17
17
|
AgentLoop,
|
|
18
|
+
AgentLoopExitReason,
|
|
18
19
|
CheckpointDecision,
|
|
19
20
|
CheckpointInfo,
|
|
20
21
|
} from "../agent/loop.js";
|
|
@@ -27,9 +28,13 @@ import type {
|
|
|
27
28
|
} from "../channels/types.js";
|
|
28
29
|
import {
|
|
29
30
|
contextWindowConfigFromEffective,
|
|
31
|
+
type EffectiveContextWindow,
|
|
30
32
|
resolveEffectiveContextWindow,
|
|
31
33
|
} from "../config/llm-context-resolution.js";
|
|
32
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
resolveCallSiteConfig,
|
|
36
|
+
resolveDefaultProfileKey,
|
|
37
|
+
} from "../config/llm-resolver.js";
|
|
33
38
|
import { getConfig } from "../config/loader.js";
|
|
34
39
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
35
40
|
import type { ContextWindowConfig } from "../config/types.js";
|
|
@@ -54,7 +59,6 @@ import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
|
54
59
|
import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
55
60
|
import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
|
|
56
61
|
import {
|
|
57
|
-
clearStrippedInjectionMetadataForConversation,
|
|
58
62
|
getConversation,
|
|
59
63
|
getConversationOriginChannel,
|
|
60
64
|
getConversationOriginInterface,
|
|
@@ -62,6 +66,8 @@ import {
|
|
|
62
66
|
getLastUserTimestampBefore,
|
|
63
67
|
getMessageById,
|
|
64
68
|
provenanceFromTrustContext,
|
|
69
|
+
setConversationHistoryStrippedAt,
|
|
70
|
+
setLastNotifiedInferenceProfile,
|
|
65
71
|
updateConversationContextWindow,
|
|
66
72
|
updateConversationSlackContextWatermark,
|
|
67
73
|
} from "../memory/conversation-crud.js";
|
|
@@ -156,13 +162,13 @@ import {
|
|
|
156
162
|
createEventHandlerState,
|
|
157
163
|
dispatchAgentEvent,
|
|
158
164
|
type EventHandlerDeps,
|
|
159
|
-
getClientDisplayMessageId,
|
|
160
165
|
} from "./conversation-agent-loop-handlers.js";
|
|
161
166
|
import {
|
|
162
167
|
approveHostAttachmentRead,
|
|
163
168
|
resolveAssistantAttachments,
|
|
164
169
|
} from "./conversation-attachments.js";
|
|
165
170
|
import {
|
|
171
|
+
budgetYieldUnrecoveredClassification,
|
|
166
172
|
buildConversationErrorMessage,
|
|
167
173
|
classifyConversationError,
|
|
168
174
|
isUserCancellation,
|
|
@@ -521,14 +527,26 @@ export interface AgentLoopConversationContext {
|
|
|
521
527
|
/** Per-turn snapshot of channelCapabilities, frozen at message-processing start. */
|
|
522
528
|
currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
523
529
|
/**
|
|
524
|
-
*
|
|
530
|
+
* Current inference-profile override for this turn. Read by
|
|
525
531
|
* `createToolExecutor` so `ToolContext.overrideProfile` carries the same
|
|
526
|
-
* profile the agent loop is sending to the provider.
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
* had `inferenceProfile` set.
|
|
532
|
+
* profile the agent loop is sending to the provider. Refreshed between
|
|
533
|
+
* model calls so an explicitly confirmed profile session opened mid-turn
|
|
534
|
+
* is inherited by later tool executions and nested subagents.
|
|
530
535
|
*/
|
|
531
536
|
currentTurnOverrideProfile?: string;
|
|
537
|
+
/**
|
|
538
|
+
* Set by the `switch_inference_profile` tool when the model self-selects a
|
|
539
|
+
* different profile mid-turn. Read by `readCurrentOverrideProfile` in the
|
|
540
|
+
* agent loop so the next LLM call uses the switched profile. Reset at
|
|
541
|
+
* turn start.
|
|
542
|
+
*/
|
|
543
|
+
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;
|
|
532
550
|
commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
533
551
|
trustContext?: TrustContext;
|
|
534
552
|
/** Task-run scope for the current turn. Cleared at turn end so queued/drained turns don't inherit it. */
|
|
@@ -536,7 +554,6 @@ export interface AgentLoopConversationContext {
|
|
|
536
554
|
assistantId?: string;
|
|
537
555
|
voiceCallControlPrompt?: string;
|
|
538
556
|
transportHints?: string[];
|
|
539
|
-
slackRuntimeContextNotice?: string;
|
|
540
557
|
clientTimezone?: string;
|
|
541
558
|
|
|
542
559
|
readonly coreToolNames: Set<string>;
|
|
@@ -670,6 +687,18 @@ export async function runAgentLoopImpl(
|
|
|
670
687
|
requestId: reqId,
|
|
671
688
|
});
|
|
672
689
|
let yieldedForHandoff = false;
|
|
690
|
+
let yieldedForBudget = false;
|
|
691
|
+
let pendingCheckpointYield: "budget" | "handoff" | null = null;
|
|
692
|
+
// Captured when the auto_compress_latest_turn rerun yields at the mid-loop
|
|
693
|
+
// budget checkpoint. SSE emission happens immediately at the detection site;
|
|
694
|
+
// assistant-row persistence is deferred until after the pendingToolResults
|
|
695
|
+
// flush so we don't orphan tool_use/tool_result pairs in the durable history.
|
|
696
|
+
let budgetYieldClassification: ReturnType<
|
|
697
|
+
typeof budgetYieldUnrecoveredClassification
|
|
698
|
+
> | null = null;
|
|
699
|
+
let emitTerminalExit:
|
|
700
|
+
| ((reason: AgentLoopExitReason) => Promise<void>)
|
|
701
|
+
| null = null;
|
|
673
702
|
|
|
674
703
|
// Default user-initiated turns to the `mainAgent` call site. Other
|
|
675
704
|
// invocation contexts (heartbeat, filing, analyze, etc.) pass their own
|
|
@@ -691,31 +720,124 @@ export async function runAgentLoopImpl(
|
|
|
691
720
|
// spawned subagent's background conversation) wins over the row read
|
|
692
721
|
// so the agent loop's own background-skip rule doesn't zero out an
|
|
693
722
|
// explicitly inherited override.
|
|
694
|
-
const
|
|
723
|
+
const userExplicitOverride =
|
|
695
724
|
options?.overrideProfile ??
|
|
696
725
|
getConversationOverrideProfileFromRow(turnStartConversation);
|
|
697
726
|
|
|
727
|
+
ctx.hasExplicitProfileOverride = !!userExplicitOverride;
|
|
728
|
+
|
|
698
729
|
const config = getConfig();
|
|
730
|
+
|
|
731
|
+
// Tool-based auto-routing: the switch_inference_profile tool lets the model
|
|
732
|
+
// self-select a different profile mid-turn. Reset the per-turn slot so a
|
|
733
|
+
// stale selection from a previous turn doesn't leak forward.
|
|
734
|
+
ctx.toolRoutedProfile = undefined;
|
|
735
|
+
|
|
736
|
+
const turnOverrideProfile = userExplicitOverride;
|
|
737
|
+
|
|
738
|
+
const readCurrentOverrideProfile = (): string | undefined =>
|
|
739
|
+
options?.overrideProfile ??
|
|
740
|
+
getConversationOverrideProfileFromRow(
|
|
741
|
+
getConversation(ctx.conversationId),
|
|
742
|
+
) ??
|
|
743
|
+
ctx.toolRoutedProfile;
|
|
744
|
+
|
|
699
745
|
const effectiveContextWindow = resolveEffectiveContextWindow({
|
|
700
746
|
llm: config.llm,
|
|
701
747
|
callSite: turnCallSite,
|
|
702
748
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
703
749
|
});
|
|
704
|
-
|
|
750
|
+
let currentEffectiveContextWindow: EffectiveContextWindow =
|
|
751
|
+
effectiveContextWindow;
|
|
752
|
+
let currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
705
753
|
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
706
754
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
707
755
|
}).contextWindow,
|
|
708
|
-
|
|
756
|
+
currentEffectiveContextWindow,
|
|
709
757
|
);
|
|
710
|
-
|
|
758
|
+
const contextWindowManager =
|
|
711
759
|
ctx.contextWindowManager as ContextWindowManager & {
|
|
712
760
|
updateConfig?: (config: ContextWindowConfig) => void;
|
|
761
|
+
};
|
|
762
|
+
contextWindowManager.updateConfig?.(currentContextWindowConfig);
|
|
763
|
+
|
|
764
|
+
let appliedOverrideProfile = turnOverrideProfile;
|
|
765
|
+
let emittedToolRoutedProfile: string | undefined;
|
|
766
|
+
const refreshCurrentProfileState = (): string | undefined => {
|
|
767
|
+
const currentOverrideProfile = readCurrentOverrideProfile();
|
|
768
|
+
if (currentOverrideProfile !== appliedOverrideProfile) {
|
|
769
|
+
currentEffectiveContextWindow = resolveEffectiveContextWindow({
|
|
770
|
+
llm: config.llm,
|
|
771
|
+
callSite: turnCallSite,
|
|
772
|
+
overrideProfile: currentOverrideProfile,
|
|
773
|
+
});
|
|
774
|
+
currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
775
|
+
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
776
|
+
overrideProfile: currentOverrideProfile,
|
|
777
|
+
}).contextWindow,
|
|
778
|
+
currentEffectiveContextWindow,
|
|
779
|
+
);
|
|
780
|
+
contextWindowManager.updateConfig?.(currentContextWindowConfig);
|
|
781
|
+
appliedOverrideProfile = currentOverrideProfile;
|
|
782
|
+
rlog.info(
|
|
783
|
+
{ overrideProfile: currentOverrideProfile ?? null },
|
|
784
|
+
"Turn inference profile changed mid-loop",
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Emit turn_profile_auto_routed when the tool-based router selects a
|
|
789
|
+
// new profile. Deduplicated so the event fires at most once per profile.
|
|
790
|
+
if (
|
|
791
|
+
ctx.toolRoutedProfile &&
|
|
792
|
+
ctx.toolRoutedProfile !== emittedToolRoutedProfile
|
|
793
|
+
) {
|
|
794
|
+
emittedToolRoutedProfile = ctx.toolRoutedProfile;
|
|
795
|
+
const profileEntry = config.llm.profiles?.[ctx.toolRoutedProfile];
|
|
796
|
+
const label = profileEntry?.label ?? ctx.toolRoutedProfile;
|
|
797
|
+
broadcastMessage({
|
|
798
|
+
type: "turn_profile_auto_routed",
|
|
799
|
+
conversationId: ctx.conversationId,
|
|
800
|
+
profile: ctx.toolRoutedProfile,
|
|
801
|
+
profileLabel: label,
|
|
802
|
+
});
|
|
713
803
|
}
|
|
714
|
-
).updateConfig?.(turnContextWindowConfig);
|
|
715
804
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
805
|
+
ctx.currentTurnOverrideProfile = currentOverrideProfile;
|
|
806
|
+
return currentOverrideProfile;
|
|
807
|
+
};
|
|
808
|
+
const resolveCurrentOverrideProfile = (): string | undefined =>
|
|
809
|
+
refreshCurrentProfileState();
|
|
810
|
+
const resolveCurrentMaxInputTokens = (): number => {
|
|
811
|
+
refreshCurrentProfileState();
|
|
812
|
+
return currentEffectiveContextWindow.maxInputTokens;
|
|
813
|
+
};
|
|
814
|
+
const resolveCurrentContextWindowConfig = (): ContextWindowConfig => {
|
|
815
|
+
refreshCurrentProfileState();
|
|
816
|
+
return currentContextWindowConfig;
|
|
817
|
+
};
|
|
818
|
+
const resolveCurrentContextBudget = (): {
|
|
819
|
+
overflowRecovery: EffectiveContextWindow["overflowRecovery"];
|
|
820
|
+
providerMaxTokens: number;
|
|
821
|
+
preflightBudget: number;
|
|
822
|
+
} => {
|
|
823
|
+
refreshCurrentProfileState();
|
|
824
|
+
const overflowRecovery = currentEffectiveContextWindow.overflowRecovery;
|
|
825
|
+
const providerMaxTokens = currentEffectiveContextWindow.maxInputTokens;
|
|
826
|
+
const baseSafetyMargin = overflowRecovery.safetyMarginRatio;
|
|
827
|
+
const messageCount = ctx.messages.length;
|
|
828
|
+
const safetyMargin =
|
|
829
|
+
messageCount > 50 ? Math.max(baseSafetyMargin, 0.15) : baseSafetyMargin;
|
|
830
|
+
return {
|
|
831
|
+
overflowRecovery,
|
|
832
|
+
providerMaxTokens,
|
|
833
|
+
preflightBudget: Math.floor(providerMaxTokens * (1 - safetyMargin)),
|
|
834
|
+
};
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// Initial value for `createToolExecutor` to read into
|
|
838
|
+
// `ToolContext.overrideProfile`. `resolveCurrentOverrideProfile` refreshes
|
|
839
|
+
// this between model calls so a confirmed profile session opened by a tool
|
|
840
|
+
// applies to later tool executions and nested subagents in the same turn.
|
|
719
841
|
ctx.currentTurnOverrideProfile = turnOverrideProfile;
|
|
720
842
|
|
|
721
843
|
// Capture the turn channel context *before* any awaits so a second
|
|
@@ -1029,6 +1151,7 @@ export async function runAgentLoopImpl(
|
|
|
1029
1151
|
{
|
|
1030
1152
|
message: result.messages[0]!,
|
|
1031
1153
|
sourceChannelTs: null,
|
|
1154
|
+
tagLineProvenance: "none",
|
|
1032
1155
|
},
|
|
1033
1156
|
...retainedRenderedMessages,
|
|
1034
1157
|
],
|
|
@@ -1088,7 +1211,7 @@ export async function runAgentLoopImpl(
|
|
|
1088
1211
|
precomputedEstimate: compactCheck.estimatedTokens,
|
|
1089
1212
|
conversationOriginChannel:
|
|
1090
1213
|
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
1091
|
-
overrideProfile:
|
|
1214
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1092
1215
|
};
|
|
1093
1216
|
let compacted: Awaited<
|
|
1094
1217
|
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
@@ -1453,6 +1576,26 @@ export async function runAgentLoopImpl(
|
|
|
1453
1576
|
}
|
|
1454
1577
|
}
|
|
1455
1578
|
|
|
1579
|
+
// Resolve the effective profile key for this turn and detect changes.
|
|
1580
|
+
// Only inject model_profile into the turn context when the profile
|
|
1581
|
+
// changed since the last turn (or on the first turn of a conversation)
|
|
1582
|
+
// to avoid per-turn token cost.
|
|
1583
|
+
const effectiveProfileKey =
|
|
1584
|
+
turnOverrideProfile ??
|
|
1585
|
+
config.llm.activeProfile ??
|
|
1586
|
+
resolveDefaultProfileKey("mainAgent", config.llm);
|
|
1587
|
+
const lastNotified = turnStartConversation?.lastNotifiedInferenceProfile;
|
|
1588
|
+
let modelProfileStr: string | null = null;
|
|
1589
|
+
if (effectiveProfileKey != null && effectiveProfileKey !== lastNotified) {
|
|
1590
|
+
const profileEntry = config.llm.profiles?.[effectiveProfileKey];
|
|
1591
|
+
const resolved = resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
1592
|
+
overrideProfile: turnOverrideProfile ?? undefined,
|
|
1593
|
+
});
|
|
1594
|
+
const label = profileEntry?.label ?? effectiveProfileKey;
|
|
1595
|
+
modelProfileStr = resolved.model ? `${label} (${resolved.model})` : label;
|
|
1596
|
+
setLastNotifiedInferenceProfile(ctx.conversationId, effectiveProfileKey);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1456
1599
|
const baseTurnContext = {
|
|
1457
1600
|
timestamp,
|
|
1458
1601
|
interfaceName,
|
|
@@ -1461,6 +1604,7 @@ export async function runAgentLoopImpl(
|
|
|
1461
1604
|
clientTimezone: timezoneContext.clientTimezone,
|
|
1462
1605
|
detectedTimezone: timezoneContext.detectedTimezone,
|
|
1463
1606
|
timeSinceLastMessage,
|
|
1607
|
+
modelProfile: modelProfileStr,
|
|
1464
1608
|
};
|
|
1465
1609
|
const unifiedTurnContextStr = buildUnifiedTurnContextBlock(
|
|
1466
1610
|
isGuardian
|
|
@@ -1506,7 +1650,7 @@ export async function runAgentLoopImpl(
|
|
|
1506
1650
|
// V2 static memory block (essentials/threads/recent/buffer).
|
|
1507
1651
|
// `currentMemoryV2Static` is the trust-gated content reused by every
|
|
1508
1652
|
// re-injection path — it stays non-null on non-full-mode turns so
|
|
1509
|
-
// that mid-turn reducer compaction (which strips the prior `<
|
|
1653
|
+
// that mid-turn reducer compaction (which strips the prior `<info>`
|
|
1510
1654
|
// block) can restore the freshest content. `memoryV2Static` is the
|
|
1511
1655
|
// first-turn / post-compaction cadence-gated value for initial
|
|
1512
1656
|
// injection only. `readMemoryV2StaticContent` self-gates on the v2
|
|
@@ -1617,7 +1761,6 @@ export async function runAgentLoopImpl(
|
|
|
1617
1761
|
nowScratchpad,
|
|
1618
1762
|
voiceCallControlPrompt: ctx.voiceCallControlPrompt ?? null,
|
|
1619
1763
|
transportHints: ctx.transportHints ?? null,
|
|
1620
|
-
slackRuntimeContextNotice: ctx.slackRuntimeContextNotice ?? null,
|
|
1621
1764
|
isNonInteractive: !isInteractiveResolved,
|
|
1622
1765
|
isBackgroundConversation: isBackgroundConversationType(
|
|
1623
1766
|
turnStartConversation?.conversationType,
|
|
@@ -1704,15 +1847,9 @@ export async function runAgentLoopImpl(
|
|
|
1704
1847
|
// After runtime injections are applied, estimate the prompt token count
|
|
1705
1848
|
// and proactively invoke the reducer if already above budget. This avoids
|
|
1706
1849
|
// a wasted provider round-trip that would just fail with context_too_large.
|
|
1707
|
-
const
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
// compounds across many messages with tool results.
|
|
1711
|
-
const baseSafetyMargin = overflowRecovery.safetyMarginRatio;
|
|
1712
|
-
const messageCount = ctx.messages.length;
|
|
1713
|
-
const safetyMargin =
|
|
1714
|
-
messageCount > 50 ? Math.max(baseSafetyMargin, 0.15) : baseSafetyMargin;
|
|
1715
|
-
const preflightBudget = Math.floor(providerMaxTokens * (1 - safetyMargin));
|
|
1850
|
+
const initialContextBudget = resolveCurrentContextBudget();
|
|
1851
|
+
const overflowRecovery = initialContextBudget.overflowRecovery;
|
|
1852
|
+
const preflightBudget = initialContextBudget.preflightBudget;
|
|
1716
1853
|
let reducerState: ReducerState | undefined;
|
|
1717
1854
|
|
|
1718
1855
|
const toolTokenBudget = ctx.agentLoop.getToolTokenBudget(runMessages);
|
|
@@ -1789,10 +1926,10 @@ export async function runAgentLoopImpl(
|
|
|
1789
1926
|
runMessages,
|
|
1790
1927
|
systemPrompt: ctx.systemPrompt,
|
|
1791
1928
|
providerName: estimationProviderName,
|
|
1792
|
-
contextWindow:
|
|
1929
|
+
contextWindow: resolveCurrentContextWindowConfig(),
|
|
1793
1930
|
preflightBudget,
|
|
1794
1931
|
toolTokenBudget,
|
|
1795
|
-
maxAttempts: overflowRecovery.maxAttempts,
|
|
1932
|
+
maxAttempts: resolveCurrentContextBudget().overflowRecovery.maxAttempts,
|
|
1796
1933
|
abortSignal: abortController.signal,
|
|
1797
1934
|
compactFn: async (msgs, signal, opts) => {
|
|
1798
1935
|
// Route the reducer's forced-compaction tier through the
|
|
@@ -1822,7 +1959,7 @@ export async function runAgentLoopImpl(
|
|
|
1822
1959
|
signal,
|
|
1823
1960
|
options: {
|
|
1824
1961
|
...(opts ?? {}),
|
|
1825
|
-
overrideProfile:
|
|
1962
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1826
1963
|
},
|
|
1827
1964
|
},
|
|
1828
1965
|
buildPluginTurnContext(ctx, reqId),
|
|
@@ -2076,8 +2213,9 @@ export async function runAgentLoopImpl(
|
|
|
2076
2213
|
};
|
|
2077
2214
|
const eventHandler = (event: AgentEvent) =>
|
|
2078
2215
|
dispatchAgentEvent(state, deps, event);
|
|
2079
|
-
|
|
2080
|
-
|
|
2216
|
+
emitTerminalExit = async (reason: AgentLoopExitReason): Promise<void> => {
|
|
2217
|
+
await eventHandler({ type: "agent_loop_exit", reason });
|
|
2218
|
+
};
|
|
2081
2219
|
|
|
2082
2220
|
const onCheckpoint = async (
|
|
2083
2221
|
checkpoint: CheckpointInfo,
|
|
@@ -2086,6 +2224,7 @@ export async function runAgentLoopImpl(
|
|
|
2086
2224
|
|
|
2087
2225
|
if (ctx.canHandoffAtCheckpoint()) {
|
|
2088
2226
|
yieldedForHandoff = true;
|
|
2227
|
+
pendingCheckpointYield = "handoff";
|
|
2089
2228
|
return "yield";
|
|
2090
2229
|
}
|
|
2091
2230
|
|
|
@@ -2093,7 +2232,8 @@ export async function runAgentLoopImpl(
|
|
|
2093
2232
|
// yield if we're approaching the preflight budget. This lets the
|
|
2094
2233
|
// conversation-agent-loop run compaction before the provider rejects.
|
|
2095
2234
|
if (overflowRecovery.enabled) {
|
|
2096
|
-
const midLoopThreshold =
|
|
2235
|
+
const midLoopThreshold =
|
|
2236
|
+
resolveCurrentContextBudget().preflightBudget * 0.85;
|
|
2097
2237
|
const estimated = await runTokenEstimatePipeline(checkpoint.history);
|
|
2098
2238
|
if (estimated > midLoopThreshold) {
|
|
2099
2239
|
rlog.warn(
|
|
@@ -2101,6 +2241,7 @@ export async function runAgentLoopImpl(
|
|
|
2101
2241
|
"Token estimate approaching budget — yielding for compaction",
|
|
2102
2242
|
);
|
|
2103
2243
|
yieldedForBudget = true;
|
|
2244
|
+
pendingCheckpointYield = "budget";
|
|
2104
2245
|
return "yield";
|
|
2105
2246
|
}
|
|
2106
2247
|
}
|
|
@@ -2129,7 +2270,9 @@ export async function runAgentLoopImpl(
|
|
|
2129
2270
|
turnCallSite,
|
|
2130
2271
|
loopTurnCtx,
|
|
2131
2272
|
turnOverrideProfile,
|
|
2132
|
-
|
|
2273
|
+
resolveCurrentMaxInputTokens(),
|
|
2274
|
+
resolveCurrentOverrideProfile,
|
|
2275
|
+
resolveCurrentMaxInputTokens,
|
|
2133
2276
|
);
|
|
2134
2277
|
|
|
2135
2278
|
rlog.info(
|
|
@@ -2137,6 +2280,11 @@ export async function runAgentLoopImpl(
|
|
|
2137
2280
|
"Agent loop run completed",
|
|
2138
2281
|
);
|
|
2139
2282
|
|
|
2283
|
+
if (yieldedForHandoff) {
|
|
2284
|
+
await emitTerminalExit?.("checkpoint_handoff");
|
|
2285
|
+
pendingCheckpointYield = null;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2140
2288
|
// ── Proactive mid-loop compaction ───────────────────────────────
|
|
2141
2289
|
// When the agent loop yielded because the token budget check in
|
|
2142
2290
|
// onCheckpoint detected approaching limits, run compaction on the
|
|
@@ -2146,12 +2294,14 @@ export async function runAgentLoopImpl(
|
|
|
2146
2294
|
let midLoopCompactAttempts = 0;
|
|
2147
2295
|
while (
|
|
2148
2296
|
yieldedForBudget &&
|
|
2149
|
-
midLoopCompactAttempts <
|
|
2297
|
+
midLoopCompactAttempts <
|
|
2298
|
+
resolveCurrentContextBudget().overflowRecovery.maxAttempts &&
|
|
2150
2299
|
!state.contextTooLargeDetected &&
|
|
2151
2300
|
!abortController.signal.aborted
|
|
2152
2301
|
) {
|
|
2153
2302
|
midLoopCompactAttempts++;
|
|
2154
2303
|
yieldedForBudget = false;
|
|
2304
|
+
pendingCheckpointYield = null;
|
|
2155
2305
|
|
|
2156
2306
|
rlog.info(
|
|
2157
2307
|
{ phase: "mid-loop-compact" },
|
|
@@ -2162,14 +2312,7 @@ export async function runAgentLoopImpl(
|
|
|
2162
2312
|
// so we compact the "raw" persistent messages.
|
|
2163
2313
|
const rawHistory = stripInjectionsForCompaction(updatedHistory);
|
|
2164
2314
|
ctx.messages = rawHistory;
|
|
2165
|
-
|
|
2166
|
-
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
2167
|
-
} catch (err) {
|
|
2168
|
-
rlog.warn(
|
|
2169
|
-
{ err },
|
|
2170
|
-
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
2171
|
-
);
|
|
2172
|
-
}
|
|
2315
|
+
setConversationHistoryStrippedAt(ctx.conversationId, Date.now());
|
|
2173
2316
|
|
|
2174
2317
|
ctx.emitActivityState(
|
|
2175
2318
|
"thinking",
|
|
@@ -2193,10 +2336,11 @@ export async function runAgentLoopImpl(
|
|
|
2193
2336
|
options: {
|
|
2194
2337
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
2195
2338
|
force: true,
|
|
2196
|
-
targetInputTokensOverride:
|
|
2339
|
+
targetInputTokensOverride:
|
|
2340
|
+
resolveCurrentContextBudget().preflightBudget,
|
|
2197
2341
|
conversationOriginChannel:
|
|
2198
2342
|
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
2199
|
-
overrideProfile:
|
|
2343
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2200
2344
|
},
|
|
2201
2345
|
},
|
|
2202
2346
|
buildPluginTurnContext(ctx, reqId),
|
|
@@ -2282,7 +2426,9 @@ export async function runAgentLoopImpl(
|
|
|
2282
2426
|
turnCallSite,
|
|
2283
2427
|
loopTurnCtx,
|
|
2284
2428
|
turnOverrideProfile,
|
|
2285
|
-
|
|
2429
|
+
resolveCurrentMaxInputTokens(),
|
|
2430
|
+
resolveCurrentOverrideProfile,
|
|
2431
|
+
resolveCurrentMaxInputTokens,
|
|
2286
2432
|
);
|
|
2287
2433
|
}
|
|
2288
2434
|
|
|
@@ -2296,7 +2442,8 @@ export async function runAgentLoopImpl(
|
|
|
2296
2442
|
{
|
|
2297
2443
|
phase: "mid-loop-compact",
|
|
2298
2444
|
midLoopCompactAttempts,
|
|
2299
|
-
maxAttempts:
|
|
2445
|
+
maxAttempts:
|
|
2446
|
+
resolveCurrentContextBudget().overflowRecovery.maxAttempts,
|
|
2300
2447
|
},
|
|
2301
2448
|
"Mid-loop compaction exhausted all attempts — escalating to convergence loop",
|
|
2302
2449
|
);
|
|
@@ -2339,7 +2486,9 @@ export async function runAgentLoopImpl(
|
|
|
2339
2486
|
turnCallSite,
|
|
2340
2487
|
loopTurnCtx,
|
|
2341
2488
|
turnOverrideProfile,
|
|
2342
|
-
|
|
2489
|
+
resolveCurrentMaxInputTokens(),
|
|
2490
|
+
resolveCurrentOverrideProfile,
|
|
2491
|
+
resolveCurrentMaxInputTokens,
|
|
2343
2492
|
);
|
|
2344
2493
|
|
|
2345
2494
|
if (state.orderingErrorDetected) {
|
|
@@ -2408,7 +2557,9 @@ export async function runAgentLoopImpl(
|
|
|
2408
2557
|
turnCallSite,
|
|
2409
2558
|
loopTurnCtx,
|
|
2410
2559
|
turnOverrideProfile,
|
|
2411
|
-
|
|
2560
|
+
resolveCurrentMaxInputTokens(),
|
|
2561
|
+
resolveCurrentOverrideProfile,
|
|
2562
|
+
resolveCurrentMaxInputTokens,
|
|
2412
2563
|
);
|
|
2413
2564
|
if (state.imageTooLargeDetected) {
|
|
2414
2565
|
rlog.error(
|
|
@@ -2445,14 +2596,7 @@ export async function runAgentLoopImpl(
|
|
|
2445
2596
|
|
|
2446
2597
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
2447
2598
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
2448
|
-
|
|
2449
|
-
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
2450
|
-
} catch (err) {
|
|
2451
|
-
rlog.warn(
|
|
2452
|
-
{ err },
|
|
2453
|
-
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
2454
|
-
);
|
|
2455
|
-
}
|
|
2599
|
+
setConversationHistoryStrippedAt(ctx.conversationId, Date.now());
|
|
2456
2600
|
convergenceStripped = true;
|
|
2457
2601
|
preRepairMessages = updatedHistory;
|
|
2458
2602
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -2479,18 +2623,21 @@ export async function runAgentLoopImpl(
|
|
|
2479
2623
|
toolTokenBudget,
|
|
2480
2624
|
},
|
|
2481
2625
|
);
|
|
2482
|
-
|
|
2626
|
+
const convergenceBudget = resolveCurrentContextBudget();
|
|
2627
|
+
let correctedTarget = convergenceBudget.preflightBudget;
|
|
2483
2628
|
if (actualTokens && estimatedTokensAtOverflow > 0) {
|
|
2484
2629
|
const estimationErrorRatio = actualTokens / estimatedTokensAtOverflow;
|
|
2485
2630
|
if (estimationErrorRatio > 1.0) {
|
|
2486
|
-
correctedTarget = Math.floor(
|
|
2631
|
+
correctedTarget = Math.floor(
|
|
2632
|
+
convergenceBudget.preflightBudget / estimationErrorRatio,
|
|
2633
|
+
);
|
|
2487
2634
|
rlog.warn(
|
|
2488
2635
|
{
|
|
2489
2636
|
phase: "convergence",
|
|
2490
2637
|
actualTokens,
|
|
2491
2638
|
estimatedTokens: estimatedTokensAtOverflow,
|
|
2492
2639
|
estimationErrorRatio: estimationErrorRatio.toFixed(2),
|
|
2493
|
-
preflightBudget,
|
|
2640
|
+
preflightBudget: convergenceBudget.preflightBudget,
|
|
2494
2641
|
correctedTarget,
|
|
2495
2642
|
},
|
|
2496
2643
|
"Adjusting compaction target based on observed estimation error",
|
|
@@ -2515,11 +2662,11 @@ export async function runAgentLoopImpl(
|
|
|
2515
2662
|
systemPrompt: ctx.systemPrompt,
|
|
2516
2663
|
tools: undefined,
|
|
2517
2664
|
compaction: emergencyConfig,
|
|
2518
|
-
maxInputTokens:
|
|
2665
|
+
maxInputTokens: resolveCurrentMaxInputTokens(),
|
|
2519
2666
|
previousEstimatedInputTokens: estimatedTokensAtOverflow,
|
|
2520
2667
|
force: true,
|
|
2521
2668
|
signal: abortController.signal,
|
|
2522
|
-
overrideProfile:
|
|
2669
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2523
2670
|
nonPersistedPrefixCount:
|
|
2524
2671
|
ctx.contextWindowManager.nonPersistedPrefixCount,
|
|
2525
2672
|
});
|
|
@@ -2557,7 +2704,7 @@ export async function runAgentLoopImpl(
|
|
|
2557
2704
|
}
|
|
2558
2705
|
|
|
2559
2706
|
let convergenceAttempts = 0;
|
|
2560
|
-
const maxAttempts = overflowRecovery.maxAttempts;
|
|
2707
|
+
const maxAttempts = convergenceBudget.overflowRecovery.maxAttempts;
|
|
2561
2708
|
|
|
2562
2709
|
while (
|
|
2563
2710
|
state.contextTooLargeDetected &&
|
|
@@ -2586,7 +2733,7 @@ export async function runAgentLoopImpl(
|
|
|
2586
2733
|
{
|
|
2587
2734
|
providerName: estimationProviderName,
|
|
2588
2735
|
systemPrompt: ctx.systemPrompt,
|
|
2589
|
-
contextWindow:
|
|
2736
|
+
contextWindow: resolveCurrentContextWindowConfig(),
|
|
2590
2737
|
targetTokens: correctedTarget,
|
|
2591
2738
|
toolTokenBudget,
|
|
2592
2739
|
},
|
|
@@ -2594,7 +2741,7 @@ export async function runAgentLoopImpl(
|
|
|
2594
2741
|
(msgs, signal, opts) =>
|
|
2595
2742
|
ctx.contextWindowManager.maybeCompact(msgs, signal!, {
|
|
2596
2743
|
...(opts ?? {}),
|
|
2597
|
-
overrideProfile:
|
|
2744
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2598
2745
|
}),
|
|
2599
2746
|
abortController.signal,
|
|
2600
2747
|
);
|
|
@@ -2670,7 +2817,9 @@ export async function runAgentLoopImpl(
|
|
|
2670
2817
|
turnCallSite,
|
|
2671
2818
|
loopTurnCtx,
|
|
2672
2819
|
turnOverrideProfile,
|
|
2673
|
-
|
|
2820
|
+
resolveCurrentMaxInputTokens(),
|
|
2821
|
+
resolveCurrentOverrideProfile,
|
|
2822
|
+
resolveCurrentMaxInputTokens,
|
|
2674
2823
|
);
|
|
2675
2824
|
|
|
2676
2825
|
// If the rerun still yields at checkpoint, the turn is still
|
|
@@ -2692,14 +2841,7 @@ export async function runAgentLoopImpl(
|
|
|
2692
2841
|
// pre-rerun messages.
|
|
2693
2842
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
2694
2843
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
2695
|
-
|
|
2696
|
-
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
2697
|
-
} catch (err) {
|
|
2698
|
-
rlog.warn(
|
|
2699
|
-
{ err },
|
|
2700
|
-
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
2701
|
-
);
|
|
2702
|
-
}
|
|
2844
|
+
setConversationHistoryStrippedAt(ctx.conversationId, Date.now());
|
|
2703
2845
|
convergenceStripped = true;
|
|
2704
2846
|
preRepairMessages = updatedHistory;
|
|
2705
2847
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -2748,7 +2890,7 @@ export async function runAgentLoopImpl(
|
|
|
2748
2890
|
force: true,
|
|
2749
2891
|
minKeepRecentUserTurns: 0,
|
|
2750
2892
|
targetInputTokensOverride: correctedTarget,
|
|
2751
|
-
overrideProfile:
|
|
2893
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2752
2894
|
},
|
|
2753
2895
|
},
|
|
2754
2896
|
buildPluginTurnContext(ctx, reqId),
|
|
@@ -2831,7 +2973,9 @@ export async function runAgentLoopImpl(
|
|
|
2831
2973
|
turnCallSite,
|
|
2832
2974
|
loopTurnCtx,
|
|
2833
2975
|
turnOverrideProfile,
|
|
2834
|
-
|
|
2976
|
+
resolveCurrentMaxInputTokens(),
|
|
2977
|
+
resolveCurrentOverrideProfile,
|
|
2978
|
+
resolveCurrentMaxInputTokens,
|
|
2835
2979
|
);
|
|
2836
2980
|
}
|
|
2837
2981
|
// action === "fail_gracefully" falls through to the final error below
|
|
@@ -2843,7 +2987,35 @@ export async function runAgentLoopImpl(
|
|
|
2843
2987
|
new Error("context_length_exceeded"),
|
|
2844
2988
|
{ phase: "agent_loop" },
|
|
2845
2989
|
);
|
|
2990
|
+
await emitTerminalExit?.("context_too_large");
|
|
2991
|
+
pendingCheckpointYield = null;
|
|
2846
2992
|
onEvent(buildConversationErrorMessage(ctx.conversationId, classified));
|
|
2993
|
+
} else if (yieldedForBudget && !abortController.signal.aborted) {
|
|
2994
|
+
// The auto_compress_latest_turn rerun (action === "auto_compress_latest_turn"
|
|
2995
|
+
// above) reset `contextTooLargeDetected` to false before its final
|
|
2996
|
+
// `agentLoop.run`, so the context-too-large branch above won't fire
|
|
2997
|
+
// even when that rerun yields at the mid-loop budget checkpoint with
|
|
2998
|
+
// no further recovery layer to re-enter. Without surfacing this here,
|
|
2999
|
+
// the turn terminates silently — the inspector sees `agent_loop_exit_reason
|
|
3000
|
+
// = NULL` and the user sees no message at all (just a "ghost" turn).
|
|
3001
|
+
//
|
|
3002
|
+
// Unlike provider-error persistence at L3091 — which only fires when
|
|
3003
|
+
// the loop produced NO assistant output — budget_yield_unrecovered
|
|
3004
|
+
// typically yields AFTER one or more successful tool-use iterations,
|
|
3005
|
+
// so `hasAssistantResponse` is true and that path would skip us. We
|
|
3006
|
+
// capture the classification here so the live SSE event fires
|
|
3007
|
+
// immediately, and persist a dedicated notice row below — after the
|
|
3008
|
+
// pendingToolResults flush — so the transcript reads as: tool-use →
|
|
3009
|
+
// tool results → "I couldn't fit the next step…" notice. Persisting
|
|
3010
|
+
// earlier would orphan an assistant(tool_use) from its user(tool_result),
|
|
3011
|
+
// breaking provider adjacency on replay.
|
|
3012
|
+
budgetYieldClassification = budgetYieldUnrecoveredClassification();
|
|
3013
|
+
onEvent(
|
|
3014
|
+
buildConversationErrorMessage(
|
|
3015
|
+
ctx.conversationId,
|
|
3016
|
+
budgetYieldClassification,
|
|
3017
|
+
),
|
|
3018
|
+
);
|
|
2847
3019
|
}
|
|
2848
3020
|
}
|
|
2849
3021
|
|
|
@@ -2919,6 +3091,52 @@ export async function runAgentLoopImpl(
|
|
|
2919
3091
|
state.pendingToolResults.clear();
|
|
2920
3092
|
}
|
|
2921
3093
|
|
|
3094
|
+
// Persist the budget_yield_unrecovered notice now that any pending
|
|
3095
|
+
// tool_results have flushed. The SSE event already fired upstream; this
|
|
3096
|
+
// makes the row durable in the right position: tool-use → tool-results →
|
|
3097
|
+
// notice. Doing it earlier (e.g. at the detection site) would land the
|
|
3098
|
+
// assistant row between a tool_use and its tool_result and break provider
|
|
3099
|
+
// adjacency on replay.
|
|
3100
|
+
if (budgetYieldClassification && !abortController.signal.aborted) {
|
|
3101
|
+
const yieldNoticeMessage = createAssistantMessage(
|
|
3102
|
+
budgetYieldClassification.userMessage,
|
|
3103
|
+
);
|
|
3104
|
+
const yieldNoticeMetadata = {
|
|
3105
|
+
...provenanceFromTrustContext(ctx.trustContext),
|
|
3106
|
+
userMessageChannel: capturedTurnChannelContext.userMessageChannel,
|
|
3107
|
+
assistantMessageChannel:
|
|
3108
|
+
capturedTurnChannelContext.assistantMessageChannel,
|
|
3109
|
+
userMessageInterface: capturedTurnInterfaceContext.userMessageInterface,
|
|
3110
|
+
assistantMessageInterface:
|
|
3111
|
+
capturedTurnInterfaceContext.assistantMessageInterface,
|
|
3112
|
+
};
|
|
3113
|
+
try {
|
|
3114
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
3115
|
+
"persistence",
|
|
3116
|
+
getMiddlewaresFor("persistence"),
|
|
3117
|
+
defaultPersistenceTerminal,
|
|
3118
|
+
{
|
|
3119
|
+
op: "add",
|
|
3120
|
+
conversationId: ctx.conversationId,
|
|
3121
|
+
role: "assistant",
|
|
3122
|
+
content: JSON.stringify(yieldNoticeMessage.content),
|
|
3123
|
+
metadata: yieldNoticeMetadata,
|
|
3124
|
+
},
|
|
3125
|
+
buildPluginTurnContext(ctx, reqId),
|
|
3126
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
3127
|
+
);
|
|
3128
|
+
} catch (err) {
|
|
3129
|
+
// Non-fatal — a DB hiccup must not escalate a budget-yield exit into
|
|
3130
|
+
// a turn-level throw. The live SSE event was already emitted, so the
|
|
3131
|
+
// user still sees the notice this turn even if the durable row missed.
|
|
3132
|
+
rlog.warn(
|
|
3133
|
+
{ err },
|
|
3134
|
+
"Failed to persist budget_yield_unrecovered notice (non-fatal)",
|
|
3135
|
+
);
|
|
3136
|
+
}
|
|
3137
|
+
await emitTerminalExit?.("budget_yield_unrecovered");
|
|
3138
|
+
}
|
|
3139
|
+
|
|
2922
3140
|
// Reconstruct history
|
|
2923
3141
|
const newMessages = updatedHistory.slice(preRunHistoryLength).map((msg) => {
|
|
2924
3142
|
if (msg.role !== "assistant") return msg;
|
|
@@ -3041,11 +3259,11 @@ export async function runAgentLoopImpl(
|
|
|
3041
3259
|
state.exchangeLlmCallCount,
|
|
3042
3260
|
{
|
|
3043
3261
|
tokens: state.lastCallInputTokens,
|
|
3044
|
-
maxTokens:
|
|
3262
|
+
maxTokens: resolveCurrentMaxInputTokens(),
|
|
3045
3263
|
},
|
|
3046
3264
|
{
|
|
3047
3265
|
callSite: turnCallSite,
|
|
3048
|
-
overrideProfile:
|
|
3266
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
3049
3267
|
},
|
|
3050
3268
|
);
|
|
3051
3269
|
|
|
@@ -3101,10 +3319,13 @@ export async function runAgentLoopImpl(
|
|
|
3101
3319
|
ctx.lastAssistantAttachments = assistantAttachments;
|
|
3102
3320
|
ctx.lastAttachmentWarnings = attachmentResult.directiveWarnings;
|
|
3103
3321
|
syncLastAssistantMessageToDisk();
|
|
3104
|
-
const clientDisplayMessageId = getClientDisplayMessageId(state);
|
|
3105
3322
|
|
|
3106
3323
|
// Re-check: the user may have cancelled during attachment resolution
|
|
3107
3324
|
if (abortController.signal.aborted) {
|
|
3325
|
+
if (pendingCheckpointYield === "budget") {
|
|
3326
|
+
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3327
|
+
pendingCheckpointYield = null;
|
|
3328
|
+
}
|
|
3108
3329
|
ctx.emitActivityState("idle", "generation_cancelled", "global", reqId);
|
|
3109
3330
|
ctx.traceEmitter.emit(
|
|
3110
3331
|
"generation_cancelled",
|
|
@@ -3143,9 +3364,6 @@ export async function runAgentLoopImpl(
|
|
|
3143
3364
|
...(state.lastAssistantMessageId
|
|
3144
3365
|
? { messageId: state.lastAssistantMessageId }
|
|
3145
3366
|
: {}),
|
|
3146
|
-
...(clientDisplayMessageId
|
|
3147
|
-
? { displayMessageId: clientDisplayMessageId }
|
|
3148
|
-
: {}),
|
|
3149
3367
|
});
|
|
3150
3368
|
publishLoopMessagesChanged();
|
|
3151
3369
|
} else {
|
|
@@ -3170,9 +3388,6 @@ export async function runAgentLoopImpl(
|
|
|
3170
3388
|
...(state.lastAssistantMessageId
|
|
3171
3389
|
? { messageId: state.lastAssistantMessageId }
|
|
3172
3390
|
: {}),
|
|
3173
|
-
...(clientDisplayMessageId
|
|
3174
|
-
? { displayMessageId: clientDisplayMessageId }
|
|
3175
|
-
: {}),
|
|
3176
3391
|
});
|
|
3177
3392
|
publishLoopMessagesChanged();
|
|
3178
3393
|
|
|
@@ -3246,6 +3461,10 @@ export async function runAgentLoopImpl(
|
|
|
3246
3461
|
aborted: abortController.signal.aborted,
|
|
3247
3462
|
};
|
|
3248
3463
|
if (isUserCancellation(err, errorCtx)) {
|
|
3464
|
+
if (pendingCheckpointYield === "budget") {
|
|
3465
|
+
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3466
|
+
pendingCheckpointYield = null;
|
|
3467
|
+
}
|
|
3249
3468
|
ctx.emitActivityState("idle", "generation_cancelled", "global", reqId);
|
|
3250
3469
|
rlog.info("Generation cancelled by user");
|
|
3251
3470
|
ctx.traceEmitter.emit(
|
|
@@ -3338,7 +3557,6 @@ export async function runAgentLoopImpl(
|
|
|
3338
3557
|
ctx.diskPressureCleanupModeActive = false;
|
|
3339
3558
|
ctx.preactivatedSkillIds = undefined;
|
|
3340
3559
|
ctx.currentTurnOverrideProfile = undefined;
|
|
3341
|
-
ctx.slackRuntimeContextNotice = undefined;
|
|
3342
3560
|
// Channel command intents (e.g. Telegram /start) are single-turn metadata.
|
|
3343
3561
|
// Clear at turn end so they never leak into subsequent unrelated messages.
|
|
3344
3562
|
ctx.commandIntent = undefined;
|
|
@@ -3476,6 +3694,7 @@ export async function applyCompactionResult(
|
|
|
3476
3694
|
result.summaryText,
|
|
3477
3695
|
ctx.contextCompactedMessageCount,
|
|
3478
3696
|
);
|
|
3697
|
+
setConversationHistoryStrippedAt(ctx.conversationId, compactedAt);
|
|
3479
3698
|
if (options.slackContextCompactionWatermarkTs) {
|
|
3480
3699
|
updateConversationSlackContextWatermark(
|
|
3481
3700
|
ctx.conversationId,
|