@vellumai/assistant 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +5 -0
- package/ARCHITECTURE.md +32 -36
- package/Dockerfile +12 -0
- package/README.md +3 -4
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +123 -11
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +428 -501
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +427 -114
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +530 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
- package/src/__tests__/conversation-agent-loop.test.ts +412 -82
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
- package/src/__tests__/conversation-queue.test.ts +41 -26
- package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +34 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/model-intents.test.ts +9 -83
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/oauth-store.test.ts +10 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +50 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor.test.ts +60 -94
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -13
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +209 -17
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +14 -1
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +23 -4
- package/src/cli.ts +0 -37
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -175
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +30 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +53 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +2 -2
- package/src/context/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/window-manager.ts +229 -25
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
- package/src/daemon/conversation-agent-loop.ts +462 -80
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-lifecycle.ts +30 -6
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-process.ts +10 -4
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +760 -29
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +10 -5
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +118 -30
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +2 -2
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +76 -14
- package/src/daemon/message-types/conversations.ts +14 -0
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +117 -9
- package/src/daemon/tool-side-effects.ts +0 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +76 -28
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +4 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +56 -2
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +4 -4
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +17 -1
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +103 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +173 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +230 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/oauth/oauth-store.ts +1 -0
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/seed-providers.ts +4 -2
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +217 -708
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +26 -78
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -16
- package/src/platform/client.ts +19 -1
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +501 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +76 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +52 -1
- package/src/runtime/http-types.ts +23 -1
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +133 -27
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/migration-routes.ts +720 -124
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +28 -6
- package/src/schedule/scheduler.ts +8 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
- package/src/tools/browser/browser-execution.ts +65 -38
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +12 -3
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +2 -2
- package/src/util/pricing.ts +15 -5
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* runAgentLoop method here via the AgentLoopConversationContext interface.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
10
12
|
import { v4 as uuid } from "uuid";
|
|
11
13
|
|
|
12
14
|
import type {
|
|
@@ -24,11 +26,15 @@ import type {
|
|
|
24
26
|
} from "../channels/types.js";
|
|
25
27
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
26
28
|
import { getConfig } from "../config/loader.js";
|
|
29
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
27
30
|
import {
|
|
28
31
|
derefToolResultReReads,
|
|
29
32
|
postTurnTruncateToolResults,
|
|
30
33
|
} from "../context/post-turn-tool-result-truncation.js";
|
|
31
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
estimatePromptTokens,
|
|
36
|
+
getCalibrationProviderKey,
|
|
37
|
+
} from "../context/token-estimator.js";
|
|
32
38
|
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
33
39
|
import type { ToolProfiler } from "../events/tool-profiling-listener.js";
|
|
34
40
|
import { writeRelationshipState } from "../home/relationship-state-writer.js";
|
|
@@ -42,6 +48,7 @@ import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
|
42
48
|
import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
|
|
43
49
|
import {
|
|
44
50
|
addMessage,
|
|
51
|
+
clearPkbSystemReminderMetadataForConversation,
|
|
45
52
|
deleteMessageById,
|
|
46
53
|
getConversation,
|
|
47
54
|
getConversationOriginChannel,
|
|
@@ -63,6 +70,7 @@ import {
|
|
|
63
70
|
} from "../memory/conversation-title-service.js";
|
|
64
71
|
import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
65
72
|
import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
|
|
73
|
+
import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
|
|
66
74
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
67
75
|
import type { ContentBlock, Message } from "../providers/types.js";
|
|
68
76
|
import type { Provider } from "../providers/types.js";
|
|
@@ -71,6 +79,7 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
|
71
79
|
import { getSubagentManager } from "../subagent/index.js";
|
|
72
80
|
import type { UsageActor } from "../usage/actors.js";
|
|
73
81
|
import { getLogger } from "../util/logger.js";
|
|
82
|
+
import { getWorkspaceDir } from "../util/platform.js";
|
|
74
83
|
import { timeAgo } from "../util/time.js";
|
|
75
84
|
import { truncate } from "../util/truncate.js";
|
|
76
85
|
import { getWorkspaceGitService } from "../workspace/git-service.js";
|
|
@@ -115,8 +124,11 @@ import {
|
|
|
115
124
|
buildSubagentStatusBlock,
|
|
116
125
|
buildUnifiedTurnContextBlock,
|
|
117
126
|
findLastInjectedNowContent,
|
|
127
|
+
getPkbAutoInjectList,
|
|
118
128
|
inboundActorContextFromTrust,
|
|
119
129
|
inboundActorContextFromTrustContext,
|
|
130
|
+
loadSlackActiveThreadFocusBlock,
|
|
131
|
+
loadSlackChronologicalMessages,
|
|
120
132
|
readNowScratchpad,
|
|
121
133
|
readPkbContext,
|
|
122
134
|
stripInjectionsForCompaction,
|
|
@@ -135,44 +147,12 @@ import type {
|
|
|
135
147
|
UsageStats,
|
|
136
148
|
} from "./message-protocol.js";
|
|
137
149
|
import type { MemoryRecalled } from "./message-types/memory.js";
|
|
150
|
+
import { parseActualTokensFromError } from "./parse-actual-tokens-from-error.js";
|
|
138
151
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
152
|
+
import { stripHistoricalWebSearchResults } from "./web-search-history.js";
|
|
139
153
|
|
|
140
154
|
const log = getLogger("conversation-agent-loop");
|
|
141
155
|
|
|
142
|
-
/**
|
|
143
|
-
* Parse the actual token count reported by the provider in a context-too-large
|
|
144
|
-
* error message. Providers typically include the prompt size, e.g.:
|
|
145
|
-
* "prompt is too long: 242201 tokens > 200000 maximum"
|
|
146
|
-
* "too many input tokens: 242201 > 200000"
|
|
147
|
-
*
|
|
148
|
-
* Returns the actual token count or null if it cannot be parsed.
|
|
149
|
-
*/
|
|
150
|
-
export function parseActualTokensFromError(
|
|
151
|
-
errorMessage: string | null,
|
|
152
|
-
): number | null {
|
|
153
|
-
if (!errorMessage) return null;
|
|
154
|
-
|
|
155
|
-
// Match patterns like "242201 tokens > 200000" or "242201 > 200000 maximum"
|
|
156
|
-
const match = errorMessage.match(
|
|
157
|
-
/(\d[\d,]*)\s*tokens?\s*[>≥]|:\s*(\d[\d,]*)\s*[>≥]/i,
|
|
158
|
-
);
|
|
159
|
-
if (match) {
|
|
160
|
-
const raw = (match[1] || match[2]).replace(/,/g, "");
|
|
161
|
-
const parsed = parseInt(raw, 10);
|
|
162
|
-
if (!isNaN(parsed) && parsed > 0) return parsed;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Fallback: match "too many input tokens: N > M"
|
|
166
|
-
const fallback = errorMessage.match(/(\d[\d,]*)\s*[>≥]\s*\d/);
|
|
167
|
-
if (fallback) {
|
|
168
|
-
const raw = fallback[1].replace(/,/g, "");
|
|
169
|
-
const parsed = parseInt(raw, 10);
|
|
170
|
-
if (!isNaN(parsed) && parsed > 0) return parsed;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
156
|
/** Title-cased friendly labels for tool names, used in confirmation chips. */
|
|
177
157
|
const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
178
158
|
bash: "Run Command",
|
|
@@ -181,12 +161,6 @@ const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
|
181
161
|
file_read: "Read File",
|
|
182
162
|
file_write: "Write File",
|
|
183
163
|
file_edit: "Edit File",
|
|
184
|
-
browser_navigate: "Browser",
|
|
185
|
-
browser_click: "Browser",
|
|
186
|
-
browser_type: "Browser",
|
|
187
|
-
browser_screenshot: "Browser",
|
|
188
|
-
browser_scroll: "Browser",
|
|
189
|
-
browser_wait: "Browser",
|
|
190
164
|
app_create: "Create App",
|
|
191
165
|
app_refresh: "Refresh App",
|
|
192
166
|
skill_load: "Load Skill",
|
|
@@ -197,6 +171,79 @@ type GitServiceInitializer = {
|
|
|
197
171
|
ensureInitialized(): Promise<void>;
|
|
198
172
|
};
|
|
199
173
|
|
|
174
|
+
// ── Compaction circuit-breaker constants ────────────────────────────
|
|
175
|
+
//
|
|
176
|
+
// The circuit opens after `COMPACTION_CIRCUIT_FAILURE_THRESHOLD` consecutive
|
|
177
|
+
// summary-LLM failures and stays open for `COMPACTION_CIRCUIT_COOLDOWN_MS`
|
|
178
|
+
// before auto-compaction is allowed to retry. User-initiated compaction
|
|
179
|
+
// (`force: true`) bypasses the breaker regardless of its state.
|
|
180
|
+
const COMPACTION_CIRCUIT_FAILURE_THRESHOLD = 3;
|
|
181
|
+
const COMPACTION_CIRCUIT_COOLDOWN_MS = 60 * 60 * 1000; // 1 hour
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Check whether the compaction circuit breaker is currently open for the
|
|
185
|
+
* given context. The breaker auto-closes once `compactionCircuitOpenUntil`
|
|
186
|
+
* has elapsed.
|
|
187
|
+
*/
|
|
188
|
+
export function isCompactionCircuitOpen(ctx: {
|
|
189
|
+
compactionCircuitOpenUntil: number | null;
|
|
190
|
+
}): boolean {
|
|
191
|
+
return (
|
|
192
|
+
ctx.compactionCircuitOpenUntil !== null &&
|
|
193
|
+
Date.now() < ctx.compactionCircuitOpenUntil
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Track the outcome of a `maybeCompact()` call against the circuit breaker.
|
|
199
|
+
*
|
|
200
|
+
* - When the summary LLM call failed (local fallback covered the result),
|
|
201
|
+
* increment the consecutive-failure counter. If the counter reaches the
|
|
202
|
+
* threshold, open the circuit for the cooldown window and emit
|
|
203
|
+
* `compaction_circuit_open` so clients can surface a notice.
|
|
204
|
+
* - When the call did not fail, reset the counter and clear any open circuit.
|
|
205
|
+
*
|
|
206
|
+
* This is called by every `maybeCompact()` site (including forced ones),
|
|
207
|
+
* because a run of three failures is a provider-health signal regardless of
|
|
208
|
+
* whether the caller bypassed the breaker.
|
|
209
|
+
*/
|
|
210
|
+
export function trackCompactionOutcome(
|
|
211
|
+
ctx: {
|
|
212
|
+
consecutiveCompactionFailures: number;
|
|
213
|
+
compactionCircuitOpenUntil: number | null;
|
|
214
|
+
},
|
|
215
|
+
summaryFailed: boolean | undefined,
|
|
216
|
+
onEvent: (msg: ServerMessage) => void,
|
|
217
|
+
): void {
|
|
218
|
+
if (summaryFailed) {
|
|
219
|
+
ctx.consecutiveCompactionFailures += 1;
|
|
220
|
+
// Treat a stale/expired open-until timestamp the same as null so a new
|
|
221
|
+
// 3-strike window can re-open the circuit after the prior cooldown
|
|
222
|
+
// elapses. Without this the second trip would no-op because
|
|
223
|
+
// `compactionCircuitOpenUntil` remains set to a past timestamp even
|
|
224
|
+
// though `isCompactionCircuitOpen()` correctly reports closed.
|
|
225
|
+
const circuitDormant =
|
|
226
|
+
ctx.compactionCircuitOpenUntil === null ||
|
|
227
|
+
Date.now() >= ctx.compactionCircuitOpenUntil;
|
|
228
|
+
if (
|
|
229
|
+
ctx.consecutiveCompactionFailures >=
|
|
230
|
+
COMPACTION_CIRCUIT_FAILURE_THRESHOLD &&
|
|
231
|
+
circuitDormant
|
|
232
|
+
) {
|
|
233
|
+
const openUntil = Date.now() + COMPACTION_CIRCUIT_COOLDOWN_MS;
|
|
234
|
+
ctx.compactionCircuitOpenUntil = openUntil;
|
|
235
|
+
onEvent({
|
|
236
|
+
type: "compaction_circuit_open",
|
|
237
|
+
reason: "3_consecutive_failures",
|
|
238
|
+
openUntil,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
ctx.consecutiveCompactionFailures = 0;
|
|
243
|
+
ctx.compactionCircuitOpenUntil = null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
200
247
|
// ── Context Interface ────────────────────────────────────────────────
|
|
201
248
|
|
|
202
249
|
export interface AgentLoopConversationContext {
|
|
@@ -213,6 +260,10 @@ export interface AgentLoopConversationContext {
|
|
|
213
260
|
readonly contextWindowManager: ContextWindowManager;
|
|
214
261
|
contextCompactedMessageCount: number;
|
|
215
262
|
contextCompactedAt: number | null;
|
|
263
|
+
/** Tracks consecutive compaction failures (summary LLM call threw). */
|
|
264
|
+
consecutiveCompactionFailures: number;
|
|
265
|
+
/** Timestamp (ms since epoch) until which the circuit breaker is open. */
|
|
266
|
+
compactionCircuitOpenUntil: number | null;
|
|
216
267
|
|
|
217
268
|
readonly memoryPolicy: { scopeId: string; includeDefaultFallback: boolean };
|
|
218
269
|
readonly graphMemory: ConversationGraphMemory;
|
|
@@ -235,6 +286,7 @@ export interface AgentLoopConversationContext {
|
|
|
235
286
|
>;
|
|
236
287
|
pendingSurfaceActions: Map<string, { surfaceType: SurfaceType }>;
|
|
237
288
|
surfaceActionRequestIds: Set<string>;
|
|
289
|
+
approvedViaPromptThisTurn?: boolean;
|
|
238
290
|
currentTurnSurfaces: Array<{
|
|
239
291
|
surfaceId: string;
|
|
240
292
|
surfaceType: SurfaceType;
|
|
@@ -356,6 +408,13 @@ export async function runAgentLoopImpl(
|
|
|
356
408
|
isInteractive?: boolean;
|
|
357
409
|
isUserMessage?: boolean;
|
|
358
410
|
titleText?: string;
|
|
411
|
+
/**
|
|
412
|
+
* LLM call-site identifier threaded into the per-call provider config.
|
|
413
|
+
* Adapter callers (heartbeat, filing, scheduler, etc.) pass their own
|
|
414
|
+
* call-site id so the resolver picks `llm.callSites.<id>`. When unset,
|
|
415
|
+
* the agent loop defaults to `'mainAgent'` for user-initiated turns.
|
|
416
|
+
*/
|
|
417
|
+
callSite?: LLMCallSite;
|
|
359
418
|
},
|
|
360
419
|
): Promise<void> {
|
|
361
420
|
if (!ctx.abortController) {
|
|
@@ -379,6 +438,13 @@ export async function runAgentLoopImpl(
|
|
|
379
438
|
});
|
|
380
439
|
let yieldedForHandoff = false;
|
|
381
440
|
|
|
441
|
+
// Default user-initiated turns to the `mainAgent` call site. Other
|
|
442
|
+
// invocation contexts (heartbeat, filing, analyze, etc.) pass their own
|
|
443
|
+
// `callSite`. The provider layer resolves provider/model/maxTokens via
|
|
444
|
+
// `resolveCallSiteConfig`, picking up any user overrides under
|
|
445
|
+
// `llm.callSites.mainAgent` (falling back to `llm.default` when absent).
|
|
446
|
+
const turnCallSite: LLMCallSite = options?.callSite ?? "mainAgent";
|
|
447
|
+
|
|
382
448
|
// Capture the turn channel context *before* any awaits so a second
|
|
383
449
|
// message from a different channel can't overwrite it mid-flight.
|
|
384
450
|
// When context is unavailable (e.g. regenerate after daemon restart),
|
|
@@ -524,7 +590,10 @@ export async function runAgentLoopImpl(
|
|
|
524
590
|
let compactedThisTurn = false;
|
|
525
591
|
|
|
526
592
|
const compactCheck = ctx.contextWindowManager.shouldCompact(ctx.messages);
|
|
527
|
-
|
|
593
|
+
// Skip auto-compaction while the circuit breaker is open. Force paths
|
|
594
|
+
// and user-initiated /compact bypass this check.
|
|
595
|
+
const autoCompactAllowed = !isCompactionCircuitOpen(ctx);
|
|
596
|
+
if (compactCheck.needed && autoCompactAllowed) {
|
|
528
597
|
ctx.emitActivityState(
|
|
529
598
|
"thinking",
|
|
530
599
|
"context_compacting",
|
|
@@ -532,15 +601,27 @@ export async function runAgentLoopImpl(
|
|
|
532
601
|
reqId,
|
|
533
602
|
);
|
|
534
603
|
}
|
|
535
|
-
const compacted =
|
|
536
|
-
ctx.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
604
|
+
const compacted = autoCompactAllowed
|
|
605
|
+
? await ctx.contextWindowManager.maybeCompact(
|
|
606
|
+
ctx.messages,
|
|
607
|
+
abortController.signal,
|
|
608
|
+
{
|
|
609
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
610
|
+
precomputedEstimate: compactCheck.estimatedTokens,
|
|
611
|
+
conversationOriginChannel:
|
|
612
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
613
|
+
},
|
|
614
|
+
)
|
|
615
|
+
: null;
|
|
616
|
+
// Only track circuit-breaker state when a summary LLM call actually ran.
|
|
617
|
+
// `summaryFailed` is `undefined` on early returns (compaction disabled,
|
|
618
|
+
// below threshold, cooldown active, no eligible messages, truncation-only
|
|
619
|
+
// path) — treating those as "successful" compactions would silently reset
|
|
620
|
+
// the 3-strike counter and break the invariant.
|
|
621
|
+
if (compacted && compacted.summaryFailed !== undefined) {
|
|
622
|
+
trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent);
|
|
623
|
+
}
|
|
624
|
+
if (compacted?.compacted) {
|
|
544
625
|
ctx.messages = compacted.messages;
|
|
545
626
|
ctx.contextCompactedMessageCount += compacted.compactedPersistedMessages;
|
|
546
627
|
ctx.contextCompactedAt = Date.now();
|
|
@@ -631,7 +712,12 @@ export async function runAgentLoopImpl(
|
|
|
631
712
|
let runMessages = ctx.messages;
|
|
632
713
|
|
|
633
714
|
// Memory graph retrieval — dispatches to context-load / per-turn based on
|
|
634
|
-
// conversation state.
|
|
715
|
+
// conversation state. Keep the query vector around so the PKB reminder
|
|
716
|
+
// can reuse it for relevance-hint search (see `applyRuntimeInjections`).
|
|
717
|
+
let pkbQueryVector: number[] | undefined;
|
|
718
|
+
let pkbSparseVector:
|
|
719
|
+
| import("../memory/qdrant-client.js").QdrantSparseVector
|
|
720
|
+
| undefined;
|
|
635
721
|
const isTrustedActor = resolveTrustClass(ctx.trustContext) === "guardian";
|
|
636
722
|
if (isTrustedActor) {
|
|
637
723
|
const graphResult = await ctx.graphMemory.prepareMemory(
|
|
@@ -641,6 +727,22 @@ export async function runAgentLoopImpl(
|
|
|
641
727
|
onEvent,
|
|
642
728
|
);
|
|
643
729
|
runMessages = graphResult.runMessages;
|
|
730
|
+
// Select dense+sparse as a matched pair so RRF fusion combines two
|
|
731
|
+
// signals aligned to the same query text:
|
|
732
|
+
// 1. Context-load with a user query: user-query dense + user-query
|
|
733
|
+
// sparse — the cleanest pairing.
|
|
734
|
+
// 2. Otherwise (context-load without a user query, or per-turn):
|
|
735
|
+
// whatever `queryVector` / `sparseVector` the retriever produced,
|
|
736
|
+
// which are themselves co-aligned (both summary-derived in
|
|
737
|
+
// context-load, both user-last-message-derived in per-turn).
|
|
738
|
+
// Never pair a user-query dense with a summary-aligned sparse.
|
|
739
|
+
if (graphResult.userQueryVector) {
|
|
740
|
+
pkbQueryVector = graphResult.userQueryVector;
|
|
741
|
+
pkbSparseVector = graphResult.userQuerySparseVector;
|
|
742
|
+
} else {
|
|
743
|
+
pkbQueryVector = graphResult.queryVector;
|
|
744
|
+
pkbSparseVector = graphResult.sparseVector;
|
|
745
|
+
}
|
|
644
746
|
|
|
645
747
|
// Persist the injected block text in message metadata so it survives
|
|
646
748
|
// conversation reloads (eviction, restart, fork). loadFromDb re-injects
|
|
@@ -839,6 +941,21 @@ export async function runAgentLoopImpl(
|
|
|
839
941
|
const pkbContext = shouldInjectNowAndPkb ? currentPkbContent : null;
|
|
840
942
|
const pkbActive = currentPkbContent !== null;
|
|
841
943
|
|
|
944
|
+
// PKB relevance-hint inputs. Resolved once per turn and reused across
|
|
945
|
+
// re-injections so post-compaction rebuilds pick up fresh hints against
|
|
946
|
+
// the updated conversation history.
|
|
947
|
+
const pkbRoot = pkbActive ? join(getWorkspaceDir(), "pkb") : undefined;
|
|
948
|
+
const pkbAutoInjectList = pkbRoot
|
|
949
|
+
? getPkbAutoInjectList(pkbRoot)
|
|
950
|
+
: undefined;
|
|
951
|
+
// Pass `ctx` directly — `PkbContextConversation` is structural and
|
|
952
|
+
// `getInContextPkbPaths` re-reads `conversation.messages` on each call,
|
|
953
|
+
// so post-compaction re-injects see the updated history.
|
|
954
|
+
const pkbConversation = pkbActive ? ctx : undefined;
|
|
955
|
+
// PKB points live under a single workspace sentinel scope, not the
|
|
956
|
+
// conversation's memoryPolicy.scopeId. See `PKB_WORKSPACE_SCOPE` for why.
|
|
957
|
+
const pkbScopeId = pkbActive ? PKB_WORKSPACE_SCOPE : undefined;
|
|
958
|
+
|
|
842
959
|
// Subagent status injection — gives the parent LLM visibility into active/completed children.
|
|
843
960
|
// Skipped when this conversation IS a subagent (no nesting) or has no children.
|
|
844
961
|
const subagentStatusBlock = ctx.isSubagent
|
|
@@ -847,6 +964,43 @@ export async function runAgentLoopImpl(
|
|
|
847
964
|
getSubagentManager().getChildrenOf(ctx.conversationId),
|
|
848
965
|
);
|
|
849
966
|
|
|
967
|
+
// For any Slack conversation (channels and DMs alike), build a
|
|
968
|
+
// chronological transcript from the persisted message rows so the
|
|
969
|
+
// model sees one channel-wide view instead of the gateway's per-turn
|
|
970
|
+
// hints. DMs render as a flat sequence (no thread tags), channels
|
|
971
|
+
// include sibling threads.
|
|
972
|
+
const isSlackConversation = ctx.channelCapabilities?.channel === "slack";
|
|
973
|
+
const slackChronologicalMessages = isSlackConversation
|
|
974
|
+
? loadSlackChronologicalMessages(
|
|
975
|
+
ctx.conversationId,
|
|
976
|
+
ctx.channelCapabilities!,
|
|
977
|
+
{ trustClass: ctx.trustContext?.trustClass },
|
|
978
|
+
)
|
|
979
|
+
: null;
|
|
980
|
+
|
|
981
|
+
// Active-thread focus block: when the inbound user message belongs to
|
|
982
|
+
// a Slack thread, append a non-persisted `<active_thread>` tail block
|
|
983
|
+
// to the final user turn listing the thread's parent + replies. Helps
|
|
984
|
+
// the model orient when the channel transcript is long and
|
|
985
|
+
// interleaved. Replays strip the block via RUNTIME_INJECTION_PREFIXES.
|
|
986
|
+
// DMs short-circuit to null inside `loadSlackActiveThreadFocusBlock`
|
|
987
|
+
// since DMs do not have threads.
|
|
988
|
+
const slackActiveThreadFocusBlock = isSlackConversation
|
|
989
|
+
? loadSlackActiveThreadFocusBlock(
|
|
990
|
+
ctx.conversationId,
|
|
991
|
+
ctx.channelCapabilities!,
|
|
992
|
+
{ trustClass: ctx.trustContext?.trustClass },
|
|
993
|
+
)
|
|
994
|
+
: null;
|
|
995
|
+
|
|
996
|
+
// Guards the chronological-transcript override on re-injection after
|
|
997
|
+
// the reducer compacts `ctx.messages`. The captured transcript is the
|
|
998
|
+
// full persisted history; blindly replaying it on every re-inject would
|
|
999
|
+
// overwrite the reducer's compacted messages and undo compaction. Flip
|
|
1000
|
+
// to `true` after any compaction so subsequent re-injections fall back
|
|
1001
|
+
// to the reduced `ctx.messages`.
|
|
1002
|
+
let reducerCompacted = compactedThisTurn;
|
|
1003
|
+
|
|
850
1004
|
// Shared injection options — reused whenever we need to re-inject after reduction.
|
|
851
1005
|
const injectionOpts = {
|
|
852
1006
|
activeSurface,
|
|
@@ -858,27 +1012,66 @@ export async function runAgentLoopImpl(
|
|
|
858
1012
|
unifiedTurnContext: unifiedTurnContextStr,
|
|
859
1013
|
pkbContext,
|
|
860
1014
|
pkbActive,
|
|
1015
|
+
pkbQueryVector,
|
|
1016
|
+
pkbSparseVector,
|
|
1017
|
+
pkbScopeId,
|
|
1018
|
+
pkbConversation,
|
|
1019
|
+
pkbAutoInjectList,
|
|
1020
|
+
pkbRoot,
|
|
1021
|
+
pkbWorkingDir: pkbActive ? ctx.workingDir : undefined,
|
|
861
1022
|
nowScratchpad,
|
|
862
1023
|
voiceCallControlPrompt: ctx.voiceCallControlPrompt ?? null,
|
|
863
1024
|
transportHints: ctx.transportHints ?? null,
|
|
864
1025
|
isNonInteractive: !isInteractiveResolved,
|
|
865
1026
|
subagentStatusBlock,
|
|
1027
|
+
slackChronologicalMessages,
|
|
1028
|
+
slackActiveThreadFocusBlock,
|
|
866
1029
|
} as const;
|
|
867
1030
|
|
|
868
1031
|
let currentInjectionMode: InjectionMode = "full";
|
|
869
1032
|
|
|
870
|
-
|
|
1033
|
+
const injection = await applyRuntimeInjections(runMessages, {
|
|
871
1034
|
...injectionOpts,
|
|
1035
|
+
slackChronologicalMessages: reducerCompacted
|
|
1036
|
+
? null
|
|
1037
|
+
: injectionOpts.slackChronologicalMessages,
|
|
872
1038
|
mode: currentInjectionMode,
|
|
873
1039
|
});
|
|
1040
|
+
runMessages = injection.messages;
|
|
1041
|
+
|
|
1042
|
+
// Persist injected blocks in message metadata so they survive conversation
|
|
1043
|
+
// reloads (eviction, restart, fork). loadFromDb re-injects from metadata.
|
|
1044
|
+
// Only the first call site persists — the overflow-recovery re-entry sites
|
|
1045
|
+
// send identical bytes and the tail row may not correspond to
|
|
1046
|
+
// `userMessageId`. Both blocks are written in a single call to avoid
|
|
1047
|
+
// doubling SQLite SELECT+UPDATE work on every turn.
|
|
1048
|
+
if (
|
|
1049
|
+
injection.blocks.unifiedTurnContext ||
|
|
1050
|
+
injection.blocks.pkbSystemReminder
|
|
1051
|
+
) {
|
|
1052
|
+
try {
|
|
1053
|
+
const metadataUpdates: Record<string, unknown> = {};
|
|
1054
|
+
if (injection.blocks.unifiedTurnContext) {
|
|
1055
|
+
metadataUpdates.turnContextBlock =
|
|
1056
|
+
injection.blocks.unifiedTurnContext;
|
|
1057
|
+
}
|
|
1058
|
+
if (injection.blocks.pkbSystemReminder) {
|
|
1059
|
+
metadataUpdates.pkbSystemReminderBlock =
|
|
1060
|
+
injection.blocks.pkbSystemReminder;
|
|
1061
|
+
}
|
|
1062
|
+
updateMessageMetadata(userMessageId, metadataUpdates);
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
rlog.warn({ err }, "Failed to persist injection metadata (non-fatal)");
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
874
1067
|
|
|
875
1068
|
// ── Preflight budget evaluation ──────────────────────────────
|
|
876
1069
|
// After runtime injections are applied, estimate the prompt token count
|
|
877
1070
|
// and proactively invoke the reducer if already above budget. This avoids
|
|
878
1071
|
// a wasted provider round-trip that would just fail with context_too_large.
|
|
879
1072
|
const config = getConfig();
|
|
880
|
-
const overflowRecovery = config.contextWindow.overflowRecovery;
|
|
881
|
-
const providerMaxTokens = config.contextWindow.maxInputTokens;
|
|
1073
|
+
const overflowRecovery = config.llm.default.contextWindow.overflowRecovery;
|
|
1074
|
+
const providerMaxTokens = config.llm.default.contextWindow.maxInputTokens;
|
|
882
1075
|
// Widen safety margin for large conversations where estimation error
|
|
883
1076
|
// compounds across many messages with tool results.
|
|
884
1077
|
const baseSafetyMargin = overflowRecovery.safetyMarginRatio;
|
|
@@ -889,10 +1082,17 @@ export async function runAgentLoopImpl(
|
|
|
889
1082
|
let reducerState: ReducerState | undefined;
|
|
890
1083
|
|
|
891
1084
|
const toolTokenBudget = ctx.agentLoop.getToolTokenBudget(runMessages);
|
|
1085
|
+
// Canonical calibration key used at every `estimatePromptTokens` site in
|
|
1086
|
+
// this function. Matches the key recorded by `handleUsage` for wrapper
|
|
1087
|
+
// providers (OpenRouter routing to Anthropic → key is `"anthropic"`).
|
|
1088
|
+
const estimationProviderName = getCalibrationProviderKey(ctx.provider);
|
|
892
1089
|
const preflightTokens = estimatePromptTokens(
|
|
893
1090
|
runMessages,
|
|
894
1091
|
ctx.systemPrompt,
|
|
895
|
-
{
|
|
1092
|
+
{
|
|
1093
|
+
providerName: estimationProviderName,
|
|
1094
|
+
toolTokenBudget,
|
|
1095
|
+
},
|
|
896
1096
|
);
|
|
897
1097
|
|
|
898
1098
|
if (overflowRecovery.enabled && preflightTokens > preflightBudget) {
|
|
@@ -922,9 +1122,9 @@ export async function runAgentLoopImpl(
|
|
|
922
1122
|
const step = await reduceContextOverflow(
|
|
923
1123
|
ctx.messages,
|
|
924
1124
|
{
|
|
925
|
-
providerName:
|
|
1125
|
+
providerName: estimationProviderName,
|
|
926
1126
|
systemPrompt: ctx.systemPrompt,
|
|
927
|
-
contextWindow: config.contextWindow,
|
|
1127
|
+
contextWindow: config.llm.default.contextWindow,
|
|
928
1128
|
targetTokens: preflightBudget,
|
|
929
1129
|
toolTokenBudget,
|
|
930
1130
|
},
|
|
@@ -938,6 +1138,24 @@ export async function runAgentLoopImpl(
|
|
|
938
1138
|
ctx.messages = step.messages;
|
|
939
1139
|
currentInjectionMode = step.state.injectionMode;
|
|
940
1140
|
|
|
1141
|
+
// Track circuit-breaker state whenever the reducer invoked compaction.
|
|
1142
|
+
// The reducer's forced_compaction tier uses force:true, so it bypasses
|
|
1143
|
+
// the open-circuit check, but we still want failure tracking to detect
|
|
1144
|
+
// a run of broken summaries and clear the counter on success. Only
|
|
1145
|
+
// track when the summary LLM actually ran — `summaryFailed === undefined`
|
|
1146
|
+
// indicates an early return (no eligible messages, truncation-only
|
|
1147
|
+
// path, etc.) that shouldn't influence the breaker.
|
|
1148
|
+
if (
|
|
1149
|
+
step.compactionResult &&
|
|
1150
|
+
step.compactionResult.summaryFailed !== undefined
|
|
1151
|
+
) {
|
|
1152
|
+
trackCompactionOutcome(
|
|
1153
|
+
ctx,
|
|
1154
|
+
step.compactionResult.summaryFailed,
|
|
1155
|
+
onEvent,
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
941
1159
|
if (step.compactionResult?.compacted) {
|
|
942
1160
|
ctx.contextCompactedMessageCount +=
|
|
943
1161
|
step.compactionResult.compactedPersistedMessages;
|
|
@@ -981,13 +1199,14 @@ export async function runAgentLoopImpl(
|
|
|
981
1199
|
step.compactionResult.compactedPersistedMessages,
|
|
982
1200
|
);
|
|
983
1201
|
shouldInjectWorkspace = true;
|
|
1202
|
+
reducerCompacted = true;
|
|
984
1203
|
}
|
|
985
1204
|
|
|
986
1205
|
// Re-inject with potentially downgraded injection mode.
|
|
987
1206
|
// When compaction ran it strips existing NOW.md / PKB blocks, so we
|
|
988
1207
|
// must re-inject the current content. Otherwise rely on the deduplicated
|
|
989
1208
|
// value from injectionOpts to avoid duplicate injection.
|
|
990
|
-
|
|
1209
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
991
1210
|
...injectionOpts,
|
|
992
1211
|
...(step.compactionResult?.compacted && {
|
|
993
1212
|
pkbContext: currentPkbContent,
|
|
@@ -998,8 +1217,16 @@ export async function runAgentLoopImpl(
|
|
|
998
1217
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
999
1218
|
? ctx.workspaceTopLevelContext
|
|
1000
1219
|
: null,
|
|
1220
|
+
// Once the reducer has compacted `ctx.messages`, the captured
|
|
1221
|
+
// `slackChronologicalMessages` snapshot (built from the full
|
|
1222
|
+
// persisted transcript) would overwrite the compacted history
|
|
1223
|
+
// and undo compaction. Suppress the override from here on.
|
|
1224
|
+
slackChronologicalMessages: reducerCompacted
|
|
1225
|
+
? null
|
|
1226
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1001
1227
|
mode: currentInjectionMode,
|
|
1002
1228
|
});
|
|
1229
|
+
runMessages = injection.messages;
|
|
1003
1230
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1004
1231
|
const memResult = ctx.graphMemory.reinjectCachedMemory(runMessages);
|
|
1005
1232
|
runMessages = memResult.runMessages;
|
|
@@ -1011,7 +1238,10 @@ export async function runAgentLoopImpl(
|
|
|
1011
1238
|
const postInjectionTokens = estimatePromptTokens(
|
|
1012
1239
|
runMessages,
|
|
1013
1240
|
ctx.systemPrompt,
|
|
1014
|
-
{
|
|
1241
|
+
{
|
|
1242
|
+
providerName: estimationProviderName,
|
|
1243
|
+
toolTokenBudget,
|
|
1244
|
+
},
|
|
1015
1245
|
);
|
|
1016
1246
|
|
|
1017
1247
|
if (postInjectionTokens <= preflightBudget) break;
|
|
@@ -1034,6 +1264,20 @@ export async function runAgentLoopImpl(
|
|
|
1034
1264
|
runMessages = preRunRepair.messages;
|
|
1035
1265
|
}
|
|
1036
1266
|
|
|
1267
|
+
// Replace historical web_search_tool_result blocks with text summaries.
|
|
1268
|
+
// The opaque `encrypted_content` tokens Anthropic attaches to each result
|
|
1269
|
+
// expire / are route-scoped; replaying a stale token is rejected with
|
|
1270
|
+
// `Invalid encrypted_content in search_result block`. Titles + URLs
|
|
1271
|
+
// preserve enough context for the model on follow-up turns.
|
|
1272
|
+
const webSearchStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1273
|
+
if (webSearchStrip.stats.blocksStripped > 0) {
|
|
1274
|
+
rlog.info(
|
|
1275
|
+
{ phase: "pre_run", ...webSearchStrip.stats },
|
|
1276
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
1277
|
+
);
|
|
1278
|
+
runMessages = webSearchStrip.messages;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1037
1281
|
let preRunHistoryLength = runMessages.length;
|
|
1038
1282
|
|
|
1039
1283
|
const shouldGenerateTitle = isReplaceableTitle(
|
|
@@ -1056,17 +1300,11 @@ export async function runAgentLoopImpl(
|
|
|
1056
1300
|
let yieldedForBudget = false;
|
|
1057
1301
|
|
|
1058
1302
|
const onCheckpoint = (checkpoint: CheckpointInfo): CheckpointDecision => {
|
|
1059
|
-
const turnTools = state.currentTurnToolNames;
|
|
1060
1303
|
state.currentTurnToolNames = [];
|
|
1061
1304
|
|
|
1062
1305
|
if (ctx.canHandoffAtCheckpoint()) {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
turnTools.every((n) => n.startsWith("browser_"));
|
|
1066
|
-
if (!inBrowserFlow) {
|
|
1067
|
-
yieldedForHandoff = true;
|
|
1068
|
-
return "yield";
|
|
1069
|
-
}
|
|
1306
|
+
yieldedForHandoff = true;
|
|
1307
|
+
return "yield";
|
|
1070
1308
|
}
|
|
1071
1309
|
|
|
1072
1310
|
// Mid-loop token budget check: estimate current context size and
|
|
@@ -1077,7 +1315,10 @@ export async function runAgentLoopImpl(
|
|
|
1077
1315
|
const estimated = estimatePromptTokens(
|
|
1078
1316
|
checkpoint.history,
|
|
1079
1317
|
ctx.systemPrompt,
|
|
1080
|
-
{
|
|
1318
|
+
{
|
|
1319
|
+
providerName: estimationProviderName,
|
|
1320
|
+
toolTokenBudget,
|
|
1321
|
+
},
|
|
1081
1322
|
);
|
|
1082
1323
|
if (estimated > midLoopThreshold) {
|
|
1083
1324
|
rlog.warn(
|
|
@@ -1096,12 +1337,20 @@ export async function runAgentLoopImpl(
|
|
|
1096
1337
|
|
|
1097
1338
|
let denyCompressionMessage: Message | null = null;
|
|
1098
1339
|
|
|
1340
|
+
rlog.info({ callSite: turnCallSite }, "Starting agent loop run");
|
|
1341
|
+
|
|
1099
1342
|
let updatedHistory = await ctx.agentLoop.run(
|
|
1100
1343
|
runMessages,
|
|
1101
1344
|
eventHandler,
|
|
1102
1345
|
abortController.signal,
|
|
1103
1346
|
reqId,
|
|
1104
1347
|
onCheckpoint,
|
|
1348
|
+
turnCallSite,
|
|
1349
|
+
);
|
|
1350
|
+
|
|
1351
|
+
rlog.info(
|
|
1352
|
+
{ resultMessageCount: updatedHistory.length },
|
|
1353
|
+
"Agent loop run completed",
|
|
1105
1354
|
);
|
|
1106
1355
|
|
|
1107
1356
|
// ── Proactive mid-loop compaction ───────────────────────────────
|
|
@@ -1129,6 +1378,14 @@ export async function runAgentLoopImpl(
|
|
|
1129
1378
|
// so we compact the "raw" persistent messages.
|
|
1130
1379
|
const rawHistory = stripInjectionsForCompaction(updatedHistory);
|
|
1131
1380
|
ctx.messages = rawHistory;
|
|
1381
|
+
try {
|
|
1382
|
+
clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
|
|
1383
|
+
} catch (err) {
|
|
1384
|
+
rlog.warn(
|
|
1385
|
+
{ err },
|
|
1386
|
+
"Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1132
1389
|
|
|
1133
1390
|
ctx.emitActivityState(
|
|
1134
1391
|
"thinking",
|
|
@@ -1144,10 +1401,19 @@ export async function runAgentLoopImpl(
|
|
|
1144
1401
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1145
1402
|
force: true,
|
|
1146
1403
|
targetInputTokensOverride: preflightBudget,
|
|
1404
|
+
conversationOriginChannel:
|
|
1405
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
1147
1406
|
},
|
|
1148
1407
|
);
|
|
1408
|
+
// `force: true` bypasses the cooldown/threshold gates but early returns
|
|
1409
|
+
// for "no eligible messages" / "insufficient messages" still leave
|
|
1410
|
+
// `summaryFailed` undefined. Only track when the summary LLM actually ran.
|
|
1411
|
+
if (midLoopCompact.summaryFailed !== undefined) {
|
|
1412
|
+
trackCompactionOutcome(ctx, midLoopCompact.summaryFailed, onEvent);
|
|
1413
|
+
}
|
|
1149
1414
|
if (midLoopCompact.compacted) {
|
|
1150
1415
|
ctx.messages = midLoopCompact.messages;
|
|
1416
|
+
reducerCompacted = true;
|
|
1151
1417
|
ctx.contextCompactedMessageCount +=
|
|
1152
1418
|
midLoopCompact.compactedPersistedMessages;
|
|
1153
1419
|
ctx.contextCompactedAt = Date.now();
|
|
@@ -1194,18 +1460,33 @@ export async function runAgentLoopImpl(
|
|
|
1194
1460
|
// stripInjectionsForCompaction() unconditionally removed the existing
|
|
1195
1461
|
// NOW.md block from ctx.messages above, so we must always re-inject
|
|
1196
1462
|
// the current content regardless of whether compaction actually ran.
|
|
1197
|
-
|
|
1463
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
1198
1464
|
...injectionOpts,
|
|
1199
1465
|
pkbContext: currentPkbContent,
|
|
1200
1466
|
nowScratchpad: currentNowContent,
|
|
1201
1467
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1202
1468
|
? ctx.workspaceTopLevelContext
|
|
1203
1469
|
: null,
|
|
1470
|
+
// Suppress the chronological-transcript snapshot once the reducer
|
|
1471
|
+
// has collapsed `ctx.messages`; the captured snapshot reflects the
|
|
1472
|
+
// full persisted transcript and would overwrite compaction.
|
|
1473
|
+
slackChronologicalMessages: reducerCompacted
|
|
1474
|
+
? null
|
|
1475
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1204
1476
|
mode: currentInjectionMode,
|
|
1205
1477
|
});
|
|
1478
|
+
runMessages = injection.messages;
|
|
1206
1479
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1207
1480
|
ctx.graphMemory.retrackCachedNodes();
|
|
1208
1481
|
}
|
|
1482
|
+
const midLoopCompactStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1483
|
+
if (midLoopCompactStrip.stats.blocksStripped > 0) {
|
|
1484
|
+
rlog.info(
|
|
1485
|
+
{ phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
|
|
1486
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
1487
|
+
);
|
|
1488
|
+
runMessages = midLoopCompactStrip.messages;
|
|
1489
|
+
}
|
|
1209
1490
|
preRepairMessages = runMessages;
|
|
1210
1491
|
preRunHistoryLength = runMessages.length;
|
|
1211
1492
|
|
|
@@ -1215,6 +1496,7 @@ export async function runAgentLoopImpl(
|
|
|
1215
1496
|
abortController.signal,
|
|
1216
1497
|
reqId,
|
|
1217
1498
|
onCheckpoint,
|
|
1499
|
+
turnCallSite,
|
|
1218
1500
|
);
|
|
1219
1501
|
}
|
|
1220
1502
|
|
|
@@ -1246,7 +1528,9 @@ export async function runAgentLoopImpl(
|
|
|
1246
1528
|
);
|
|
1247
1529
|
const retryRepair = deepRepairHistory(runMessages);
|
|
1248
1530
|
runMessages = retryRepair.messages;
|
|
1249
|
-
|
|
1531
|
+
const retryStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1532
|
+
runMessages = retryStrip.messages;
|
|
1533
|
+
preRepairMessages = runMessages;
|
|
1250
1534
|
preRunHistoryLength = runMessages.length;
|
|
1251
1535
|
state.orderingErrorDetected = false;
|
|
1252
1536
|
state.deferredOrderingError = null;
|
|
@@ -1257,6 +1541,7 @@ export async function runAgentLoopImpl(
|
|
|
1257
1541
|
abortController.signal,
|
|
1258
1542
|
reqId,
|
|
1259
1543
|
onCheckpoint,
|
|
1544
|
+
turnCallSite,
|
|
1260
1545
|
);
|
|
1261
1546
|
|
|
1262
1547
|
if (state.orderingErrorDetected) {
|
|
@@ -1286,6 +1571,14 @@ export async function runAgentLoopImpl(
|
|
|
1286
1571
|
|
|
1287
1572
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
1288
1573
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
1574
|
+
try {
|
|
1575
|
+
clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
|
|
1576
|
+
} catch (err) {
|
|
1577
|
+
rlog.warn(
|
|
1578
|
+
{ err },
|
|
1579
|
+
"Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1289
1582
|
convergenceStripped = true;
|
|
1290
1583
|
preRepairMessages = updatedHistory;
|
|
1291
1584
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -1298,14 +1591,19 @@ export async function runAgentLoopImpl(
|
|
|
1298
1591
|
// message (e.g. "242201 tokens > 200000"), use it to correct the
|
|
1299
1592
|
// compaction target. The estimator may significantly underestimate
|
|
1300
1593
|
// (e.g. estimated 185k but actual was 242k), so using the
|
|
1301
|
-
// uncorrected preflightBudget would still be too high.
|
|
1594
|
+
// uncorrected preflightBudget would still be too high. Passes the raw
|
|
1595
|
+
// error so ContextOverflowError.actualTokens can short-circuit the
|
|
1596
|
+
// string-regex path for proxy-rewrapped untyped errors.
|
|
1302
1597
|
const actualTokens = parseActualTokensFromError(
|
|
1303
|
-
state.
|
|
1598
|
+
state.contextTooLargeError,
|
|
1304
1599
|
);
|
|
1305
1600
|
const estimatedTokensAtOverflow = estimatePromptTokens(
|
|
1306
1601
|
ctx.messages,
|
|
1307
1602
|
ctx.systemPrompt,
|
|
1308
|
-
{
|
|
1603
|
+
{
|
|
1604
|
+
providerName: estimationProviderName,
|
|
1605
|
+
toolTokenBudget,
|
|
1606
|
+
},
|
|
1309
1607
|
);
|
|
1310
1608
|
let correctedTarget = preflightBudget;
|
|
1311
1609
|
if (actualTokens && estimatedTokensAtOverflow > 0) {
|
|
@@ -1353,9 +1651,9 @@ export async function runAgentLoopImpl(
|
|
|
1353
1651
|
const step = await reduceContextOverflow(
|
|
1354
1652
|
ctx.messages,
|
|
1355
1653
|
{
|
|
1356
|
-
providerName:
|
|
1654
|
+
providerName: estimationProviderName,
|
|
1357
1655
|
systemPrompt: ctx.systemPrompt,
|
|
1358
|
-
contextWindow: config.contextWindow,
|
|
1656
|
+
contextWindow: config.llm.default.contextWindow,
|
|
1359
1657
|
targetTokens: correctedTarget,
|
|
1360
1658
|
toolTokenBudget,
|
|
1361
1659
|
},
|
|
@@ -1369,6 +1667,21 @@ export async function runAgentLoopImpl(
|
|
|
1369
1667
|
ctx.messages = step.messages;
|
|
1370
1668
|
currentInjectionMode = step.state.injectionMode;
|
|
1371
1669
|
|
|
1670
|
+
// See the preflight reducer call above for rationale. Only track when
|
|
1671
|
+
// the summary LLM actually ran — `summaryFailed === undefined`
|
|
1672
|
+
// indicates the reducer's forced compaction took an early-return path
|
|
1673
|
+
// without calling the summary LLM.
|
|
1674
|
+
if (
|
|
1675
|
+
step.compactionResult &&
|
|
1676
|
+
step.compactionResult.summaryFailed !== undefined
|
|
1677
|
+
) {
|
|
1678
|
+
trackCompactionOutcome(
|
|
1679
|
+
ctx,
|
|
1680
|
+
step.compactionResult.summaryFailed,
|
|
1681
|
+
onEvent,
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1372
1685
|
if (step.compactionResult?.compacted) {
|
|
1373
1686
|
ctx.contextCompactedMessageCount +=
|
|
1374
1687
|
step.compactionResult.compactedPersistedMessages;
|
|
@@ -1412,23 +1725,36 @@ export async function runAgentLoopImpl(
|
|
|
1412
1725
|
step.compactionResult.compactedPersistedMessages,
|
|
1413
1726
|
);
|
|
1414
1727
|
shouldInjectWorkspace = true;
|
|
1728
|
+
reducerCompacted = true;
|
|
1415
1729
|
}
|
|
1416
1730
|
|
|
1417
1731
|
// Only re-inject NOW.md when ctx.messages was actually stripped;
|
|
1418
1732
|
// otherwise the existing NOW.md block is still present and
|
|
1419
1733
|
// re-injecting would duplicate it.
|
|
1420
|
-
|
|
1734
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
1421
1735
|
...injectionOpts,
|
|
1422
1736
|
pkbContext: currentPkbContent,
|
|
1423
1737
|
nowScratchpad: convergenceStripped ? currentNowContent : null,
|
|
1424
1738
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1425
1739
|
? ctx.workspaceTopLevelContext
|
|
1426
1740
|
: null,
|
|
1741
|
+
slackChronologicalMessages: reducerCompacted
|
|
1742
|
+
? null
|
|
1743
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1427
1744
|
mode: currentInjectionMode,
|
|
1428
1745
|
});
|
|
1746
|
+
runMessages = injection.messages;
|
|
1429
1747
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1430
1748
|
ctx.graphMemory.retrackCachedNodes();
|
|
1431
1749
|
}
|
|
1750
|
+
const convergenceStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1751
|
+
if (convergenceStrip.stats.blocksStripped > 0) {
|
|
1752
|
+
rlog.info(
|
|
1753
|
+
{ phase: "convergence", ...convergenceStrip.stats },
|
|
1754
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
1755
|
+
);
|
|
1756
|
+
runMessages = convergenceStrip.messages;
|
|
1757
|
+
}
|
|
1432
1758
|
preRepairMessages = runMessages;
|
|
1433
1759
|
preRunHistoryLength = runMessages.length;
|
|
1434
1760
|
state.contextTooLargeDetected = false;
|
|
@@ -1440,6 +1766,7 @@ export async function runAgentLoopImpl(
|
|
|
1440
1766
|
abortController.signal,
|
|
1441
1767
|
reqId,
|
|
1442
1768
|
onCheckpoint,
|
|
1769
|
+
turnCallSite,
|
|
1443
1770
|
);
|
|
1444
1771
|
|
|
1445
1772
|
// If the rerun still yields at checkpoint, the turn is still
|
|
@@ -1461,6 +1788,14 @@ export async function runAgentLoopImpl(
|
|
|
1461
1788
|
// pre-rerun messages.
|
|
1462
1789
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
1463
1790
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
1791
|
+
try {
|
|
1792
|
+
clearPkbSystemReminderMetadataForConversation(ctx.conversationId);
|
|
1793
|
+
} catch (err) {
|
|
1794
|
+
rlog.warn(
|
|
1795
|
+
{ err },
|
|
1796
|
+
"Failed to clear pkbSystemReminderBlock metadata after compaction strip (non-fatal)",
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1464
1799
|
convergenceStripped = true;
|
|
1465
1800
|
preRepairMessages = updatedHistory;
|
|
1466
1801
|
preRunHistoryLength = updatedHistory.length;
|
|
@@ -1496,8 +1831,18 @@ export async function runAgentLoopImpl(
|
|
|
1496
1831
|
targetInputTokensOverride: correctedTarget,
|
|
1497
1832
|
},
|
|
1498
1833
|
);
|
|
1834
|
+
// Only track when the summary LLM actually ran; `force: true`
|
|
1835
|
+
// bypasses the cooldown but not the early-return paths.
|
|
1836
|
+
if (emergencyCompact.summaryFailed !== undefined) {
|
|
1837
|
+
trackCompactionOutcome(
|
|
1838
|
+
ctx,
|
|
1839
|
+
emergencyCompact.summaryFailed,
|
|
1840
|
+
onEvent,
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1499
1843
|
if (emergencyCompact.compacted) {
|
|
1500
1844
|
ctx.messages = emergencyCompact.messages;
|
|
1845
|
+
reducerCompacted = true;
|
|
1501
1846
|
ctx.contextCompactedMessageCount +=
|
|
1502
1847
|
emergencyCompact.compactedPersistedMessages;
|
|
1503
1848
|
ctx.contextCompactedAt = Date.now();
|
|
@@ -1544,18 +1889,30 @@ export async function runAgentLoopImpl(
|
|
|
1544
1889
|
|
|
1545
1890
|
// Only re-inject NOW.md when ctx.messages was actually stripped;
|
|
1546
1891
|
// otherwise the existing block is still present.
|
|
1547
|
-
|
|
1892
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
1548
1893
|
...injectionOpts,
|
|
1549
1894
|
pkbContext: currentPkbContent,
|
|
1550
1895
|
nowScratchpad: convergenceStripped ? currentNowContent : null,
|
|
1551
1896
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1552
1897
|
? ctx.workspaceTopLevelContext
|
|
1553
1898
|
: null,
|
|
1899
|
+
slackChronologicalMessages: reducerCompacted
|
|
1900
|
+
? null
|
|
1901
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1554
1902
|
mode: currentInjectionMode,
|
|
1555
1903
|
});
|
|
1904
|
+
runMessages = injection.messages;
|
|
1556
1905
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1557
1906
|
ctx.graphMemory.retrackCachedNodes();
|
|
1558
1907
|
}
|
|
1908
|
+
const emergencyStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1909
|
+
if (emergencyStrip.stats.blocksStripped > 0) {
|
|
1910
|
+
rlog.info(
|
|
1911
|
+
{ phase: "emergency_compact", ...emergencyStrip.stats },
|
|
1912
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
1913
|
+
);
|
|
1914
|
+
runMessages = emergencyStrip.messages;
|
|
1915
|
+
}
|
|
1559
1916
|
preRepairMessages = runMessages;
|
|
1560
1917
|
preRunHistoryLength = runMessages.length;
|
|
1561
1918
|
state.contextTooLargeDetected = false;
|
|
@@ -1566,6 +1923,7 @@ export async function runAgentLoopImpl(
|
|
|
1566
1923
|
abortController.signal,
|
|
1567
1924
|
reqId,
|
|
1568
1925
|
onCheckpoint,
|
|
1926
|
+
turnCallSite,
|
|
1569
1927
|
);
|
|
1570
1928
|
} else {
|
|
1571
1929
|
// User denied compression — emit a graceful assistant explanation
|
|
@@ -1619,8 +1977,18 @@ export async function runAgentLoopImpl(
|
|
|
1619
1977
|
targetInputTokensOverride: correctedTarget,
|
|
1620
1978
|
},
|
|
1621
1979
|
);
|
|
1980
|
+
// Only track when the summary LLM actually ran; `force: true`
|
|
1981
|
+
// bypasses the cooldown but not the early-return paths.
|
|
1982
|
+
if (emergencyCompact.summaryFailed !== undefined) {
|
|
1983
|
+
trackCompactionOutcome(
|
|
1984
|
+
ctx,
|
|
1985
|
+
emergencyCompact.summaryFailed,
|
|
1986
|
+
onEvent,
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1622
1989
|
if (emergencyCompact.compacted) {
|
|
1623
1990
|
ctx.messages = emergencyCompact.messages;
|
|
1991
|
+
reducerCompacted = true;
|
|
1624
1992
|
ctx.contextCompactedMessageCount +=
|
|
1625
1993
|
emergencyCompact.compactedPersistedMessages;
|
|
1626
1994
|
ctx.contextCompactedAt = Date.now();
|
|
@@ -1667,18 +2035,30 @@ export async function runAgentLoopImpl(
|
|
|
1667
2035
|
|
|
1668
2036
|
// Only re-inject NOW.md when ctx.messages was actually stripped;
|
|
1669
2037
|
// otherwise the existing block is still present.
|
|
1670
|
-
|
|
2038
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
1671
2039
|
...injectionOpts,
|
|
1672
2040
|
pkbContext: currentPkbContent,
|
|
1673
2041
|
nowScratchpad: convergenceStripped ? currentNowContent : null,
|
|
1674
2042
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1675
2043
|
? ctx.workspaceTopLevelContext
|
|
1676
2044
|
: null,
|
|
2045
|
+
slackChronologicalMessages: reducerCompacted
|
|
2046
|
+
? null
|
|
2047
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1677
2048
|
mode: currentInjectionMode,
|
|
1678
2049
|
});
|
|
2050
|
+
runMessages = injection.messages;
|
|
1679
2051
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1680
2052
|
ctx.graphMemory.retrackCachedNodes();
|
|
1681
2053
|
}
|
|
2054
|
+
const fallbackStrip = stripHistoricalWebSearchResults(runMessages);
|
|
2055
|
+
if (fallbackStrip.stats.blocksStripped > 0) {
|
|
2056
|
+
rlog.info(
|
|
2057
|
+
{ phase: "fail_gracefully_compact", ...fallbackStrip.stats },
|
|
2058
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
2059
|
+
);
|
|
2060
|
+
runMessages = fallbackStrip.messages;
|
|
2061
|
+
}
|
|
1682
2062
|
preRepairMessages = runMessages;
|
|
1683
2063
|
preRunHistoryLength = runMessages.length;
|
|
1684
2064
|
state.contextTooLargeDetected = false;
|
|
@@ -1689,6 +2069,7 @@ export async function runAgentLoopImpl(
|
|
|
1689
2069
|
abortController.signal,
|
|
1690
2070
|
reqId,
|
|
1691
2071
|
onCheckpoint,
|
|
2072
|
+
turnCallSite,
|
|
1692
2073
|
);
|
|
1693
2074
|
}
|
|
1694
2075
|
// action === "fail_gracefully" falls through to the final error below
|
|
@@ -1863,7 +2244,7 @@ export async function runAgentLoopImpl(
|
|
|
1863
2244
|
state.exchangeLlmCallCount,
|
|
1864
2245
|
{
|
|
1865
2246
|
tokens: state.lastCallInputTokens,
|
|
1866
|
-
maxTokens: config.contextWindow.maxInputTokens,
|
|
2247
|
+
maxTokens: config.llm.default.contextWindow.maxInputTokens,
|
|
1867
2248
|
},
|
|
1868
2249
|
);
|
|
1869
2250
|
|
|
@@ -2095,6 +2476,7 @@ export async function runAgentLoopImpl(
|
|
|
2095
2476
|
ctx.processing = false;
|
|
2096
2477
|
ctx.onConfirmationOutcome = undefined;
|
|
2097
2478
|
ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
|
|
2479
|
+
ctx.approvedViaPromptThisTurn = false;
|
|
2098
2480
|
ctx.currentRequestId = undefined;
|
|
2099
2481
|
ctx.currentActiveSurfaceId = undefined;
|
|
2100
2482
|
ctx.allowedToolNames = undefined;
|