@vellumai/assistant 0.8.5 → 0.8.7-dev.202606052118.34cd356
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -1
- package/ARCHITECTURE.md +1 -1
- package/Dockerfile +21 -4
- package/bun.lock +13 -4
- package/bunfig.toml +6 -1
- package/docker-entrypoint.sh +12 -8
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +114 -86
- package/examples/plugins/echo/README.md +13 -12
- package/examples/plugins/echo/register.ts +0 -54
- package/knip.json +1 -0
- package/node_modules/@vellumai/environments/bun.lock +24 -0
- package/node_modules/@vellumai/environments/package.json +18 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
- package/node_modules/@vellumai/environments/src/index.ts +11 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
- package/node_modules/@vellumai/environments/src/types.ts +70 -0
- package/node_modules/@vellumai/environments/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +15 -17
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +15 -7
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +8748 -589
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +88 -54
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
- package/src/__tests__/agent-loop-exit-reason.test.ts +284 -48
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +21 -33
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +7 -5
- package/src/__tests__/agent-loop-thinking.test.ts +17 -12
- package/src/__tests__/agent-loop.test.ts +238 -422
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +7 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -40
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +3 -3
- package/src/__tests__/anthropic-provider.test.ts +296 -57
- package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
- package/src/__tests__/app-control-flow.test.ts +6 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +5 -11
- package/src/__tests__/approval-routes-http.test.ts +17 -16
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-event.test.ts +15 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -27
- package/src/__tests__/assistant-stream-state.test.ts +645 -0
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/avatar-e2e.test.ts +7 -37
- package/src/__tests__/avatar-generator.test.ts +12 -42
- package/src/__tests__/avatar-identity-sync.test.ts +28 -3
- package/src/__tests__/background-shell-bash.test.ts +3 -7
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +72 -17
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/call-pointer-messages.test.ts +5 -3
- package/src/__tests__/call-site-routing-provider.test.ts +22 -40
- package/src/__tests__/catalog-files.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +52 -23
- package/src/__tests__/channel-approvals.test.ts +4 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-invite-transport.test.ts +1 -5
- package/src/__tests__/channel-readiness-routes.test.ts +0 -4
- package/src/__tests__/channel-readiness-slack-remote.test.ts +170 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +388 -79
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/clawhub-files.test.ts +1 -0
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +6 -17
- package/src/__tests__/compaction-trail-store.test.ts +186 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +14 -16
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/config-watcher.test.ts +28 -0
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-search-agent-runner.test.ts +6 -3
- package/src/__tests__/context-token-estimator.test.ts +56 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +73 -23
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +23 -34
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +477 -930
- package/src/__tests__/conversation-agent-loop.test.ts +1056 -1068
- package/src/__tests__/conversation-analysis-routes.test.ts +8 -3
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -1
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-clear-safety.test.ts +20 -10
- package/src/__tests__/conversation-confirmation-signals.test.ts +16 -45
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +10 -17
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +132 -157
- package/src/__tests__/conversation-fork-route.test.ts +19 -16
- package/src/__tests__/conversation-history-web-search.test.ts +12 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
- package/src/__tests__/conversation-lifecycle.test.ts +4 -2
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -3
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -1
- package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
- package/src/__tests__/conversation-pairing.test.ts +60 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +36 -7
- package/src/__tests__/conversation-process-callsite.test.ts +28 -30
- package/src/__tests__/conversation-provider-retry-repair.test.ts +85 -51
- package/src/__tests__/conversation-queue.test.ts +605 -455
- package/src/__tests__/conversation-routes-disk-view.test.ts +9 -20
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +35 -10
- package/src/__tests__/conversation-routes-slash-commands.test.ts +40 -8
- package/src/__tests__/conversation-runtime-assembly.test.ts +395 -313
- package/src/__tests__/conversation-runtime-workspace.test.ts +114 -36
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +125 -62
- package/src/__tests__/conversation-slash-unknown.test.ts +18 -15
- package/src/__tests__/conversation-speed-override.test.ts +9 -22
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +136 -15
- package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-table-action.test.ts +13 -32
- package/src/__tests__/conversation-sync-tags.test.ts +140 -12
- package/src/__tests__/conversation-title-service.test.ts +136 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +53 -11
- package/src/__tests__/conversation-unread-route.test.ts +14 -2
- package/src/__tests__/conversation-usage.test.ts +1 -2
- package/src/__tests__/conversation-wipe.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +21 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +119 -23
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +39 -13
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-execution-tools.test.ts +1 -2
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +275 -4
- package/src/__tests__/cu-unified-flow.test.ts +26 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -0
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +119 -36
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +9 -35
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +38 -43
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-page-surface.test.ts +99 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/edit-propagation.test.ts +1 -2
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/filing-service.test.ts +3 -2
- package/src/__tests__/first-greeting.test.ts +103 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/gemini-inline-media.test.ts +78 -0
- package/src/__tests__/gemini-provider.test.ts +375 -26
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +60 -71
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +11 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +3 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -1
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +162 -0
- package/src/__tests__/history-repair-observability.test.ts +1 -1
- package/src/__tests__/history-repair.test.ts +2 -1
- package/src/__tests__/host-app-control-proxy.test.ts +2 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-proxy.test.ts +2 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +4 -3
- package/src/__tests__/host-file-edit-tool.test.ts +4 -2
- package/src/__tests__/host-file-proxy.test.ts +31 -0
- package/src/__tests__/host-file-read-tool.test.ts +4 -2
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-write-tool.test.ts +9 -3
- package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
- package/src/__tests__/host-shell-tool.test.ts +11 -5
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +31 -9
- package/src/__tests__/identity-intro-cache.test.ts +140 -96
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +56 -75
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +78 -58
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +214 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-attachments.test.ts +7 -8
- package/src/__tests__/list-messages-hidden-metadata.test.ts +131 -11
- package/src/__tests__/list-messages-page-latest.test.ts +60 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +56 -6
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
- package/src/__tests__/llm-resolver.test.ts +346 -39
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/llm-usage-store.test.ts +268 -1
- package/src/__tests__/log-export-routes.test.ts +59 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-auth-routes.test.ts +15 -10
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/mcp-health-check.test.ts +18 -13
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/messaging-send-tool.test.ts +9 -4
- package/src/__tests__/migration-export-http.test.ts +12 -12
- package/src/__tests__/migration-import-commit-http.test.ts +8 -8
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +235 -22
- package/src/__tests__/notification-decision-identity.test.ts +9 -18
- package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +38 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +15 -2
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +105 -80
- package/src/__tests__/openai-responses-provider.test.ts +90 -86
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +48 -2
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -286
- package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +86 -13
- package/src/__tests__/pipeline-runner.test.ts +31 -43
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-bootstrap.test.ts +72 -63
- package/src/__tests__/plugin-registry.test.ts +0 -27
- package/src/__tests__/plugin-route-contribution.test.ts +6 -16
- package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +51 -64
- package/src/__tests__/plugin-types.test.ts +8 -173
- package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
- package/src/__tests__/process-message-background-slack.test.ts +38 -32
- package/src/__tests__/process-message-display-content.test.ts +55 -66
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
- package/src/__tests__/provider-error-scenarios.test.ts +7 -6
- package/src/__tests__/provider-platform-proxy-integration.test.ts +215 -8
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
- package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
- package/src/__tests__/provider-usage-tracking.test.ts +0 -6
- package/src/__tests__/ratelimit.test.ts +9 -4
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +6 -1
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +30 -23
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
- package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
- package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +390 -0
- package/src/__tests__/schedule-routes.test.ts +683 -12
- package/src/__tests__/schedule-store.test.ts +124 -1
- package/src/__tests__/schedule-tools.test.ts +160 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +7 -3
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
- package/src/__tests__/secret-response-routing.test.ts +13 -11
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +87 -44
- package/src/__tests__/server-history-render.test.ts +318 -2
- package/src/__tests__/shell-observability.test.ts +249 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +52 -21
- package/src/__tests__/skill-feature-flags.test.ts +20 -22
- package/src/__tests__/skill-load-feature-flag.test.ts +15 -15
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
- package/src/__tests__/skillssh-files.test.ts +1 -0
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/starter-task-flow.test.ts +6 -6
- package/src/__tests__/strip-memory-injections.test.ts +102 -14
- package/src/__tests__/subagent-call-site-routing.test.ts +14 -6
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +25 -12
- package/src/__tests__/subagent-fork-spawn.test.ts +14 -5
- package/src/__tests__/subagent-manager-notify.test.ts +21 -11
- package/src/__tests__/subagent-notify-parent.test.ts +6 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +59 -1
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +4 -3
- package/src/__tests__/sync-message-contract.test.ts +19 -16
- package/src/__tests__/system-prompt.test.ts +112 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +9 -25
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/thread-backfill.test.ts +4 -9
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +481 -15
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +1 -1
- package/src/__tests__/tools-audio-read.test.ts +113 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
- package/src/__tests__/turn-events-store.test.ts +11 -7
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +2 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +10 -7
- package/src/__tests__/voice-session-bridge.test.ts +56 -38
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +695 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +125 -0
- package/src/acp/auto-install.ts +174 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +52 -11
- package/src/acp/resolve-agent.test.ts +147 -6
- package/src/acp/resolve-agent.ts +81 -7
- package/src/acp/resume-hint.ts +22 -0
- package/src/acp/session-manager.ts +492 -77
- package/src/agent/compaction-circuit.ts +98 -0
- package/src/agent/loop.ts +730 -449
- package/src/api/README.md +126 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/constants/tool-execution.ts +21 -0
- package/src/api/events/assistant-activity-state.ts +75 -0
- package/src/api/events/assistant-outbound-attachment.ts +49 -0
- package/src/api/events/assistant-text-delta.ts +30 -0
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/assistant-turn-start.ts +31 -0
- package/src/api/events/avatar-updated.ts +24 -0
- package/src/api/events/compaction-circuit-closed.ts +26 -0
- package/src/api/events/compaction-circuit-open.ts +28 -0
- package/src/api/events/confirmation-request.ts +114 -0
- package/src/api/events/contact-request.ts +33 -0
- package/src/api/events/conversation-error.ts +77 -0
- package/src/api/events/conversation-list-invalidated.ts +38 -0
- package/src/api/events/conversation-title-updated.ts +24 -0
- package/src/api/events/disk-pressure-status-changed.ts +61 -0
- package/src/api/events/document-comment-created.ts +44 -0
- package/src/api/events/document-comment-deleted.ts +22 -0
- package/src/api/events/document-comment-reopened.ts +23 -0
- package/src/api/events/document-comment-resolved.ts +25 -0
- package/src/api/events/document-editor-update.ts +27 -0
- package/src/api/events/error.ts +32 -0
- package/src/api/events/generation-cancelled.ts +22 -0
- package/src/api/events/generation-handoff.ts +39 -0
- package/src/api/events/home-feed-updated.ts +26 -0
- package/src/api/events/identity-changed.ts +32 -0
- package/src/api/events/interaction-resolved.ts +50 -0
- package/src/api/events/message-complete.ts +40 -0
- package/src/api/events/message-dequeued.ts +21 -0
- package/src/api/events/message-queued-deleted.ts +23 -0
- package/src/api/events/message-queued.ts +22 -0
- package/src/api/events/message-request-complete.ts +29 -0
- package/src/api/events/navigate-settings.ts +20 -0
- package/src/api/events/notification-intent.ts +33 -0
- package/src/api/events/open-url.ts +28 -0
- package/src/api/events/question-request.ts +67 -0
- package/src/{events → api/events}/relationship-state-updated.ts +6 -8
- package/src/api/events/secret-request.ts +42 -0
- package/src/api/events/subagent-event.ts +79 -0
- package/src/api/events/subagent-spawned.ts +40 -0
- package/src/api/events/subagent-status-changed.ts +65 -0
- package/src/api/events/sync-changed.ts +29 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-result.ts +129 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/tool-use-start.ts +30 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/events/turn-profile-auto-routed.ts +28 -0
- package/src/api/events/ui-surface-complete.ts +30 -0
- package/src/api/events/ui-surface-dismiss.ts +22 -0
- package/src/api/events/ui-surface-show.ts +67 -0
- package/src/api/events/ui-surface-update.ts +26 -0
- package/src/api/events/usage-update.ts +34 -0
- package/src/api/events/user-message-echo.ts +35 -0
- package/src/api/index.ts +517 -3
- package/src/api/requests/dictation.ts +45 -0
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/api/responses/disk-pressure-status.ts +26 -0
- package/src/api/responses/home.ts +217 -0
- package/src/api/responses/llm-context-response.ts +41 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/api/responses/memory-v3-selection-log.ts +50 -0
- package/src/api/responses/subagent-detail.ts +48 -0
- package/src/approvals/guardian-decision-primitive.ts +7 -15
- package/src/approvals/guardian-request-resolvers.ts +7 -10
- package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
- package/src/avatar/__tests__/avatar-store.test.ts +198 -0
- package/src/avatar/avatar-manifest.ts +195 -0
- package/src/avatar/avatar-store.ts +113 -0
- package/src/avatar/traits-png-sync.ts +8 -2
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/next-wake.test.ts +31 -1
- package/src/background-wake/next-wake.ts +5 -1
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/call-conversation-messages.ts +6 -4
- package/src/calls/guardian-action-sweep.ts +6 -4
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/relay-server.ts +12 -8
- package/src/calls/voice-session-bridge.ts +17 -31
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
- package/src/cli/commands/__tests__/notifications.test.ts +242 -54
- package/src/cli/commands/avatar.ts +17 -11
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/conversations.ts +15 -1
- package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
- package/src/cli/commands/db/__tests__/status.test.ts +253 -0
- package/src/cli/commands/db/format.ts +48 -0
- package/src/cli/commands/db/index.ts +29 -0
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
- package/src/cli/commands/db/repair-step-integrity.ts +146 -0
- package/src/cli/commands/db/repair-steps.ts +164 -0
- package/src/cli/commands/db/repair.ts +141 -0
- package/src/cli/commands/db/status.ts +366 -0
- package/src/cli/commands/memory-v3.ts +168 -203
- package/src/cli/commands/notifications.ts +427 -65
- package/src/cli/lib/cli-colors.ts +24 -6
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +6 -5
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +4 -4
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +47 -55
- package/src/config/bundled-skills/acp/SKILL.md +64 -30
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -387
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +33 -24
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +10 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +3 -8
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +81 -25
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -211
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/call-site-catalog.ts +8 -15
- package/src/config/schemas/heartbeat.ts +10 -1
- package/src/config/schemas/llm.ts +93 -4
- package/src/config/schemas/memory-lifecycle.ts +24 -0
- package/src/config/schemas/memory-v2.ts +8 -227
- package/src/config/schemas/memory-v3.ts +47 -0
- package/src/config/schemas/memory.ts +6 -1
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/schemas/timeouts.ts +3 -1
- package/src/config/seed-inference-profiles.ts +38 -18
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +55 -32
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +52 -5
- package/src/context/tool-result-truncation.ts +1 -66
- package/src/context/window-manager.ts +141 -26
- package/src/credential-execution/executable-discovery.ts +56 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +9 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +15 -17
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +11 -8
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +11 -6
- package/src/daemon/approval-generators.ts +4 -4
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +7 -1
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +1146 -247
- package/src/daemon/conversation-agent-loop.ts +570 -1457
- package/src/daemon/conversation-error.ts +40 -12
- package/src/daemon/conversation-history.ts +27 -10
- package/src/daemon/conversation-launch.ts +4 -8
- package/src/daemon/conversation-lifecycle.ts +13 -42
- package/src/daemon/conversation-messaging.ts +89 -49
- package/src/daemon/conversation-notifiers.ts +7 -5
- package/src/daemon/conversation-process.ts +183 -130
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +209 -362
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +15 -95
- package/src/daemon/conversation-surfaces.ts +346 -107
- package/src/daemon/conversation-tool-setup.ts +38 -77
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +143 -186
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +7 -4
- package/src/daemon/disk-pressure-guard.ts +54 -50
- package/src/daemon/external-plugins-bootstrap.ts +53 -32
- package/src/daemon/first-greeting.ts +53 -13
- package/src/daemon/guardian-action-generators.ts +2 -2
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +9 -23
- package/src/daemon/handlers/shared.ts +158 -77
- package/src/daemon/handlers/skills.ts +53 -20
- package/src/daemon/host-app-control-proxy.ts +54 -1
- package/src/daemon/host-cu-proxy.ts +46 -22
- package/src/daemon/host-file-proxy.ts +25 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -6
- package/src/daemon/lifecycle.ts +65 -67
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-protocol.ts +2 -3
- package/src/daemon/message-provenance.ts +49 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/contacts.ts +3 -20
- package/src/daemon/message-types/conversations.ts +25 -125
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/documents.ts +3 -9
- package/src/daemon/message-types/home.ts +5 -18
- package/src/daemon/message-types/integrations.ts +4 -13
- package/src/daemon/message-types/messages.ts +50 -428
- package/src/daemon/message-types/notifications.ts +2 -32
- package/src/daemon/message-types/settings.ts +3 -8
- package/src/daemon/message-types/skills.ts +4 -0
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/surfaces.ts +138 -3
- package/src/daemon/message-types/sync.ts +12 -25
- package/src/daemon/message-types/workspace.ts +3 -11
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +59 -58
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +30 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/tool-side-effects.ts +10 -7
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +24 -2
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +34 -0
- package/src/heartbeat/heartbeat-run-store.ts +54 -1
- package/src/heartbeat/heartbeat-service.ts +105 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-types.ts +36 -221
- package/src/home/feed-writer.ts +146 -7
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/__tests__/email-ipc.test.ts +0 -9
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +6 -3
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
- package/src/ipc/routes/route-adapter.ts +45 -6
- package/src/ipc/skill-routes/__tests__/memory.test.ts +34 -9
- package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
- package/src/ipc/skill-routes/__tests__/registries.test.ts +59 -20
- package/src/ipc/skill-routes/memory.ts +29 -13
- package/src/ipc/skill-routes/providers.ts +5 -6
- package/src/ipc/skill-routes/registries.ts +39 -88
- package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/conversation-queries.test.ts +192 -8
- package/src/memory/__tests__/db-maintenance.test.ts +128 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +82 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +11 -6
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/context-search/agent-runner.ts +2 -4
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +386 -115
- package/src/memory/conversation-queries.ts +78 -22
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +18 -0
- package/src/memory/db-maintenance.ts +18 -2
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/consolidation.ts +8 -11
- package/src/memory/graph/conversation-graph-memory.ts +106 -8
- package/src/memory/graph/extraction.ts +6 -9
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/graph/retriever.ts +20 -26
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/job-handlers/conversation-starters.ts +45 -34
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/job-handlers/summarization.ts +1 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-store.ts +36 -1
- package/src/memory/jobs-worker.ts +93 -43
- package/src/memory/llm-request-log-source-clickhouse.ts +55 -1
- package/src/memory/llm-request-log-source-local.ts +13 -0
- package/src/memory/llm-request-log-source.ts +21 -6
- package/src/memory/llm-request-log-store.ts +147 -3
- package/src/memory/llm-usage-store.ts +234 -50
- package/src/memory/memory-marker.ts +17 -0
- package/src/memory/memory-retrospective-job.ts +6 -2
- package/src/memory/memory-v2-activation-log-store.ts +13 -1
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
- package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
- package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
- package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
- package/src/memory/migrations/index.ts +9 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +27 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +125 -1
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/migration.test.ts +11 -3
- package/src/memory/v2/__tests__/page-index.test.ts +37 -1
- package/src/memory/v2/__tests__/router.test.ts +14 -4
- package/src/memory/v2/__tests__/sweep-job.test.ts +9 -5
- package/src/memory/v2/backfill-jobs.ts +6 -0
- package/src/memory/v2/consolidation-job.ts +99 -10
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v2/migration.ts +5 -3
- package/src/memory/v2/page-index.ts +11 -0
- package/src/memory/v2/router.ts +8 -11
- package/src/memory/v2/sweep-job.ts +8 -11
- package/src/memory/v2/types.ts +1 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.ts +2 -2
- package/src/messaging/style-analyzer.ts +8 -11
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -8
- package/src/notifications/decision-engine.ts +16 -16
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/notifications/preference-extractor.ts +11 -14
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/permissions/prompter.ts +46 -36
- package/src/permissions/question-prompter.test.ts +35 -26
- package/src/permissions/question-prompter.ts +6 -10
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +10 -1
- package/src/plugin-api/types.ts +176 -4
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +15 -0
- package/src/plugins/defaults/compaction/register.ts +24 -0
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/package.json +15 -0
- package/src/plugins/defaults/empty-response/register.ts +23 -0
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/history-repair/package.json +15 -0
- package/src/plugins/defaults/history-repair/register.ts +24 -0
- package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
- package/src/plugins/defaults/index.ts +22 -49
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors.ts → memory-retrieval/injectors.ts} +297 -120
- package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +242 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +118 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +39 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +36 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +37 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +219 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +330 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +288 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +107 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +436 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +274 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +61 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +332 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +179 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +470 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +432 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +168 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +192 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +54 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +106 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +44 -0
- package/src/plugins/defaults/memory-v3-shadow/assign.ts +268 -0
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +124 -0
- package/src/plugins/defaults/memory-v3-shadow/core.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/data/README.md +84 -0
- package/src/plugins/defaults/memory-v3-shadow/data/assignments.json +5 -0
- package/src/plugins/defaults/memory-v3-shadow/data/core.json +1 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-x.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-y.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-b/topic-z.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +314 -0
- package/src/plugins/defaults/memory-v3-shadow/needle.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +126 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +15 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +34 -0
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +523 -0
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/router.ts +190 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +84 -0
- package/src/plugins/defaults/memory-v3-shadow/selector.ts +226 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +349 -0
- package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +209 -0
- package/src/plugins/defaults/memory-v3-shadow/tree.ts +174 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/working-set.ts +88 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +15 -0
- package/src/plugins/defaults/title-generate/register.ts +35 -0
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +15 -0
- package/src/plugins/defaults/tool-error/register.ts +23 -0
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +24 -0
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +132 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/pipeline.ts +8 -35
- package/src/plugins/registry.ts +8 -25
- package/src/plugins/types.ts +62 -677
- package/src/plugins/user-loader.ts +4 -3
- package/src/proactive-artifact/aux-message-injector.ts +4 -5
- package/src/proactive-artifact/job.test.ts +29 -21
- package/src/proactive-artifact/job.ts +3 -1
- package/src/prompts/__tests__/system-prompt.test.ts +46 -4
- package/src/prompts/sections.ts +20 -7
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
- package/src/prompts/templates/BOOTSTRAP.md +12 -12
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +21 -0
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -25
- package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
- package/src/providers/anthropic/client.ts +61 -34
- package/src/providers/call-site-routing.ts +34 -18
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +176 -37
- package/src/providers/gemini/inline-media.ts +74 -0
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +269 -7
- package/src/providers/openai/chat-completions-provider.ts +155 -16
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +54 -57
- package/src/providers/openrouter/client.ts +15 -14
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/providers/provider-send-message.ts +23 -14
- package/src/providers/ratelimit.ts +1 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -9
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +20 -2
- package/src/providers/usage-tracking.ts +1 -9
- package/src/runtime/__tests__/agent-wake.test.ts +142 -32
- package/src/runtime/__tests__/background-job-runner.test.ts +2 -3
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/agent-wake.ts +95 -23
- package/src/runtime/assistant-event-hub.ts +38 -8
- package/src/runtime/assistant-stream-state.ts +368 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
- package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
- package/src/runtime/auth/route-policy.ts +42 -1069
- package/src/runtime/background-job-runner.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -1
- package/src/runtime/channel-approvals.ts +4 -15
- package/src/runtime/channel-invite-transport.ts +5 -6
- package/src/runtime/channel-readiness-service.ts +70 -5
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +59 -30
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/http-router.ts +35 -43
- package/src/runtime/http-types.ts +23 -71
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/invite-instruction-generator.ts +3 -3
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/pending-interactions.ts +3 -2
- package/src/runtime/routes/__tests__/acp-routes.test.ts +253 -55
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +129 -1
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +26 -72
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +58 -5
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +297 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/__tests__/tts-routes.test.ts +9 -5
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/acp-routes.test.ts +186 -100
- package/src/runtime/routes/acp-routes.ts +110 -35
- package/src/runtime/routes/app-management-routes.ts +175 -106
- package/src/runtime/routes/app-routes.ts +38 -20
- package/src/runtime/routes/approval-routes.ts +17 -5
- package/src/runtime/routes/attachment-routes.ts +51 -16
- package/src/runtime/routes/audio-routes.ts +1 -0
- package/src/runtime/routes/audit-routes.ts +5 -0
- package/src/runtime/routes/auth-routes.ts +5 -0
- package/src/runtime/routes/avatar-routes.ts +264 -59
- package/src/runtime/routes/background-tool-routes.ts +9 -0
- package/src/runtime/routes/background-wake-routes.ts +201 -23
- package/src/runtime/routes/backup-routes.ts +45 -0
- package/src/runtime/routes/bookmark-routes.ts +13 -0
- package/src/runtime/routes/brain-graph-routes.ts +9 -0
- package/src/runtime/routes/browser-routes.ts +6 -1
- package/src/runtime/routes/browser-tabs-routes.ts +11 -10
- package/src/runtime/routes/btw-routes.ts +37 -27
- package/src/runtime/routes/cache-routes.ts +13 -0
- package/src/runtime/routes/call-routes.ts +21 -10
- package/src/runtime/routes/channel-availability-routes.ts +5 -1
- package/src/runtime/routes/channel-readiness-routes.ts +37 -4
- package/src/runtime/routes/channel-route-definitions.ts +21 -0
- package/src/runtime/routes/channel-verification-routes.ts +21 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
- package/src/runtime/routes/client-routes.ts +9 -0
- package/src/runtime/routes/consolidation-routes.ts +133 -25
- package/src/runtime/routes/contact-prompt-routes.ts +9 -0
- package/src/runtime/routes/contact-routes.ts +90 -23
- package/src/runtime/routes/content-source-routes.ts +5 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +11 -1
- package/src/runtime/routes/conversation-attention-routes.ts +5 -0
- package/src/runtime/routes/conversation-cli-routes.ts +54 -7
- package/src/runtime/routes/conversation-compaction-routes.ts +292 -0
- package/src/runtime/routes/conversation-list-routes.ts +225 -9
- package/src/runtime/routes/conversation-management-routes.ts +96 -28
- package/src/runtime/routes/conversation-query-routes.ts +150 -51
- package/src/runtime/routes/conversation-routes.ts +615 -327
- package/src/runtime/routes/conversation-starter-routes.ts +35 -20
- package/src/runtime/routes/conversations-import-routes.ts +48 -13
- package/src/runtime/routes/credential-prompt-routes.ts +5 -0
- package/src/runtime/routes/credential-routes.ts +25 -6
- package/src/runtime/routes/debug-bash-routes.ts +5 -0
- package/src/runtime/routes/debug-routes.ts +11 -2
- package/src/runtime/routes/defer-routes.ts +13 -0
- package/src/runtime/routes/diagnostics-routes.ts +37 -46
- package/src/runtime/routes/disk-pressure-routes.ts +17 -31
- package/src/runtime/routes/document-comments-routes.ts +46 -27
- package/src/runtime/routes/documents-routes.ts +35 -11
- package/src/runtime/routes/domain-routes.ts +98 -51
- package/src/runtime/routes/email-routes.ts +33 -0
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +107 -8
- package/src/runtime/routes/filing-routes.ts +9 -4
- package/src/runtime/routes/gateway-log-routes.ts +31 -4
- package/src/runtime/routes/global-search-routes.ts +53 -50
- package/src/runtime/routes/group-routes.ts +32 -5
- package/src/runtime/routes/guardian-action-routes.ts +9 -0
- package/src/runtime/routes/guardian-approval-interception.ts +0 -31
- package/src/runtime/routes/heartbeat-routes.ts +57 -21
- package/src/runtime/routes/home-feed-routes.ts +149 -16
- package/src/runtime/routes/home-state-routes.ts +8 -40
- package/src/runtime/routes/host-app-control-routes.ts +6 -1
- package/src/runtime/routes/host-bash-routes.ts +5 -0
- package/src/runtime/routes/host-browser-routes.ts +13 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +26 -6
- package/src/runtime/routes/host-transfer-routes.ts +13 -2
- package/src/runtime/routes/http-adapter.ts +1 -2
- package/src/runtime/routes/identity-intro-cache.ts +72 -39
- package/src/runtime/routes/identity-routes.ts +257 -20
- package/src/runtime/routes/image-generation-routes.ts +45 -2
- package/src/runtime/routes/inbound-message-handler.ts +16 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +524 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +72 -27
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
- package/src/runtime/routes/inference-provider-connection-routes.ts +26 -31
- package/src/runtime/routes/inference-send-routes.ts +11 -11
- package/src/runtime/routes/integrations/a2a.ts +32 -7
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +23 -3
- package/src/runtime/routes/integrations/slack/share.ts +36 -8
- package/src/runtime/routes/integrations/telegram.ts +34 -9
- package/src/runtime/routes/integrations/twilio.ts +77 -7
- package/src/runtime/routes/integrations/vercel.ts +18 -3
- package/src/runtime/routes/internal-oauth-routes.ts +5 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/internal-twilio-routes.ts +13 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/log-export-routes.ts +36 -10
- package/src/runtime/routes/mcp-auth-routes.ts +25 -0
- package/src/runtime/routes/memory-item-routes.ts +21 -10
- package/src/runtime/routes/memory-v2-routes.ts +105 -44
- package/src/runtime/routes/memory-v3-routes.ts +313 -257
- package/src/runtime/routes/migration-rollback-routes.ts +5 -1
- package/src/runtime/routes/migration-routes.ts +49 -13
- package/src/runtime/routes/notification-routes.ts +80 -2
- package/src/runtime/routes/oauth-apps.ts +99 -23
- package/src/runtime/routes/oauth-commands-routes.ts +43 -15
- package/src/runtime/routes/oauth-connect-routes.ts +9 -0
- package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
- package/src/runtime/routes/oauth-providers.ts +79 -15
- package/src/runtime/routes/platform-routes.ts +102 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +9 -6
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
- package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
- package/src/runtime/routes/playground/force-compact.ts +2 -2
- package/src/runtime/routes/playground/helpers.ts +1 -2
- package/src/runtime/routes/playground/inject-failures.ts +13 -8
- package/src/runtime/routes/playground/reset-circuit.ts +14 -9
- package/src/runtime/routes/playground/seed-conversation.ts +1 -1
- package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
- package/src/runtime/routes/playground/state.ts +4 -3
- package/src/runtime/routes/plugins-routes.ts +22 -19
- package/src/runtime/routes/profiler-routes.ts +17 -4
- package/src/runtime/routes/ps-routes.ts +5 -0
- package/src/runtime/routes/publish-routes.ts +13 -3
- package/src/runtime/routes/question-routes.ts +5 -0
- package/src/runtime/routes/recording-routes.ts +25 -12
- package/src/runtime/routes/rename-conversation-routes.ts +10 -0
- package/src/runtime/routes/sanity-routes.ts +9 -2
- package/src/runtime/routes/schedule-routes.ts +288 -88
- package/src/runtime/routes/secret-routes.ts +31 -6
- package/src/runtime/routes/sequence-routes.ts +33 -0
- package/src/runtime/routes/settings-routes.ts +65 -19
- package/src/runtime/routes/skills-routes.ts +166 -73
- package/src/runtime/routes/slack-channel-routes.ts +5 -0
- package/src/runtime/routes/stt-routes.ts +13 -6
- package/src/runtime/routes/subagents-routes.ts +24 -18
- package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
- package/src/runtime/routes/surface-action-routes.ts +10 -38
- package/src/runtime/routes/surface-content-routes.ts +21 -6
- package/src/runtime/routes/surface-conversation-resolver.ts +66 -0
- package/src/runtime/routes/task-routes.ts +37 -0
- package/src/runtime/routes/telemetry-routes.ts +9 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trace-event-routes.ts +42 -1
- package/src/runtime/routes/trust-rules-routes.ts +31 -2
- package/src/runtime/routes/tts-routes.ts +48 -6
- package/src/runtime/routes/types.ts +83 -16
- package/src/runtime/routes/ui-request-routes.ts +5 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
- package/src/runtime/routes/usage-routes.ts +118 -42
- package/src/runtime/routes/user-routes-cli.ts +9 -0
- package/src/runtime/routes/user-routes.ts +5 -1
- package/src/runtime/routes/wake-conversation-routes.ts +5 -0
- package/src/runtime/routes/watcher-routes.ts +21 -0
- package/src/runtime/routes/webhook-routes.ts +50 -2
- package/src/runtime/routes/wipe-conversation-routes.ts +8 -0
- package/src/runtime/routes/work-items-routes.ts +49 -23
- package/src/runtime/routes/workspace-commit-routes.ts +5 -0
- package/src/runtime/routes/workspace-routes.test.ts +42 -0
- package/src/runtime/routes/workspace-routes.ts +124 -9
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +10 -4
- package/src/runtime/services/analyze-conversation.ts +5 -8
- package/src/runtime/services/conversation-serializer.ts +24 -2
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +17 -3
- package/src/runtime/sync/sync-publisher.ts +2 -2
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/run-script.ts +28 -3
- package/src/schedule/schedule-store.ts +36 -2
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +126 -21
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/cancel.ts +2 -4
- package/src/signals/user-message.ts +10 -16
- package/src/skills/catalog-files.ts +4 -1
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -0
- package/src/skills/skillssh-files.ts +1 -0
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +33 -24
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/telemetry/types.ts +55 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +250 -4
- package/src/telemetry/usage-telemetry-reporter.ts +88 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +198 -93
- package/src/tools/acp/spawn.ts +32 -70
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/definitions.ts +42 -24
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
- package/src/tools/ask-question/ask-question-tool.ts +85 -90
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +295 -289
- package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
- package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
- package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
- package/src/tools/credentials/vault.ts +112 -111
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +3 -6
- package/src/tools/execution-timeout.ts +3 -4
- package/src/tools/executor.ts +18 -107
- package/src/tools/filesystem/edit.ts +45 -42
- package/src/tools/filesystem/list.ts +33 -30
- package/src/tools/filesystem/read.ts +54 -35
- package/src/tools/filesystem/write.ts +69 -32
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/edit.ts +44 -42
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/read.ts +49 -35
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/transfer.ts +121 -108
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/host-filesystem/write.ts +33 -31
- package/src/tools/host-terminal/host-shell.ts +50 -48
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/memory/register.ts +23 -24
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +222 -6
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-fetch.ts +49 -46
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +414 -97
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +184 -118
- package/src/tools/schedule/create.ts +14 -1
- package/src/tools/schedule/update.ts +16 -0
- package/src/tools/shared/filesystem/audio-read.ts +122 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/execute.ts +34 -31
- package/src/tools/skills/load.ts +29 -23
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/notify-parent.ts +35 -32
- package/src/tools/subagent/spawn.ts +2 -1
- package/src/tools/system/avatar-generator.ts +13 -22
- package/src/tools/system/request-permission.ts +30 -27
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/terminal/shell.ts +190 -61
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-defaults.ts +20 -9
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +86 -33
- package/src/tools/ui-surface/definitions.ts +196 -95
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/usage/types.ts +10 -0
- package/src/util/browser.ts +7 -2
- package/src/util/errors.ts +2 -2
- package/src/util/map-limit.ts +27 -0
- package/src/util/mutex.ts +47 -0
- package/src/util/platform.ts +15 -12
- package/src/work-items/work-item-runner.ts +7 -2
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
- package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
- package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
- package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +15 -17
- package/tsconfig.json +4 -1
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -262
- package/src/__tests__/empty-response-pipeline.test.ts +0 -301
- package/src/__tests__/history-repair-pipeline.test.ts +0 -396
- package/src/__tests__/llm-call-pipeline.test.ts +0 -281
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -376
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -481
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -344
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
- package/src/cli/commands/memory-v3-render.ts +0 -344
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/daemon/message-types/disk-pressure.ts +0 -9
- package/src/email/feature-gate.ts +0 -23
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
- package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -468
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
- package/src/memory/v3/__tests__/edges.test.ts +0 -563
- package/src/memory/v3/__tests__/filter.test.ts +0 -512
- package/src/memory/v3/__tests__/gate.test.ts +0 -574
- package/src/memory/v3/__tests__/index-composition.test.ts +0 -233
- package/src/memory/v3/__tests__/loop.test.ts +0 -530
- package/src/memory/v3/__tests__/retriever.test.ts +0 -226
- package/src/memory/v3/__tests__/scouts.test.ts +0 -440
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -312
- package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
- package/src/memory/v3/__tests__/traversal.test.ts +0 -469
- package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
- package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
- package/src/memory/v3/__tests__/tree-walk.test.ts +0 -707
- package/src/memory/v3/__tests__/validate.test.ts +0 -245
- package/src/memory/v3/auto-edges.ts +0 -223
- package/src/memory/v3/coactivation-store.ts +0 -124
- package/src/memory/v3/consolidation-job.ts +0 -323
- package/src/memory/v3/edge-learning-job.ts +0 -160
- package/src/memory/v3/edges.ts +0 -249
- package/src/memory/v3/filter.ts +0 -281
- package/src/memory/v3/gate.ts +0 -334
- package/src/memory/v3/index-composition.ts +0 -113
- package/src/memory/v3/llm-capture.ts +0 -46
- package/src/memory/v3/loop.ts +0 -382
- package/src/memory/v3/maintenance.ts +0 -144
- package/src/memory/v3/prompt-context.ts +0 -33
- package/src/memory/v3/prompts/consolidation.ts +0 -458
- package/src/memory/v3/prompts/system-prompts.ts +0 -196
- package/src/memory/v3/retriever.ts +0 -33
- package/src/memory/v3/scouts.ts +0 -420
- package/src/memory/v3/shadow-middleware.ts +0 -305
- package/src/memory/v3/traversal.ts +0 -206
- package/src/memory/v3/tree-index.ts +0 -237
- package/src/memory/v3/tree-store.ts +0 -394
- package/src/memory/v3/tree-walk.ts +0 -351
- package/src/memory/v3/types.ts +0 -65
- package/src/memory/v3/validate.ts +0 -300
- package/src/plugins/defaults/circuit-breaker.ts +0 -141
- package/src/plugins/defaults/compaction.ts +0 -141
- package/src/plugins/defaults/empty-response.ts +0 -124
- package/src/plugins/defaults/history-repair.ts +0 -83
- package/src/plugins/defaults/llm-call.ts +0 -77
- package/src/plugins/defaults/memory-retrieval.ts +0 -219
- package/src/plugins/defaults/overflow-reduce.ts +0 -185
- package/src/plugins/defaults/persistence.ts +0 -127
- package/src/plugins/defaults/title-generate.ts +0 -90
- package/src/plugins/defaults/token-estimate.ts +0 -101
- package/src/plugins/defaults/tool-error.ts +0 -119
- package/src/plugins/defaults/tool-execute.ts +0 -87
- package/src/plugins/defaults/tool-result-truncate.ts +0 -84
- package/src/skills/category-inference.ts +0 -111
|
@@ -14,15 +14,11 @@
|
|
|
14
14
|
import { createRequire } from "node:module";
|
|
15
15
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
16
16
|
|
|
17
|
-
import type {
|
|
18
|
-
AgentEvent,
|
|
19
|
-
CheckpointDecision,
|
|
20
|
-
CheckpointInfo,
|
|
21
|
-
} from "../agent/loop.js";
|
|
17
|
+
import type { LoopToolExecutor } from "../agent/loop.js";
|
|
22
18
|
import type { LLMConfig } from "../config/schemas/llm.js";
|
|
23
19
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
24
20
|
import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
|
|
25
|
-
import type {
|
|
21
|
+
import type { Message, Provider, ToolDefinition } from "../providers/types.js";
|
|
26
22
|
|
|
27
23
|
const conversationCrudRealSnapshot = {
|
|
28
24
|
...(createRequire(import.meta.url)(
|
|
@@ -91,6 +87,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
91
87
|
memory: { retrieval: { scratchpadInjection: { enabled: true } } },
|
|
92
88
|
ui: {},
|
|
93
89
|
compaction: { enabled: true, autoThreshold: 0.7 },
|
|
90
|
+
conversations: { skipAutoRetitling: true },
|
|
94
91
|
}),
|
|
95
92
|
loadRawConfig: () => ({}),
|
|
96
93
|
saveRawConfig: () => {},
|
|
@@ -102,10 +99,10 @@ mock.module("../config/loader.js", () => ({
|
|
|
102
99
|
// Token estimator — controllable per-test via mockEstimateTokens.
|
|
103
100
|
// Can be a number (constant), a no-arg function, or a function that
|
|
104
101
|
// receives the messages array for dynamic behavior based on content.
|
|
105
|
-
// Both the calibrated entry point (`estimatePromptTokens`,
|
|
106
|
-
// convergence path) and the raw entry point
|
|
107
|
-
// used by the
|
|
108
|
-
//
|
|
102
|
+
// Both the calibrated entry point (`estimatePromptTokens`, which backs the
|
|
103
|
+
// preflight overflow gate and the convergence path) and the raw entry point
|
|
104
|
+
// (`estimatePromptTokensRaw`, used by the pre-send calibration capture) are
|
|
105
|
+
// stubbed so either call site can drive the test.
|
|
109
106
|
let mockEstimateTokens: number | ((msgs?: Message[]) => number) = 1000;
|
|
110
107
|
mock.module("../context/token-estimator.js", () => ({
|
|
111
108
|
estimatePromptTokens: (msgs: Message[]) =>
|
|
@@ -116,8 +113,16 @@ mock.module("../context/token-estimator.js", () => ({
|
|
|
116
113
|
typeof mockEstimateTokens === "function"
|
|
117
114
|
? mockEstimateTokens(msgs)
|
|
118
115
|
: mockEstimateTokens,
|
|
119
|
-
//
|
|
120
|
-
//
|
|
116
|
+
// The preflight overflow gate calls this calibrated wrapper directly, so it
|
|
117
|
+
// must honor `mockEstimateTokens` too — otherwise the real implementation
|
|
118
|
+
// (which sums tool tokens onto the real calibrated estimate) ignores the
|
|
119
|
+
// per-test value and the overflow scenarios below never trigger.
|
|
120
|
+
estimatePromptTokensWithTools: (history: Message[]) =>
|
|
121
|
+
typeof mockEstimateTokens === "function"
|
|
122
|
+
? mockEstimateTokens(history)
|
|
123
|
+
: mockEstimateTokens,
|
|
124
|
+
// `estimatePromptTokensWithTools` folds tool tokens in via this helper; 0
|
|
125
|
+
// keeps the stubbed value unchanged.
|
|
121
126
|
estimateToolsTokens: () => 0,
|
|
122
127
|
// Conversation agent loop now calls this helper to canonicalize the
|
|
123
128
|
// provider key shared with the calibration system. The tests here
|
|
@@ -198,6 +203,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
198
203
|
setLastNotifiedInferenceProfile: () => {},
|
|
199
204
|
getLastUserTimestampBefore: () => 0,
|
|
200
205
|
getConversationOverrideProfileFromRow: () => undefined,
|
|
206
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
201
207
|
}));
|
|
202
208
|
|
|
203
209
|
afterAll(() => {
|
|
@@ -268,15 +274,6 @@ mock.module("../daemon/conversation-runtime-assembly.js", () => ({
|
|
|
268
274
|
blocks: {},
|
|
269
275
|
}),
|
|
270
276
|
stripInjectionsForCompaction: (msgs: Message[]) => msgs,
|
|
271
|
-
findLastInjectedNowContent: () => null,
|
|
272
|
-
readNowScratchpad: () => null,
|
|
273
|
-
readPkbContext: () => null,
|
|
274
|
-
getPkbAutoInjectList: () => [
|
|
275
|
-
"INDEX.md",
|
|
276
|
-
"essentials.md",
|
|
277
|
-
"threads.md",
|
|
278
|
-
"buffer.md",
|
|
279
|
-
],
|
|
280
277
|
isSlackChannelConversation: () => false,
|
|
281
278
|
getSlackCompactionWatermarkForPrefix: () => null,
|
|
282
279
|
loadSlackChronologicalContext: () => null,
|
|
@@ -290,7 +287,7 @@ mock.module("../daemon/date-context.js", () => ({
|
|
|
290
287
|
formatTurnTimestamp: () => "2026-01-01 (Thursday) 00:00:00 +00:00 (UTC)",
|
|
291
288
|
}));
|
|
292
289
|
|
|
293
|
-
mock.module("../
|
|
290
|
+
mock.module("../plugins/defaults/history-repair/terminal.js", () => ({
|
|
294
291
|
repairHistory: (msgs: Message[]) => ({
|
|
295
292
|
messages: msgs,
|
|
296
293
|
stats: {
|
|
@@ -424,37 +421,55 @@ mock.module("../memory/archive-store.js", () => ({
|
|
|
424
421
|
|
|
425
422
|
// ── Imports (after mocks) ────────────────────────────────────────────
|
|
426
423
|
|
|
424
|
+
import { AgentLoop } from "../agent/loop.js";
|
|
427
425
|
import {
|
|
428
426
|
type AgentLoopConversationContext,
|
|
429
427
|
runAgentLoopImpl,
|
|
430
428
|
} from "../daemon/conversation-agent-loop.js";
|
|
429
|
+
import {
|
|
430
|
+
createMockProvider,
|
|
431
|
+
type ScriptedResponse,
|
|
432
|
+
textResponse,
|
|
433
|
+
toolUseResponse,
|
|
434
|
+
} from "./helpers/mock-provider.js";
|
|
431
435
|
|
|
432
436
|
// ── Test helpers ─────────────────────────────────────────────────────
|
|
433
437
|
|
|
434
|
-
type AgentLoopRun = (
|
|
435
|
-
messages: Message[],
|
|
436
|
-
onEvent: (event: AgentEvent) => void,
|
|
437
|
-
signal?: AbortSignal,
|
|
438
|
-
requestId?: string,
|
|
439
|
-
onCheckpoint?: (
|
|
440
|
-
checkpoint: CheckpointInfo,
|
|
441
|
-
) => CheckpointDecision | Promise<CheckpointDecision>,
|
|
442
|
-
) => Promise<Message[]>;
|
|
443
|
-
|
|
444
438
|
function makeCtx(
|
|
445
439
|
overrides?: Partial<AgentLoopConversationContext> & {
|
|
446
|
-
|
|
440
|
+
providerResponses?: ScriptedResponse[];
|
|
441
|
+
loopProvider?: Provider;
|
|
442
|
+
loopTools?: ToolDefinition[];
|
|
443
|
+
toolExecutor?: LoopToolExecutor;
|
|
447
444
|
},
|
|
448
445
|
): AgentLoopConversationContext {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
446
|
+
const {
|
|
447
|
+
providerResponses,
|
|
448
|
+
loopProvider,
|
|
449
|
+
loopTools,
|
|
450
|
+
toolExecutor,
|
|
451
|
+
...ctxOverrides
|
|
452
|
+
} = overrides ?? {};
|
|
453
|
+
const conversationId = ctxOverrides.conversationId ?? "test-conv";
|
|
454
|
+
|
|
455
|
+
// Drive the real `AgentLoop` against a scripted provider, mocking only the
|
|
456
|
+
// provider HTTP boundary. The loop owns its mid-loop budget gate, inline
|
|
457
|
+
// compaction, and event emission, so these overflow tests exercise the real
|
|
458
|
+
// escalation/persistence path.
|
|
459
|
+
const loopProviderName =
|
|
460
|
+
(ctxOverrides.provider as { name?: string } | undefined)?.name ??
|
|
461
|
+
"mock-provider";
|
|
462
|
+
const provider =
|
|
463
|
+
loopProvider ??
|
|
464
|
+
createMockProvider(
|
|
465
|
+
providerResponses ?? [textResponse("response")],
|
|
466
|
+
loopProviderName,
|
|
467
|
+
).provider;
|
|
468
|
+
const agentLoop = new AgentLoop(provider, "system prompt", {
|
|
469
|
+
conversationId,
|
|
470
|
+
tools: loopTools ?? [],
|
|
471
|
+
toolExecutor,
|
|
472
|
+
});
|
|
458
473
|
|
|
459
474
|
return {
|
|
460
475
|
conversationId: "test-conv",
|
|
@@ -462,18 +477,16 @@ function makeCtx(
|
|
|
462
477
|
{ role: "user", content: [{ type: "text", text: "Hello" }] },
|
|
463
478
|
] as Message[],
|
|
464
479
|
processing: true,
|
|
480
|
+
isProcessing(this: { processing: boolean }) {
|
|
481
|
+
return this.processing;
|
|
482
|
+
},
|
|
483
|
+
setProcessing(this: { processing: boolean }, value: boolean) {
|
|
484
|
+
this.processing = value;
|
|
485
|
+
},
|
|
465
486
|
abortController: new AbortController(),
|
|
466
487
|
currentRequestId: "test-req",
|
|
467
488
|
|
|
468
|
-
agentLoop
|
|
469
|
-
run: agentLoopRun,
|
|
470
|
-
getToolTokenBudget: () => 0,
|
|
471
|
-
getResolvedTools: () => [],
|
|
472
|
-
// Tests in this file don't exercise calibration, so returning
|
|
473
|
-
// undefined is fine — the estimator falls back to the per-provider
|
|
474
|
-
// aggregate key.
|
|
475
|
-
getActiveModel: () => undefined,
|
|
476
|
-
} as unknown as AgentLoopConversationContext["agentLoop"],
|
|
489
|
+
agentLoop,
|
|
477
490
|
provider: {
|
|
478
491
|
name: "mock-provider",
|
|
479
492
|
sendMessage: async () => ({
|
|
@@ -502,8 +515,6 @@ function makeCtx(
|
|
|
502
515
|
currentTurnSurfaces: [],
|
|
503
516
|
|
|
504
517
|
workingDir: "/tmp",
|
|
505
|
-
workspaceTopLevelContext: null,
|
|
506
|
-
workspaceTopLevelDirty: false,
|
|
507
518
|
channelCapabilities: undefined,
|
|
508
519
|
commandIntent: undefined,
|
|
509
520
|
trustContext: undefined,
|
|
@@ -540,7 +551,6 @@ function makeCtx(
|
|
|
540
551
|
getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
|
|
541
552
|
commitTurnChanges: async () => {},
|
|
542
553
|
|
|
543
|
-
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
544
554
|
markWorkspaceTopLevelDirty: () => {},
|
|
545
555
|
emitActivityState: () => {},
|
|
546
556
|
getQueueDepth: () => 0,
|
|
@@ -566,9 +576,10 @@ function makeCtx(
|
|
|
566
576
|
injectedTokens: 0,
|
|
567
577
|
}),
|
|
568
578
|
retrackCachedNodes: () => {},
|
|
579
|
+
recordPkbQueryVectors: () => {},
|
|
569
580
|
} as unknown as AgentLoopConversationContext["graphMemory"],
|
|
570
581
|
|
|
571
|
-
...
|
|
582
|
+
...ctxOverrides,
|
|
572
583
|
} as AgentLoopConversationContext;
|
|
573
584
|
}
|
|
574
585
|
|
|
@@ -637,15 +648,15 @@ beforeEach(() => {
|
|
|
637
648
|
recordUsageMock.mockClear();
|
|
638
649
|
setAgentLoopExitReasonOnLatestLogMock.mockClear();
|
|
639
650
|
addMessageMock.mockClear();
|
|
640
|
-
// Reset the plugin registry and re-register every default so the
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
// (`reduceContextOverflow`, `syncMessageToDisk`, …) these tests install.
|
|
651
|
+
// Reset the plugin registry and re-register every default so the compaction
|
|
652
|
+
// pipeline dispatches to the default middleware, which in turn hits the
|
|
653
|
+
// mocked collaborators (`syncMessageToDisk`, …) these tests install.
|
|
644
654
|
resetPluginRegistryAndRegisterDefaults();
|
|
645
655
|
});
|
|
646
656
|
|
|
647
657
|
describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
648
658
|
test("usage update context max follows active main-agent profile budget", async () => {
|
|
659
|
+
// GIVEN an active main-agent profile that narrows the context budget
|
|
649
660
|
mockLlmConfig = {
|
|
650
661
|
...structuredClone(defaultLlmConfig),
|
|
651
662
|
activeProfile: "short-context",
|
|
@@ -657,27 +668,22 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
657
668
|
},
|
|
658
669
|
};
|
|
659
670
|
|
|
671
|
+
// AND a provider turn that reports 12k input tokens of usage
|
|
660
672
|
const ctx = makeCtx({
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
type: "
|
|
664
|
-
inputTokens: 12_000,
|
|
665
|
-
outputTokens: 300,
|
|
673
|
+
providerResponses: [
|
|
674
|
+
{
|
|
675
|
+
content: [{ type: "text", text: "response" }],
|
|
666
676
|
model: "mock-model",
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
{
|
|
672
|
-
role: "assistant" as const,
|
|
673
|
-
content: [{ type: "text" as const, text: "response" }],
|
|
674
|
-
},
|
|
675
|
-
];
|
|
676
|
-
},
|
|
677
|
+
usage: { inputTokens: 12_000, outputTokens: 300 },
|
|
678
|
+
stopReason: "end_turn",
|
|
679
|
+
},
|
|
680
|
+
],
|
|
677
681
|
});
|
|
678
682
|
|
|
683
|
+
// WHEN the turn runs to completion
|
|
679
684
|
await runAgentLoopImpl(ctx, "hello", "msg-1", () => {});
|
|
680
685
|
|
|
686
|
+
// THEN the recorded main-agent usage carries the profile's max budget
|
|
681
687
|
const mainAgentUsageCall = recordUsageMock.mock.calls.find(
|
|
682
688
|
(call) => call[5] === "main_agent",
|
|
683
689
|
);
|
|
@@ -690,10 +696,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
690
696
|
|
|
691
697
|
// ── Test 1 ────────────────────────────────────────────────────────
|
|
692
698
|
// BUG: When the agent loop makes progress (adds messages to history)
|
|
693
|
-
// before hitting context_too_large, the convergence loop
|
|
694
|
-
//
|
|
695
|
-
//
|
|
696
|
-
// invoked — the error is surfaced immediately at line 1163-1175
|
|
699
|
+
// before hitting context_too_large, the convergence loop's progress
|
|
700
|
+
// check must recognize that the loop appended messages. If it fails to,
|
|
701
|
+
// the reducer is never invoked — the error is surfaced immediately
|
|
697
702
|
// without any compaction attempt.
|
|
698
703
|
//
|
|
699
704
|
// Expected behavior (PR 2 fix): After progress + context_too_large,
|
|
@@ -733,122 +738,31 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
733
738
|
};
|
|
734
739
|
};
|
|
735
740
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
{
|
|
745
|
-
role: "assistant" as const,
|
|
746
|
-
content: [
|
|
747
|
-
{ type: "text", text: "Let me check that." },
|
|
748
|
-
{
|
|
749
|
-
type: "tool_use",
|
|
750
|
-
id: "tu-progress",
|
|
751
|
-
name: "bash",
|
|
752
|
-
input: { command: "ls" },
|
|
753
|
-
},
|
|
754
|
-
] as ContentBlock[],
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
role: "user" as const,
|
|
758
|
-
content: [
|
|
759
|
-
{
|
|
760
|
-
type: "tool_result",
|
|
761
|
-
tool_use_id: "tu-progress",
|
|
762
|
-
content: "file1.ts\nfile2.ts",
|
|
763
|
-
is_error: false,
|
|
764
|
-
},
|
|
765
|
-
] as ContentBlock[],
|
|
766
|
-
},
|
|
767
|
-
];
|
|
741
|
+
// Run 1 makes progress (a tool turn) then the following provider call
|
|
742
|
+
// rejects with a context_too_large error; after the convergence reducer
|
|
743
|
+
// compacts, the rerun recovers with plain text.
|
|
744
|
+
const { provider } = createMockProvider([
|
|
745
|
+
toolUseResponse("tu-progress", "bash", { command: "ls" }),
|
|
746
|
+
new Error("prompt is too long: 242201 tokens > 200000 maximum"),
|
|
747
|
+
textResponse("recovered after compaction"),
|
|
748
|
+
]);
|
|
768
749
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
750
|
+
const ctx = makeCtx({
|
|
751
|
+
loopProvider: provider,
|
|
752
|
+
loopTools: [
|
|
753
|
+
{
|
|
773
754
|
name: "bash",
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
toolUseId: "tu-progress",
|
|
779
|
-
content: "file1.ts\nfile2.ts",
|
|
780
|
-
isError: false,
|
|
781
|
-
});
|
|
782
|
-
onEvent({
|
|
783
|
-
type: "message_complete",
|
|
784
|
-
message: {
|
|
785
|
-
role: "assistant",
|
|
786
|
-
content: [
|
|
787
|
-
{ type: "text", text: "Let me check that." },
|
|
788
|
-
{
|
|
789
|
-
type: "tool_use",
|
|
790
|
-
id: "tu-progress",
|
|
791
|
-
name: "bash",
|
|
792
|
-
input: { command: "ls" },
|
|
793
|
-
},
|
|
794
|
-
],
|
|
755
|
+
description: "Run a shell command",
|
|
756
|
+
input_schema: {
|
|
757
|
+
type: "object",
|
|
758
|
+
properties: { command: { type: "string" } },
|
|
795
759
|
},
|
|
796
|
-
});
|
|
797
|
-
onEvent({
|
|
798
|
-
type: "usage",
|
|
799
|
-
inputTokens: 100,
|
|
800
|
-
outputTokens: 50,
|
|
801
|
-
model: "test-model",
|
|
802
|
-
providerDurationMs: 100,
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
// Then context_too_large error occurs on the *next* LLM call
|
|
806
|
-
onEvent({
|
|
807
|
-
type: "error",
|
|
808
|
-
error: new Error(
|
|
809
|
-
"prompt is too long: 242201 tokens > 200000 maximum",
|
|
810
|
-
),
|
|
811
|
-
});
|
|
812
|
-
onEvent({
|
|
813
|
-
type: "usage",
|
|
814
|
-
inputTokens: 0,
|
|
815
|
-
outputTokens: 0,
|
|
816
|
-
model: "test-model",
|
|
817
|
-
providerDurationMs: 10,
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
// Return the history WITH progress (more messages than input)
|
|
821
|
-
return progressMessages;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// Second call (after compaction): succeed
|
|
825
|
-
onEvent({
|
|
826
|
-
type: "message_complete",
|
|
827
|
-
message: {
|
|
828
|
-
role: "assistant",
|
|
829
|
-
content: [{ type: "text", text: "recovered after compaction" }],
|
|
830
760
|
},
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
model: "test-model",
|
|
837
|
-
providerDurationMs: 100,
|
|
838
|
-
});
|
|
839
|
-
return [
|
|
840
|
-
...messages,
|
|
841
|
-
{
|
|
842
|
-
role: "assistant" as const,
|
|
843
|
-
content: [
|
|
844
|
-
{ type: "text", text: "recovered after compaction" },
|
|
845
|
-
] as ContentBlock[],
|
|
846
|
-
},
|
|
847
|
-
];
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
const ctx = makeCtx({
|
|
851
|
-
agentLoopRun,
|
|
761
|
+
],
|
|
762
|
+
toolExecutor: async () => ({
|
|
763
|
+
content: "file1.ts\nfile2.ts",
|
|
764
|
+
isError: false,
|
|
765
|
+
}),
|
|
852
766
|
contextWindowManager: {
|
|
853
767
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
854
768
|
maybeCompact: async () => ({ compacted: false }),
|
|
@@ -877,13 +791,14 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
877
791
|
// This test should PASS against current code (when no progress is made).
|
|
878
792
|
test("overflow recovery compacts below limit even when estimation underestimates", async () => {
|
|
879
793
|
const events: ServerMessage[] = [];
|
|
880
|
-
let callCount = 0;
|
|
881
794
|
let reducerCalled = false;
|
|
882
795
|
|
|
883
|
-
//
|
|
796
|
+
// GIVEN the estimator reports 185k — under the 190k preflight budget
|
|
797
|
+
// (200k * 0.95), so the turn proceeds to the provider rather than
|
|
798
|
+
// compacting up front.
|
|
884
799
|
mockEstimateTokens = 185_000;
|
|
885
800
|
|
|
886
|
-
//
|
|
801
|
+
// AND the post-run convergence reducer successfully compacts
|
|
887
802
|
mockReducerStepFn = (msgs: Message[]) => {
|
|
888
803
|
reducerCalled = true;
|
|
889
804
|
return {
|
|
@@ -913,93 +828,46 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
913
828
|
};
|
|
914
829
|
};
|
|
915
830
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
type: "error",
|
|
923
|
-
error: new Error(
|
|
924
|
-
"prompt is too long: 242201 tokens > 200000 maximum",
|
|
925
|
-
),
|
|
926
|
-
});
|
|
927
|
-
onEvent({
|
|
928
|
-
type: "usage",
|
|
929
|
-
inputTokens: 0,
|
|
930
|
-
outputTokens: 0,
|
|
931
|
-
model: "test-model",
|
|
932
|
-
providerDurationMs: 10,
|
|
933
|
-
});
|
|
934
|
-
// No progress — return same messages
|
|
935
|
-
return messages;
|
|
936
|
-
}
|
|
937
|
-
// Second call succeeds
|
|
938
|
-
onEvent({
|
|
939
|
-
type: "message_complete",
|
|
940
|
-
message: {
|
|
941
|
-
role: "assistant",
|
|
942
|
-
content: [{ type: "text", text: "recovered" }],
|
|
943
|
-
},
|
|
944
|
-
});
|
|
945
|
-
onEvent({
|
|
946
|
-
type: "usage",
|
|
947
|
-
inputTokens: 80_000,
|
|
948
|
-
outputTokens: 200,
|
|
949
|
-
model: "test-model",
|
|
950
|
-
providerDurationMs: 500,
|
|
951
|
-
});
|
|
952
|
-
return [
|
|
953
|
-
...messages,
|
|
954
|
-
{
|
|
955
|
-
role: "assistant" as const,
|
|
956
|
-
content: [{ type: "text", text: "recovered" }] as ContentBlock[],
|
|
957
|
-
},
|
|
958
|
-
];
|
|
959
|
-
};
|
|
831
|
+
// AND a provider that rejects the first call as too long (revealing the
|
|
832
|
+
// real 242k count the estimator missed), then succeeds on the rerun.
|
|
833
|
+
const { provider, calls } = createMockProvider([
|
|
834
|
+
new Error("prompt is too long: 242201 tokens > 200000 maximum"),
|
|
835
|
+
textResponse("recovered"),
|
|
836
|
+
]);
|
|
960
837
|
|
|
961
838
|
const ctx = makeCtx({
|
|
962
|
-
|
|
839
|
+
loopProvider: provider,
|
|
963
840
|
contextWindowManager: {
|
|
964
841
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
965
842
|
maybeCompact: async () => ({ compacted: false }),
|
|
966
843
|
} as unknown as AgentLoopConversationContext["contextWindowManager"],
|
|
967
844
|
});
|
|
968
845
|
|
|
846
|
+
// WHEN the turn runs
|
|
969
847
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
970
848
|
|
|
971
|
-
//
|
|
849
|
+
// THEN the convergence reducer ran and the rerun recovered without a
|
|
850
|
+
// user-facing conversation_error.
|
|
972
851
|
expect(reducerCalled).toBe(true);
|
|
973
|
-
// Should recover without conversation_error
|
|
974
852
|
const conversationError = events.find(
|
|
975
853
|
(e) => e.type === "conversation_error",
|
|
976
854
|
);
|
|
977
855
|
expect(conversationError).toBeUndefined();
|
|
978
|
-
expect(
|
|
856
|
+
expect(calls.length).toBe(2);
|
|
979
857
|
});
|
|
980
858
|
|
|
981
859
|
// ── Test 3 ────────────────────────────────────────────────────────
|
|
982
|
-
//
|
|
983
|
-
// "242201 tokens > 200000"), the reducer
|
|
984
|
-
// the actual limit
|
|
985
|
-
//
|
|
986
|
-
//
|
|
987
|
-
//
|
|
988
|
-
//
|
|
989
|
-
//
|
|
990
|
-
// Expected behavior (PR 4 fix): `targetInputTokensOverride` should
|
|
991
|
-
// be adjusted based on the ratio between estimated and actual tokens.
|
|
992
|
-
// BUG: The targetTokens passed to the reducer is preflightBudget = 190k.
|
|
993
|
-
// But when the actual token count is 242k (1.31x the estimate of 185k),
|
|
994
|
-
// the target should be adjusted downward to account for the estimation
|
|
995
|
-
// inaccuracy. For example: 190k / 1.31 ≈ 145k.
|
|
996
|
-
// Planned fix: targetInputTokensOverride should be adjusted based on
|
|
997
|
-
// the ratio between estimated and actual tokens.
|
|
860
|
+
// When the provider rejection reveals the actual token count (e.g.,
|
|
861
|
+
// "242201 tokens > 200000"), the overflow reducer's `targetTokens`
|
|
862
|
+
// should be a budget below the actual limit, not below the estimator's
|
|
863
|
+
// inaccurate budget. With a preflightBudget of 190k but an actual count
|
|
864
|
+
// of 242k (1.31x the estimate of 185k), the target is adjusted downward
|
|
865
|
+
// based on the observed mismatch (190k / 1.31 ≈ 145k) so the reducer
|
|
866
|
+
// converges toward the real ceiling rather than the optimistic estimate.
|
|
998
867
|
test.todo(
|
|
999
868
|
"forced compaction targets a lower budget when estimation has been inaccurate",
|
|
1000
869
|
async () => {
|
|
1001
870
|
const events: ServerMessage[] = [];
|
|
1002
|
-
let callCount = 0;
|
|
1003
871
|
let capturedTargetTokens: number | undefined;
|
|
1004
872
|
|
|
1005
873
|
// Estimator says 185k (below 190k budget = 200k * 0.95)
|
|
@@ -1035,52 +903,16 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1035
903
|
};
|
|
1036
904
|
};
|
|
1037
905
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
"prompt is too long: 242201 tokens > 200000 maximum",
|
|
1046
|
-
),
|
|
1047
|
-
});
|
|
1048
|
-
onEvent({
|
|
1049
|
-
type: "usage",
|
|
1050
|
-
inputTokens: 0,
|
|
1051
|
-
outputTokens: 0,
|
|
1052
|
-
model: "test-model",
|
|
1053
|
-
providerDurationMs: 10,
|
|
1054
|
-
});
|
|
1055
|
-
// No progress — return same messages
|
|
1056
|
-
return messages;
|
|
1057
|
-
}
|
|
1058
|
-
// Second call succeeds after compaction
|
|
1059
|
-
onEvent({
|
|
1060
|
-
type: "message_complete",
|
|
1061
|
-
message: {
|
|
1062
|
-
role: "assistant",
|
|
1063
|
-
content: [{ type: "text", text: "recovered" }],
|
|
1064
|
-
},
|
|
1065
|
-
});
|
|
1066
|
-
onEvent({
|
|
1067
|
-
type: "usage",
|
|
1068
|
-
inputTokens: 80_000,
|
|
1069
|
-
outputTokens: 200,
|
|
1070
|
-
model: "test-model",
|
|
1071
|
-
providerDurationMs: 500,
|
|
1072
|
-
});
|
|
1073
|
-
return [
|
|
1074
|
-
...messages,
|
|
1075
|
-
{
|
|
1076
|
-
role: "assistant" as const,
|
|
1077
|
-
content: [{ type: "text", text: "recovered" }] as ContentBlock[],
|
|
1078
|
-
},
|
|
1079
|
-
];
|
|
1080
|
-
};
|
|
906
|
+
// The provider rejects the first call with a context_too_large error
|
|
907
|
+
// (actual tokens 242201, far above the 185k estimate); after forced
|
|
908
|
+
// compaction re-targets a lower budget, the rerun recovers with text.
|
|
909
|
+
const { provider, calls } = createMockProvider([
|
|
910
|
+
new Error("prompt is too long: 242201 tokens > 200000 maximum"),
|
|
911
|
+
textResponse("recovered"),
|
|
912
|
+
]);
|
|
1081
913
|
|
|
1082
914
|
const ctx = makeCtx({
|
|
1083
|
-
|
|
915
|
+
loopProvider: provider,
|
|
1084
916
|
contextWindowManager: {
|
|
1085
917
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1086
918
|
maybeCompact: async () => ({ compacted: false }),
|
|
@@ -1110,7 +942,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1110
942
|
(e) => e.type === "conversation_error",
|
|
1111
943
|
);
|
|
1112
944
|
expect(conversationError).toBeUndefined();
|
|
1113
|
-
expect(
|
|
945
|
+
expect(calls.length).toBe(2);
|
|
1114
946
|
},
|
|
1115
947
|
);
|
|
1116
948
|
|
|
@@ -1124,7 +956,6 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1124
956
|
async () => {
|
|
1125
957
|
const events: ServerMessage[] = [];
|
|
1126
958
|
const longHistory = buildLongConversation(75);
|
|
1127
|
-
let callCount = 0;
|
|
1128
959
|
let reducerCalled = false;
|
|
1129
960
|
|
|
1130
961
|
// Estimator says ~195k — just above budget so preflight reducer runs
|
|
@@ -1160,35 +991,14 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1160
991
|
};
|
|
1161
992
|
};
|
|
1162
993
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
role: "assistant",
|
|
1169
|
-
content: [{ type: "text", text: "Here's the analysis..." }],
|
|
1170
|
-
},
|
|
1171
|
-
});
|
|
1172
|
-
onEvent({
|
|
1173
|
-
type: "usage",
|
|
1174
|
-
inputTokens: 50_000,
|
|
1175
|
-
outputTokens: 300,
|
|
1176
|
-
model: "test-model",
|
|
1177
|
-
providerDurationMs: 800,
|
|
1178
|
-
});
|
|
1179
|
-
return [
|
|
1180
|
-
...messages,
|
|
1181
|
-
{
|
|
1182
|
-
role: "assistant" as const,
|
|
1183
|
-
content: [
|
|
1184
|
-
{ type: "text", text: "Here's the analysis..." },
|
|
1185
|
-
] as ContentBlock[],
|
|
1186
|
-
},
|
|
1187
|
-
];
|
|
1188
|
-
};
|
|
994
|
+
// After the preflight reducer compacts the long history under budget,
|
|
995
|
+
// a single provider call completes the turn with plain text.
|
|
996
|
+
const { provider, calls } = createMockProvider([
|
|
997
|
+
textResponse("Here's the analysis..."),
|
|
998
|
+
]);
|
|
1189
999
|
|
|
1190
1000
|
const ctx = makeCtx({
|
|
1191
|
-
|
|
1001
|
+
loopProvider: provider,
|
|
1192
1002
|
messages: longHistory,
|
|
1193
1003
|
contextWindowManager: {
|
|
1194
1004
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
@@ -1203,7 +1013,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1203
1013
|
// Preflight should trigger the reducer since 195k > 190k budget
|
|
1204
1014
|
expect(reducerCalled).toBe(true);
|
|
1205
1015
|
// Should succeed
|
|
1206
|
-
expect(
|
|
1016
|
+
expect(calls.length).toBe(1);
|
|
1207
1017
|
const conversationError = events.find(
|
|
1208
1018
|
(e) => e.type === "conversation_error",
|
|
1209
1019
|
);
|
|
@@ -1247,115 +1057,31 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1247
1057
|
};
|
|
1248
1058
|
};
|
|
1249
1059
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
role: "assistant" as const,
|
|
1259
|
-
content: [
|
|
1260
|
-
{ type: "text", text: "Running analysis..." },
|
|
1261
|
-
{
|
|
1262
|
-
type: "tool_use",
|
|
1263
|
-
id: "tu-1",
|
|
1264
|
-
name: "bash",
|
|
1265
|
-
input: { command: "find . -name '*.ts'" },
|
|
1266
|
-
},
|
|
1267
|
-
] as ContentBlock[],
|
|
1268
|
-
},
|
|
1269
|
-
{
|
|
1270
|
-
role: "user" as const,
|
|
1271
|
-
content: [
|
|
1272
|
-
{
|
|
1273
|
-
type: "tool_result",
|
|
1274
|
-
tool_use_id: "tu-1",
|
|
1275
|
-
content: "file1.ts\nfile2.ts\nfile3.ts",
|
|
1276
|
-
is_error: false,
|
|
1277
|
-
},
|
|
1278
|
-
] as ContentBlock[],
|
|
1279
|
-
},
|
|
1280
|
-
];
|
|
1060
|
+
// Run 1 makes progress (a tool turn) then the following provider call
|
|
1061
|
+
// rejects with context_too_large; after emergency compaction the rerun
|
|
1062
|
+
// recovers with plain text.
|
|
1063
|
+
const { provider } = createMockProvider([
|
|
1064
|
+
toolUseResponse("tu-1", "bash", { command: "find . -name '*.ts'" }),
|
|
1065
|
+
new Error("context_length_exceeded"),
|
|
1066
|
+
textResponse("recovered"),
|
|
1067
|
+
]);
|
|
1281
1068
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1069
|
+
const ctx = makeCtx({
|
|
1070
|
+
loopProvider: provider,
|
|
1071
|
+
loopTools: [
|
|
1072
|
+
{
|
|
1285
1073
|
name: "bash",
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
toolUseId: "tu-1",
|
|
1291
|
-
content: "file1.ts\nfile2.ts\nfile3.ts",
|
|
1292
|
-
isError: false,
|
|
1293
|
-
});
|
|
1294
|
-
onEvent({
|
|
1295
|
-
type: "message_complete",
|
|
1296
|
-
message: {
|
|
1297
|
-
role: "assistant",
|
|
1298
|
-
content: [
|
|
1299
|
-
{ type: "text", text: "Running analysis..." },
|
|
1300
|
-
{
|
|
1301
|
-
type: "tool_use",
|
|
1302
|
-
id: "tu-1",
|
|
1303
|
-
name: "bash",
|
|
1304
|
-
input: { command: "find . -name '*.ts'" },
|
|
1305
|
-
},
|
|
1306
|
-
],
|
|
1074
|
+
description: "Run a shell command",
|
|
1075
|
+
input_schema: {
|
|
1076
|
+
type: "object",
|
|
1077
|
+
properties: { command: { type: "string" } },
|
|
1307
1078
|
},
|
|
1308
|
-
});
|
|
1309
|
-
onEvent({
|
|
1310
|
-
type: "usage",
|
|
1311
|
-
inputTokens: 190_000,
|
|
1312
|
-
outputTokens: 100,
|
|
1313
|
-
model: "test-model",
|
|
1314
|
-
providerDurationMs: 200,
|
|
1315
|
-
});
|
|
1316
|
-
|
|
1317
|
-
// Then context_too_large on the next LLM call within the loop
|
|
1318
|
-
onEvent({
|
|
1319
|
-
type: "error",
|
|
1320
|
-
error: new Error("context_length_exceeded"),
|
|
1321
|
-
});
|
|
1322
|
-
onEvent({
|
|
1323
|
-
type: "usage",
|
|
1324
|
-
inputTokens: 0,
|
|
1325
|
-
outputTokens: 0,
|
|
1326
|
-
model: "test-model",
|
|
1327
|
-
providerDurationMs: 10,
|
|
1328
|
-
});
|
|
1329
|
-
|
|
1330
|
-
return progressMessages;
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
// After emergency compaction, succeed
|
|
1334
|
-
onEvent({
|
|
1335
|
-
type: "message_complete",
|
|
1336
|
-
message: {
|
|
1337
|
-
role: "assistant",
|
|
1338
|
-
content: [{ type: "text", text: "recovered" }],
|
|
1339
1079
|
},
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
model: "test-model",
|
|
1346
|
-
providerDurationMs: 200,
|
|
1347
|
-
});
|
|
1348
|
-
return [
|
|
1349
|
-
...messages,
|
|
1350
|
-
{
|
|
1351
|
-
role: "assistant" as const,
|
|
1352
|
-
content: [{ type: "text", text: "recovered" }] as ContentBlock[],
|
|
1353
|
-
},
|
|
1354
|
-
];
|
|
1355
|
-
};
|
|
1356
|
-
|
|
1357
|
-
const ctx = makeCtx({
|
|
1358
|
-
agentLoopRun,
|
|
1080
|
+
],
|
|
1081
|
+
toolExecutor: async () => ({
|
|
1082
|
+
content: "file1.ts\nfile2.ts\nfile3.ts",
|
|
1083
|
+
isError: false,
|
|
1084
|
+
}),
|
|
1359
1085
|
contextWindowManager: {
|
|
1360
1086
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1361
1087
|
maybeCompact: async (
|
|
@@ -1432,114 +1158,30 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1432
1158
|
return 170_000;
|
|
1433
1159
|
};
|
|
1434
1160
|
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
) => {
|
|
1443
|
-
agentLoopCallCount++;
|
|
1444
|
-
|
|
1445
|
-
if (agentLoopCallCount === 1) {
|
|
1446
|
-
// Simulate a tool round: assistant calls a tool, results come back
|
|
1447
|
-
const withProgress: Message[] = [
|
|
1448
|
-
...messages,
|
|
1449
|
-
{
|
|
1450
|
-
role: "assistant" as const,
|
|
1451
|
-
content: [
|
|
1452
|
-
{ type: "text", text: "Let me check." },
|
|
1453
|
-
{
|
|
1454
|
-
type: "tool_use",
|
|
1455
|
-
id: "tu-1",
|
|
1456
|
-
name: "bash",
|
|
1457
|
-
input: { command: "ls" },
|
|
1458
|
-
},
|
|
1459
|
-
] as ContentBlock[],
|
|
1460
|
-
},
|
|
1461
|
-
{
|
|
1462
|
-
role: "user" as const,
|
|
1463
|
-
content: [
|
|
1464
|
-
{
|
|
1465
|
-
type: "tool_result",
|
|
1466
|
-
tool_use_id: "tu-1",
|
|
1467
|
-
content: "file1.ts\nfile2.ts",
|
|
1468
|
-
is_error: false,
|
|
1469
|
-
},
|
|
1470
|
-
] as ContentBlock[],
|
|
1471
|
-
},
|
|
1472
|
-
];
|
|
1473
|
-
|
|
1474
|
-
onEvent({
|
|
1475
|
-
type: "message_complete",
|
|
1476
|
-
message: {
|
|
1477
|
-
role: "assistant",
|
|
1478
|
-
content: [
|
|
1479
|
-
{ type: "text", text: "Let me check." },
|
|
1480
|
-
{
|
|
1481
|
-
type: "tool_use",
|
|
1482
|
-
id: "tu-1",
|
|
1483
|
-
name: "bash",
|
|
1484
|
-
input: { command: "ls" },
|
|
1485
|
-
},
|
|
1486
|
-
],
|
|
1487
|
-
},
|
|
1488
|
-
});
|
|
1489
|
-
onEvent({
|
|
1490
|
-
type: "usage",
|
|
1491
|
-
inputTokens: 100,
|
|
1492
|
-
outputTokens: 50,
|
|
1493
|
-
model: "test-model",
|
|
1494
|
-
providerDurationMs: 100,
|
|
1495
|
-
});
|
|
1496
|
-
|
|
1497
|
-
// Call onCheckpoint — this should trigger the mid-loop budget check
|
|
1498
|
-
// which sees 170_000 > 161_500 and returns "yield"
|
|
1499
|
-
if (onCheckpoint) {
|
|
1500
|
-
const decision = await onCheckpoint({
|
|
1501
|
-
turnIndex: 0,
|
|
1502
|
-
toolCount: 1,
|
|
1503
|
-
hasToolUse: true,
|
|
1504
|
-
history: withProgress,
|
|
1505
|
-
});
|
|
1506
|
-
if (decision === "yield") {
|
|
1507
|
-
// Agent loop stops when checkpoint yields
|
|
1508
|
-
return withProgress;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
return withProgress;
|
|
1513
|
-
}
|
|
1161
|
+
// A tool round trips the mid-loop budget gate (170k > 161_500); the
|
|
1162
|
+
// gate compacts in place (productive) and the loop continues, so the
|
|
1163
|
+
// post-compaction provider call completes the turn with plain text.
|
|
1164
|
+
const { provider, calls } = createMockProvider([
|
|
1165
|
+
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1166
|
+
textResponse("done after compaction"),
|
|
1167
|
+
]);
|
|
1514
1168
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
message: {
|
|
1519
|
-
role: "assistant",
|
|
1520
|
-
content: [{ type: "text", text: "done after compaction" }],
|
|
1521
|
-
},
|
|
1522
|
-
});
|
|
1523
|
-
onEvent({
|
|
1524
|
-
type: "usage",
|
|
1525
|
-
inputTokens: 50,
|
|
1526
|
-
outputTokens: 25,
|
|
1527
|
-
model: "test-model",
|
|
1528
|
-
providerDurationMs: 100,
|
|
1529
|
-
});
|
|
1530
|
-
return [
|
|
1531
|
-
...messages,
|
|
1169
|
+
const ctx = makeCtx({
|
|
1170
|
+
loopProvider: provider,
|
|
1171
|
+
loopTools: [
|
|
1532
1172
|
{
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1173
|
+
name: "bash",
|
|
1174
|
+
description: "Run a shell command",
|
|
1175
|
+
input_schema: {
|
|
1176
|
+
type: "object",
|
|
1177
|
+
properties: { command: { type: "string" } },
|
|
1178
|
+
},
|
|
1537
1179
|
},
|
|
1538
|
-
]
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1180
|
+
],
|
|
1181
|
+
toolExecutor: async () => ({
|
|
1182
|
+
content: "file1.ts\nfile2.ts",
|
|
1183
|
+
isError: false,
|
|
1184
|
+
}),
|
|
1543
1185
|
contextWindowManager: {
|
|
1544
1186
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1545
1187
|
maybeCompact: async () => {
|
|
@@ -1573,8 +1215,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1573
1215
|
// The mid-loop budget check should have triggered compaction
|
|
1574
1216
|
expect(compactionCalled).toBe(true);
|
|
1575
1217
|
|
|
1576
|
-
//
|
|
1577
|
-
|
|
1218
|
+
// Provider called twice: the tool turn that tripped the gate, then the
|
|
1219
|
+
// post-compaction turn that completed the run.
|
|
1220
|
+
expect(calls.length).toBe(2);
|
|
1578
1221
|
|
|
1579
1222
|
// No conversation_error should be emitted
|
|
1580
1223
|
const conversationError = events.find(
|
|
@@ -1615,107 +1258,36 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1615
1258
|
return 175_000;
|
|
1616
1259
|
};
|
|
1617
1260
|
|
|
1618
|
-
let agentLoopCallCount = 0;
|
|
1619
1261
|
let contextTooLargeEmitted = false;
|
|
1620
1262
|
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
// Simulate 5 tool rounds — but the checkpoint should yield at round 3
|
|
1634
|
-
for (let i = 0; i < 5; i++) {
|
|
1635
|
-
const toolId = `tu-${i}`;
|
|
1636
|
-
const assistantMsg: Message = {
|
|
1637
|
-
role: "assistant" as const,
|
|
1638
|
-
content: [
|
|
1639
|
-
{ type: "text", text: `Step ${i}` },
|
|
1640
|
-
{
|
|
1641
|
-
type: "tool_use",
|
|
1642
|
-
id: toolId,
|
|
1643
|
-
name: "bash",
|
|
1644
|
-
input: { command: `cmd-${i}` },
|
|
1645
|
-
},
|
|
1646
|
-
] as ContentBlock[],
|
|
1647
|
-
};
|
|
1648
|
-
const resultMsg: Message = {
|
|
1649
|
-
role: "user" as const,
|
|
1650
|
-
content: [
|
|
1651
|
-
{
|
|
1652
|
-
type: "tool_result",
|
|
1653
|
-
tool_use_id: toolId,
|
|
1654
|
-
content: "x".repeat(10_000),
|
|
1655
|
-
is_error: false,
|
|
1656
|
-
},
|
|
1657
|
-
] as ContentBlock[],
|
|
1658
|
-
};
|
|
1659
|
-
currentHistory.push(assistantMsg, resultMsg);
|
|
1660
|
-
|
|
1661
|
-
onEvent({
|
|
1662
|
-
type: "message_complete",
|
|
1663
|
-
message: assistantMsg,
|
|
1664
|
-
});
|
|
1665
|
-
onEvent({
|
|
1666
|
-
type: "usage",
|
|
1667
|
-
inputTokens: 50_000 + i * 20_000,
|
|
1668
|
-
outputTokens: 50,
|
|
1669
|
-
model: "test-model",
|
|
1670
|
-
providerDurationMs: 100,
|
|
1671
|
-
});
|
|
1672
|
-
|
|
1673
|
-
if (onCheckpoint) {
|
|
1674
|
-
const decision = await onCheckpoint({
|
|
1675
|
-
turnIndex: i,
|
|
1676
|
-
toolCount: 1,
|
|
1677
|
-
hasToolUse: true,
|
|
1678
|
-
history: currentHistory,
|
|
1679
|
-
});
|
|
1680
|
-
if (decision === "yield") {
|
|
1681
|
-
return currentHistory;
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
return currentHistory;
|
|
1687
|
-
}
|
|
1263
|
+
// Each tool round produces a large result; the estimate grows with each
|
|
1264
|
+
// checkpoint until tool round 3 trips the mid-loop gate (175k > 161_500).
|
|
1265
|
+
// Compaction runs in place (productive) and the loop continues, so the
|
|
1266
|
+
// following plain-text provider call completes the turn. The provider
|
|
1267
|
+
// never rejects with context_too_large.
|
|
1268
|
+
const { provider, calls } = createMockProvider([
|
|
1269
|
+
toolUseResponse("tu-0", "bash", { command: "cmd-0" }),
|
|
1270
|
+
toolUseResponse("tu-1", "bash", { command: "cmd-1" }),
|
|
1271
|
+
toolUseResponse("tu-2", "bash", { command: "cmd-2" }),
|
|
1272
|
+
textResponse("completed after mid-loop compaction"),
|
|
1273
|
+
]);
|
|
1688
1274
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
message: {
|
|
1693
|
-
role: "assistant",
|
|
1694
|
-
content: [
|
|
1695
|
-
{ type: "text", text: "completed after mid-loop compaction" },
|
|
1696
|
-
],
|
|
1697
|
-
},
|
|
1698
|
-
});
|
|
1699
|
-
onEvent({
|
|
1700
|
-
type: "usage",
|
|
1701
|
-
inputTokens: 60_000,
|
|
1702
|
-
outputTokens: 100,
|
|
1703
|
-
model: "test-model",
|
|
1704
|
-
providerDurationMs: 200,
|
|
1705
|
-
});
|
|
1706
|
-
return [
|
|
1707
|
-
...messages,
|
|
1275
|
+
const ctx = makeCtx({
|
|
1276
|
+
loopProvider: provider,
|
|
1277
|
+
loopTools: [
|
|
1708
1278
|
{
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1279
|
+
name: "bash",
|
|
1280
|
+
description: "Run a shell command",
|
|
1281
|
+
input_schema: {
|
|
1282
|
+
type: "object",
|
|
1283
|
+
properties: { command: { type: "string" } },
|
|
1284
|
+
},
|
|
1713
1285
|
},
|
|
1714
|
-
]
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1286
|
+
],
|
|
1287
|
+
toolExecutor: async () => ({
|
|
1288
|
+
content: "x".repeat(10_000),
|
|
1289
|
+
isError: false,
|
|
1290
|
+
}),
|
|
1719
1291
|
contextWindowManager: {
|
|
1720
1292
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1721
1293
|
maybeCompact: async () => {
|
|
@@ -1762,8 +1334,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1762
1334
|
// The provider should NEVER have rejected with context_too_large
|
|
1763
1335
|
expect(contextTooLargeEmitted).toBe(false);
|
|
1764
1336
|
|
|
1765
|
-
//
|
|
1766
|
-
|
|
1337
|
+
// Provider called four times: three tool rounds (the third trips the
|
|
1338
|
+
// mid-loop gate) plus the post-compaction text turn that completes.
|
|
1339
|
+
expect(calls.length).toBe(4);
|
|
1767
1340
|
|
|
1768
1341
|
// No conversation_error
|
|
1769
1342
|
const conversationError = events.find(
|
|
@@ -1792,85 +1365,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1792
1365
|
return 170_000;
|
|
1793
1366
|
};
|
|
1794
1367
|
|
|
1795
|
-
|
|
1796
|
-
const agentLoopRun: AgentLoopRun = async (
|
|
1797
|
-
messages,
|
|
1798
|
-
onEvent,
|
|
1799
|
-
_signal,
|
|
1800
|
-
_requestId,
|
|
1801
|
-
onCheckpoint,
|
|
1802
|
-
) => {
|
|
1803
|
-
agentLoopCallCount++;
|
|
1804
|
-
|
|
1805
|
-
// Every call: simulate tool progress then yield at checkpoint
|
|
1806
|
-
const withProgress: Message[] = [
|
|
1807
|
-
...messages,
|
|
1808
|
-
{
|
|
1809
|
-
role: "assistant" as const,
|
|
1810
|
-
content: [
|
|
1811
|
-
{ type: "text", text: `Tool call ${agentLoopCallCount}` },
|
|
1812
|
-
{
|
|
1813
|
-
type: "tool_use",
|
|
1814
|
-
id: `tu-${agentLoopCallCount}`,
|
|
1815
|
-
name: "bash",
|
|
1816
|
-
input: { command: "ls" },
|
|
1817
|
-
},
|
|
1818
|
-
] as ContentBlock[],
|
|
1819
|
-
},
|
|
1820
|
-
{
|
|
1821
|
-
role: "user" as const,
|
|
1822
|
-
content: [
|
|
1823
|
-
{
|
|
1824
|
-
type: "tool_result",
|
|
1825
|
-
tool_use_id: `tu-${agentLoopCallCount}`,
|
|
1826
|
-
content: "output",
|
|
1827
|
-
is_error: false,
|
|
1828
|
-
},
|
|
1829
|
-
] as ContentBlock[],
|
|
1830
|
-
},
|
|
1831
|
-
];
|
|
1832
|
-
|
|
1833
|
-
onEvent({
|
|
1834
|
-
type: "message_complete",
|
|
1835
|
-
message: {
|
|
1836
|
-
role: "assistant",
|
|
1837
|
-
content: [
|
|
1838
|
-
{ type: "text", text: `Tool call ${agentLoopCallCount}` },
|
|
1839
|
-
{
|
|
1840
|
-
type: "tool_use",
|
|
1841
|
-
id: `tu-${agentLoopCallCount}`,
|
|
1842
|
-
name: "bash",
|
|
1843
|
-
input: { command: "ls" },
|
|
1844
|
-
},
|
|
1845
|
-
],
|
|
1846
|
-
},
|
|
1847
|
-
});
|
|
1848
|
-
onEvent({
|
|
1849
|
-
type: "usage",
|
|
1850
|
-
inputTokens: 100,
|
|
1851
|
-
outputTokens: 50,
|
|
1852
|
-
model: "test-model",
|
|
1853
|
-
providerDurationMs: 100,
|
|
1854
|
-
});
|
|
1855
|
-
|
|
1856
|
-
// Always yield at checkpoint — simulates compaction not helping
|
|
1857
|
-
if (onCheckpoint) {
|
|
1858
|
-
const decision = await onCheckpoint({
|
|
1859
|
-
turnIndex: 0,
|
|
1860
|
-
toolCount: 1,
|
|
1861
|
-
hasToolUse: true,
|
|
1862
|
-
history: withProgress,
|
|
1863
|
-
});
|
|
1864
|
-
if (decision === "yield") {
|
|
1865
|
-
return withProgress;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1869
|
-
return withProgress;
|
|
1870
|
-
};
|
|
1871
|
-
|
|
1872
|
-
let compactionCallCount = 0;
|
|
1873
|
-
// Convergence reducer: reduce tokens enough to succeed
|
|
1368
|
+
// The convergence reducer reduces tokens enough for the rerun to recover.
|
|
1874
1369
|
let convergenceReducerCalled = false;
|
|
1875
1370
|
mockReducerStepFn = (msgs: Message[]) => {
|
|
1876
1371
|
convergenceReducerCalled = true;
|
|
@@ -1886,15 +1381,43 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1886
1381
|
};
|
|
1887
1382
|
};
|
|
1888
1383
|
|
|
1384
|
+
// Every provider call returns a tool_use, so each loop run does a tool
|
|
1385
|
+
// turn that trips the mid-loop budget gate. On the initial run the gate
|
|
1386
|
+
// calls compaction (which surfaces `exhausted: true`); the convergence
|
|
1387
|
+
// rerun runs without a compaction hook and yields "budget" directly.
|
|
1388
|
+
// With the reducer exhausted, the convergence loop terminates with the
|
|
1389
|
+
// turn still over budget and the orchestrator stamps `context_too_large`.
|
|
1390
|
+
const { provider, calls } = createMockProvider([
|
|
1391
|
+
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1392
|
+
]);
|
|
1393
|
+
|
|
1394
|
+
let compactionCallCount = 0;
|
|
1889
1395
|
const ctx = makeCtx({
|
|
1890
|
-
|
|
1396
|
+
loopProvider: provider,
|
|
1397
|
+
loopTools: [
|
|
1398
|
+
{
|
|
1399
|
+
name: "bash",
|
|
1400
|
+
description: "Run a shell command",
|
|
1401
|
+
input_schema: {
|
|
1402
|
+
type: "object",
|
|
1403
|
+
properties: { command: { type: "string" } },
|
|
1404
|
+
},
|
|
1405
|
+
},
|
|
1406
|
+
],
|
|
1407
|
+
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1891
1408
|
contextWindowManager: {
|
|
1892
1409
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1893
1410
|
maybeCompact: async () => {
|
|
1894
1411
|
compactionCallCount++;
|
|
1895
|
-
// Compaction
|
|
1412
|
+
// Compaction's internal retry budget is exhausted — the
|
|
1413
|
+
// compactor itself ran maxAttempts passes and still couldn't
|
|
1414
|
+
// drop below the auto-threshold. `maybeCompact` surfaces this
|
|
1415
|
+
// via `exhausted: true` so the loop yields "budget" and the
|
|
1416
|
+
// orchestrator escalates straight to the convergence loop
|
|
1417
|
+
// instead of looping on a stuck compactor.
|
|
1896
1418
|
return {
|
|
1897
1419
|
compacted: true,
|
|
1420
|
+
exhausted: true,
|
|
1898
1421
|
messages: [
|
|
1899
1422
|
{
|
|
1900
1423
|
role: "user" as const,
|
|
@@ -1919,14 +1442,20 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1919
1442
|
|
|
1920
1443
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
1921
1444
|
|
|
1922
|
-
// 1 initial auto-compact +
|
|
1923
|
-
|
|
1445
|
+
// 1 initial auto-compact + 1 mid-loop compaction = 2 total. The
|
|
1446
|
+
// first mid-loop call surfaces `exhausted: true`, so the
|
|
1447
|
+
// orchestrator escalates immediately without retrying maybeCompact
|
|
1448
|
+
// — the retry budget for the compactor itself lives inside
|
|
1449
|
+
// `ContextWindowManager.maybeCompact`.
|
|
1450
|
+
expect(compactionCallCount).toBe(2);
|
|
1924
1451
|
|
|
1925
|
-
//
|
|
1926
|
-
|
|
1452
|
+
// Provider calls: 1 initial tool turn (yields budget) + 1 convergence
|
|
1453
|
+
// rerun that recovers. No mid-loop re-entries because the orchestrator
|
|
1454
|
+
// broke out on `exhausted` before re-invoking the loop.
|
|
1455
|
+
expect(calls.length).toBe(2);
|
|
1927
1456
|
|
|
1928
|
-
// After
|
|
1929
|
-
// have been triggered (contextTooLargeDetected set to true)
|
|
1457
|
+
// After the compactor exhausted itself, the convergence loop
|
|
1458
|
+
// should have been triggered (contextTooLargeDetected set to true)
|
|
1930
1459
|
expect(convergenceReducerCalled).toBe(true);
|
|
1931
1460
|
expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
|
|
1932
1461
|
"test-conv",
|
|
@@ -1934,6 +1463,102 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1934
1463
|
);
|
|
1935
1464
|
});
|
|
1936
1465
|
|
|
1466
|
+
// ── Test 8b ───────────────────────────────────────────────────────
|
|
1467
|
+
// Counterpart to Test 8: when a mid-loop `maybeCompact` returns
|
|
1468
|
+
// productive (`compacted: true`, no `exhausted` flag), the loop
|
|
1469
|
+
// compacts in place and continues the run itself — it never yields
|
|
1470
|
+
// "budget", so the orchestrator does not escalate to the convergence
|
|
1471
|
+
// loop. Mid-loop iteration is now wholly internal to `AgentLoop.run`;
|
|
1472
|
+
// the orchestrator only reacts to the binary `exhausted`/timeout
|
|
1473
|
+
// signal carried back as a "budget" exit.
|
|
1474
|
+
test("productive mid-loop compaction continues in place without escalating", async () => {
|
|
1475
|
+
const events: ServerMessage[] = [];
|
|
1476
|
+
|
|
1477
|
+
// Budget = 200_000 * 0.95 = 190_000
|
|
1478
|
+
// Mid-loop threshold = 190_000 * 0.85 = 161_500
|
|
1479
|
+
let estimateCallCount = 0;
|
|
1480
|
+
mockEstimateTokens = () => {
|
|
1481
|
+
estimateCallCount++;
|
|
1482
|
+
// Preflight: below budget.
|
|
1483
|
+
if (estimateCallCount === 1) return 100_000;
|
|
1484
|
+
// Every checkpoint estimate: above threshold — always trips the
|
|
1485
|
+
// yield. Simulates a long turn where each tool call's result
|
|
1486
|
+
// inflates the context past 85% even after a successful compaction.
|
|
1487
|
+
return 170_000;
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1490
|
+
// A single tool round reaches one checkpoint; the in-loop budget gate
|
|
1491
|
+
// trips there and compaction runs in place. The loop continues the run
|
|
1492
|
+
// itself — the following provider call returns plain text and the turn
|
|
1493
|
+
// completes — so the orchestrator never re-enters the convergence loop.
|
|
1494
|
+
const { provider, calls } = createMockProvider([
|
|
1495
|
+
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1496
|
+
textResponse("final answer"),
|
|
1497
|
+
]);
|
|
1498
|
+
|
|
1499
|
+
// Compaction reports `estimatedInputTokens` well below the 161_500
|
|
1500
|
+
// threshold — the "compaction is productive" signal (no `exhausted`
|
|
1501
|
+
// flag) that lets the loop continue in place.
|
|
1502
|
+
let compactionCallCount = 0;
|
|
1503
|
+
const ctx = makeCtx({
|
|
1504
|
+
loopProvider: provider,
|
|
1505
|
+
loopTools: [
|
|
1506
|
+
{
|
|
1507
|
+
name: "bash",
|
|
1508
|
+
description: "Run a shell command",
|
|
1509
|
+
input_schema: {
|
|
1510
|
+
type: "object",
|
|
1511
|
+
properties: { command: { type: "string" } },
|
|
1512
|
+
},
|
|
1513
|
+
},
|
|
1514
|
+
],
|
|
1515
|
+
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1516
|
+
contextWindowManager: {
|
|
1517
|
+
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1518
|
+
maybeCompact: async () => {
|
|
1519
|
+
compactionCallCount++;
|
|
1520
|
+
return {
|
|
1521
|
+
compacted: true,
|
|
1522
|
+
messages: [
|
|
1523
|
+
{
|
|
1524
|
+
role: "user" as const,
|
|
1525
|
+
content: [{ type: "text", text: "Hello" }],
|
|
1526
|
+
},
|
|
1527
|
+
] as Message[],
|
|
1528
|
+
compactedPersistedMessages: 5,
|
|
1529
|
+
summaryText: "Compaction summary",
|
|
1530
|
+
previousEstimatedInputTokens: 170_000,
|
|
1531
|
+
estimatedInputTokens: 100_000,
|
|
1532
|
+
maxInputTokens: 200_000,
|
|
1533
|
+
thresholdTokens: 160_000,
|
|
1534
|
+
compactedMessages: 10,
|
|
1535
|
+
summaryCalls: 1,
|
|
1536
|
+
summaryInputTokens: 500,
|
|
1537
|
+
summaryOutputTokens: 200,
|
|
1538
|
+
summaryModel: "mock-model",
|
|
1539
|
+
};
|
|
1540
|
+
},
|
|
1541
|
+
} as unknown as AgentLoopConversationContext["contextWindowManager"],
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
1545
|
+
|
|
1546
|
+
// 1 initial auto-compact + 1 productive mid-loop compaction.
|
|
1547
|
+
expect(compactionCallCount).toBe(2);
|
|
1548
|
+
// The loop continued in place after compacting: a tool turn followed by
|
|
1549
|
+
// the post-compaction text turn, both within a single run.
|
|
1550
|
+
expect(calls.length).toBe(2);
|
|
1551
|
+
|
|
1552
|
+
// No escalation to the convergence loop because the mid-loop
|
|
1553
|
+
// `maybeCompact` returned productive (no `exhausted` flag), and the turn
|
|
1554
|
+
// completed normally.
|
|
1555
|
+
expect(setAgentLoopExitReasonOnLatestLogMock).not.toHaveBeenCalledWith(
|
|
1556
|
+
"test-conv",
|
|
1557
|
+
"context_too_large",
|
|
1558
|
+
);
|
|
1559
|
+
expect(events.find((e) => e.type === "conversation_error")).toBeUndefined();
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1937
1562
|
// ── Test 9 ────────────────────────────────────────────────────────
|
|
1938
1563
|
// When the convergence loop reruns the agent loop and it still yields
|
|
1939
1564
|
// at checkpoint (yieldedForBudget), the loop must continue reducing
|
|
@@ -1953,81 +1578,13 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1953
1578
|
return 170_000;
|
|
1954
1579
|
};
|
|
1955
1580
|
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
) => {
|
|
1964
|
-
agentLoopCallCount++;
|
|
1965
|
-
|
|
1966
|
-
const withProgress: Message[] = [
|
|
1967
|
-
...messages,
|
|
1968
|
-
{
|
|
1969
|
-
role: "assistant" as const,
|
|
1970
|
-
content: [
|
|
1971
|
-
{ type: "text", text: `Tool call ${agentLoopCallCount}` },
|
|
1972
|
-
{
|
|
1973
|
-
type: "tool_use",
|
|
1974
|
-
id: `tu-${agentLoopCallCount}`,
|
|
1975
|
-
name: "bash",
|
|
1976
|
-
input: { command: "ls" },
|
|
1977
|
-
},
|
|
1978
|
-
] as ContentBlock[],
|
|
1979
|
-
},
|
|
1980
|
-
{
|
|
1981
|
-
role: "user" as const,
|
|
1982
|
-
content: [
|
|
1983
|
-
{
|
|
1984
|
-
type: "tool_result",
|
|
1985
|
-
tool_use_id: `tu-${agentLoopCallCount}`,
|
|
1986
|
-
content: "output",
|
|
1987
|
-
is_error: false,
|
|
1988
|
-
},
|
|
1989
|
-
] as ContentBlock[],
|
|
1990
|
-
},
|
|
1991
|
-
];
|
|
1992
|
-
|
|
1993
|
-
onEvent({
|
|
1994
|
-
type: "message_complete",
|
|
1995
|
-
message: {
|
|
1996
|
-
role: "assistant",
|
|
1997
|
-
content: [
|
|
1998
|
-
{ type: "text", text: `Tool call ${agentLoopCallCount}` },
|
|
1999
|
-
{
|
|
2000
|
-
type: "tool_use",
|
|
2001
|
-
id: `tu-${agentLoopCallCount}`,
|
|
2002
|
-
name: "bash",
|
|
2003
|
-
input: { command: "ls" },
|
|
2004
|
-
},
|
|
2005
|
-
],
|
|
2006
|
-
},
|
|
2007
|
-
});
|
|
2008
|
-
onEvent({
|
|
2009
|
-
type: "usage",
|
|
2010
|
-
inputTokens: 100,
|
|
2011
|
-
outputTokens: 50,
|
|
2012
|
-
model: "test-model",
|
|
2013
|
-
providerDurationMs: 100,
|
|
2014
|
-
});
|
|
2015
|
-
|
|
2016
|
-
// Always yield at checkpoint — simulates reduction not helping enough
|
|
2017
|
-
if (onCheckpoint) {
|
|
2018
|
-
const decision = await onCheckpoint({
|
|
2019
|
-
turnIndex: 0,
|
|
2020
|
-
toolCount: 1,
|
|
2021
|
-
hasToolUse: true,
|
|
2022
|
-
history: withProgress,
|
|
2023
|
-
});
|
|
2024
|
-
if (decision === "yield") {
|
|
2025
|
-
return withProgress;
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
return withProgress;
|
|
2030
|
-
};
|
|
1581
|
+
// Every provider call returns a tool_use, so each loop run does a tool
|
|
1582
|
+
// turn that trips the mid-loop budget gate and yields "budget". The
|
|
1583
|
+
// initial run's gate calls compaction (exhausted); the convergence
|
|
1584
|
+
// reruns run without a compaction hook and yield directly.
|
|
1585
|
+
const { provider, calls } = createMockProvider([
|
|
1586
|
+
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1587
|
+
]);
|
|
2031
1588
|
|
|
2032
1589
|
// Convergence reducer: first call returns non-exhausted, second returns exhausted
|
|
2033
1590
|
let reducerCallCount = 0;
|
|
@@ -2059,9 +1616,25 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
2059
1616
|
};
|
|
2060
1617
|
|
|
2061
1618
|
const ctx = makeCtx({
|
|
2062
|
-
|
|
1619
|
+
loopProvider: provider,
|
|
1620
|
+
loopTools: [
|
|
1621
|
+
{
|
|
1622
|
+
name: "bash",
|
|
1623
|
+
description: "Run a shell command",
|
|
1624
|
+
input_schema: {
|
|
1625
|
+
type: "object",
|
|
1626
|
+
properties: { command: { type: "string" } },
|
|
1627
|
+
},
|
|
1628
|
+
},
|
|
1629
|
+
],
|
|
1630
|
+
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
2063
1631
|
contextWindowManager: {
|
|
2064
1632
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1633
|
+
// Under the new architecture (Compaction Re-homing Arc, Bullet 1)
|
|
1634
|
+
// the retry budget lives inside `ContextWindowManager._maybeCompact`,
|
|
1635
|
+
// so a single daemon-level call represents the full manager retry
|
|
1636
|
+
// sequence. Signal `exhausted: true` immediately to escalate the
|
|
1637
|
+
// mid-loop to the convergence reducer.
|
|
2065
1638
|
maybeCompact: async () => ({
|
|
2066
1639
|
compacted: true,
|
|
2067
1640
|
messages: [
|
|
@@ -2081,6 +1654,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
2081
1654
|
summaryInputTokens: 500,
|
|
2082
1655
|
summaryOutputTokens: 200,
|
|
2083
1656
|
summaryModel: "mock-model",
|
|
1657
|
+
exhausted: true,
|
|
2084
1658
|
}),
|
|
2085
1659
|
} as unknown as AgentLoopConversationContext["contextWindowManager"],
|
|
2086
1660
|
});
|
|
@@ -2091,8 +1665,11 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
2091
1665
|
// once more after yieldedForBudget triggered re-entry
|
|
2092
1666
|
expect(reducerCallCount).toBe(2);
|
|
2093
1667
|
|
|
2094
|
-
//
|
|
2095
|
-
|
|
1668
|
+
// Provider calls: 1 initial run + 2 convergence reruns = 3 calls, each a
|
|
1669
|
+
// tool turn that yields "budget". The mid-loop no longer drives
|
|
1670
|
+
// daemon-level retries — the manager owns its retry budget and signals
|
|
1671
|
+
// exhaustion via the `exhausted` flag.
|
|
1672
|
+
expect(calls.length).toBe(3);
|
|
2096
1673
|
expect(setAgentLoopExitReasonOnLatestLogMock).toHaveBeenCalledWith(
|
|
2097
1674
|
"test-conv",
|
|
2098
1675
|
"context_too_large",
|
|
@@ -2192,32 +1769,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
2192
1769
|
};
|
|
2193
1770
|
};
|
|
2194
1771
|
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
type: "message_complete",
|
|
2198
|
-
message: {
|
|
2199
|
-
role: "assistant",
|
|
2200
|
-
content: [{ type: "text", text: "done" }],
|
|
2201
|
-
},
|
|
2202
|
-
});
|
|
2203
|
-
onEvent({
|
|
2204
|
-
type: "usage",
|
|
2205
|
-
inputTokens: 170_000,
|
|
2206
|
-
outputTokens: 200,
|
|
2207
|
-
model: "test-model",
|
|
2208
|
-
providerDurationMs: 500,
|
|
2209
|
-
});
|
|
2210
|
-
return [
|
|
2211
|
-
...messages,
|
|
2212
|
-
{
|
|
2213
|
-
role: "assistant" as const,
|
|
2214
|
-
content: [{ type: "text", text: "done" }] as ContentBlock[],
|
|
2215
|
-
},
|
|
2216
|
-
];
|
|
2217
|
-
};
|
|
2218
|
-
|
|
1772
|
+
// The preflight overflow reducer runs in the orchestrator before the loop,
|
|
1773
|
+
// so a single successful provider turn is enough to drive the path.
|
|
2219
1774
|
const ctx = makeCtx({
|
|
2220
|
-
|
|
1775
|
+
providerResponses: [textResponse("done")],
|
|
2221
1776
|
contextWindowManager: {
|
|
2222
1777
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
2223
1778
|
maybeCompact: async () => ({ compacted: false }),
|
|
@@ -2288,108 +1843,100 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
2288
1843
|
// emergency compaction + final agentLoop.run path executes.
|
|
2289
1844
|
mockOverflowAction = "auto_compress_latest_turn";
|
|
2290
1845
|
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
onCheckpoint,
|
|
2298
|
-
) => {
|
|
2299
|
-
agentLoopCallCount++;
|
|
2300
|
-
|
|
2301
|
-
const withProgress: Message[] = [
|
|
2302
|
-
...messages,
|
|
2303
|
-
{
|
|
2304
|
-
role: "assistant" as const,
|
|
2305
|
-
content: [
|
|
2306
|
-
{ type: "text", text: `tool call ${agentLoopCallCount}` },
|
|
2307
|
-
{
|
|
2308
|
-
type: "tool_use",
|
|
2309
|
-
id: `tu-${agentLoopCallCount}`,
|
|
2310
|
-
name: "bash",
|
|
2311
|
-
input: { command: "ls" },
|
|
2312
|
-
},
|
|
2313
|
-
] as ContentBlock[],
|
|
2314
|
-
},
|
|
2315
|
-
{
|
|
2316
|
-
role: "user" as const,
|
|
2317
|
-
content: [
|
|
2318
|
-
{
|
|
2319
|
-
type: "tool_result",
|
|
2320
|
-
tool_use_id: `tu-${agentLoopCallCount}`,
|
|
2321
|
-
content: "output",
|
|
2322
|
-
is_error: false,
|
|
2323
|
-
},
|
|
2324
|
-
] as ContentBlock[],
|
|
2325
|
-
},
|
|
2326
|
-
];
|
|
2327
|
-
|
|
2328
|
-
onEvent({
|
|
2329
|
-
type: "message_complete",
|
|
2330
|
-
message: {
|
|
2331
|
-
role: "assistant",
|
|
2332
|
-
content: [
|
|
2333
|
-
{ type: "text", text: `tool call ${agentLoopCallCount}` },
|
|
2334
|
-
{
|
|
2335
|
-
type: "tool_use",
|
|
2336
|
-
id: `tu-${agentLoopCallCount}`,
|
|
2337
|
-
name: "bash",
|
|
2338
|
-
input: { command: "ls" },
|
|
2339
|
-
},
|
|
2340
|
-
],
|
|
2341
|
-
},
|
|
2342
|
-
});
|
|
2343
|
-
onEvent({
|
|
2344
|
-
type: "usage",
|
|
2345
|
-
inputTokens: 100,
|
|
2346
|
-
outputTokens: 50,
|
|
2347
|
-
model: "test-model",
|
|
2348
|
-
providerDurationMs: 100,
|
|
2349
|
-
});
|
|
2350
|
-
|
|
2351
|
-
// Every checkpoint yields — including the final auto_compress rerun.
|
|
2352
|
-
if (onCheckpoint) {
|
|
2353
|
-
const decision = await onCheckpoint({
|
|
2354
|
-
turnIndex: 0,
|
|
2355
|
-
toolCount: 1,
|
|
2356
|
-
hasToolUse: true,
|
|
2357
|
-
history: withProgress,
|
|
2358
|
-
});
|
|
2359
|
-
if (decision === "yield") {
|
|
2360
|
-
return withProgress;
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
|
|
2364
|
-
return withProgress;
|
|
2365
|
-
};
|
|
1846
|
+
// Every provider call returns a tool_use, so each loop run does a tool
|
|
1847
|
+
// turn that trips the mid-loop budget gate and yields "budget" —
|
|
1848
|
+
// including the final auto_compress rerun.
|
|
1849
|
+
const { provider } = createMockProvider([
|
|
1850
|
+
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1851
|
+
]);
|
|
2366
1852
|
|
|
1853
|
+
// `maybeCompact` is invoked through three distinct call sites:
|
|
1854
|
+
// 1. Start-of-turn compaction (no `force` option) — return a no-op
|
|
1855
|
+
// so the start-of-turn pass doesn't perturb state. The mock's
|
|
1856
|
+
// `shouldCompact` already returns `needed: false`, but the
|
|
1857
|
+
// orchestrator still invokes the compaction pipeline.
|
|
1858
|
+
// 2. Mid-loop after the initial agent-loop yield (`force: true`) —
|
|
1859
|
+
// must signal `exhausted: true` so the daemon escalates to the
|
|
1860
|
+
// convergence reducer instead of looping forever.
|
|
1861
|
+
// 3. auto_compress_latest_turn emergency compaction (`force: true`,
|
|
1862
|
+
// `minKeepRecentUserTurns: 0`) — succeeds and drops tokens below
|
|
1863
|
+
// threshold; the subsequent rerun yields again and is classified
|
|
1864
|
+
// as BUDGET_YIELD_UNRECOVERED.
|
|
1865
|
+
let forcedMaybeCompactCallCount = 0;
|
|
2367
1866
|
const ctx = makeCtx({
|
|
2368
|
-
|
|
1867
|
+
loopProvider: provider,
|
|
1868
|
+
loopTools: [
|
|
1869
|
+
{
|
|
1870
|
+
name: "bash",
|
|
1871
|
+
description: "Run a shell command",
|
|
1872
|
+
input_schema: {
|
|
1873
|
+
type: "object",
|
|
1874
|
+
properties: { command: { type: "string" } },
|
|
1875
|
+
},
|
|
1876
|
+
},
|
|
1877
|
+
],
|
|
1878
|
+
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
2369
1879
|
contextWindowManager: {
|
|
2370
1880
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
}
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
1881
|
+
maybeCompact: async (
|
|
1882
|
+
_msgs: Message[],
|
|
1883
|
+
_signal: AbortSignal,
|
|
1884
|
+
opts?: { force?: boolean },
|
|
1885
|
+
) => {
|
|
1886
|
+
// Start-of-turn calls pass no `force` option; route them to a
|
|
1887
|
+
// no-op so only the mid-loop and emergency paths drive the test.
|
|
1888
|
+
if (!opts?.force) {
|
|
1889
|
+
return { compacted: false };
|
|
1890
|
+
}
|
|
1891
|
+
forcedMaybeCompactCallCount++;
|
|
1892
|
+
if (forcedMaybeCompactCallCount === 1) {
|
|
1893
|
+
// Mid-loop call — under the new architecture (Compaction
|
|
1894
|
+
// Re-homing Arc, Bullet 1) the manager owns its own retry
|
|
1895
|
+
// budget; signal exhaustion to escalate to convergence.
|
|
1896
|
+
return {
|
|
1897
|
+
compacted: true,
|
|
1898
|
+
messages: [
|
|
1899
|
+
{
|
|
1900
|
+
role: "user" as const,
|
|
1901
|
+
content: [{ type: "text", text: "mid-loop compacted" }],
|
|
1902
|
+
},
|
|
1903
|
+
] as Message[],
|
|
1904
|
+
compactedPersistedMessages: 5,
|
|
1905
|
+
summaryText: "Mid-loop summary",
|
|
1906
|
+
previousEstimatedInputTokens: 170_000,
|
|
1907
|
+
estimatedInputTokens: 165_000,
|
|
1908
|
+
maxInputTokens: 200_000,
|
|
1909
|
+
thresholdTokens: 160_000,
|
|
1910
|
+
compactedMessages: 10,
|
|
1911
|
+
summaryCalls: 1,
|
|
1912
|
+
summaryInputTokens: 500,
|
|
1913
|
+
summaryOutputTokens: 200,
|
|
1914
|
+
summaryModel: "mock-model",
|
|
1915
|
+
exhausted: true,
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
// Emergency compaction call from auto_compress_latest_turn.
|
|
1919
|
+
return {
|
|
1920
|
+
compacted: true,
|
|
1921
|
+
messages: [
|
|
1922
|
+
{
|
|
1923
|
+
role: "user" as const,
|
|
1924
|
+
content: [{ type: "text", text: "compacted" }],
|
|
1925
|
+
},
|
|
1926
|
+
] as Message[],
|
|
1927
|
+
compactedPersistedMessages: 5,
|
|
1928
|
+
summaryText: "Emergency summary",
|
|
1929
|
+
previousEstimatedInputTokens: 170_000,
|
|
1930
|
+
estimatedInputTokens: 90_000,
|
|
1931
|
+
maxInputTokens: 200_000,
|
|
1932
|
+
thresholdTokens: 160_000,
|
|
1933
|
+
compactedMessages: 10,
|
|
1934
|
+
summaryCalls: 1,
|
|
1935
|
+
summaryInputTokens: 500,
|
|
1936
|
+
summaryOutputTokens: 200,
|
|
1937
|
+
summaryModel: "mock-model",
|
|
1938
|
+
};
|
|
1939
|
+
},
|
|
2393
1940
|
} as unknown as AgentLoopConversationContext["contextWindowManager"],
|
|
2394
1941
|
});
|
|
2395
1942
|
|