@vellumai/assistant 0.6.5 → 0.7.0
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 +29 -1
- package/ARCHITECTURE.md +60 -53
- package/Dockerfile +25 -3
- package/README.md +8 -10
- package/__tests__/permissions/gateway-threshold-reader.test.ts +277 -0
- package/bun.lock +306 -119
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +26 -120
- package/docs/architecture/security.md +22 -36
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/credential-execution-service.md +7 -5
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/bun.lock +25 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +8 -22
- package/node_modules/@vellumai/ces-client/bun.lock +33 -0
- package/node_modules/@vellumai/ces-client/package.json +25 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
- package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
- package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
- package/node_modules/@vellumai/gateway-client/package.json +23 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
- package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +891 -0
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
- package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +91 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1348 -0
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +333 -0
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
- package/openapi.yaml +3135 -692
- package/package.json +13 -7
- package/scripts/check-circular-deps.ts +80 -0
- package/scripts/generate-openapi.ts +24 -7
- package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +28 -28
- package/src/__tests__/access-request-decision.test.ts +2 -11
- package/src/__tests__/acp-session.test.ts +4 -150
- package/src/__tests__/actor-token-service.test.ts +17 -678
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
- package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
- package/src/__tests__/agent-loop-thinking.test.ts +4 -4
- package/src/__tests__/agent-wake-override-profile.test.ts +261 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
- package/src/__tests__/anthropic-provider.test.ts +127 -15
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/app-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +10 -357
- package/src/__tests__/approval-conversation-turn.test.ts +3 -8
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +2 -1
- package/src/__tests__/approval-routes-http.test.ts +34 -451
- package/src/__tests__/assistant-events-sse-hardening.test.ts +73 -80
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
- package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
- package/src/__tests__/attachments-store.test.ts +46 -1
- package/src/__tests__/audit-log-rotation.test.ts +2 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -20
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/background-shell-bash.test.ts +227 -0
- package/src/__tests__/background-shell-host-bash.test.ts +474 -0
- package/src/__tests__/background-tool-registry.test.ts +145 -0
- package/src/__tests__/background-tool-routes.test.ts +175 -0
- package/src/__tests__/btw-routes.test.ts +147 -183
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +15 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -1
- package/src/__tests__/call-domain.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +11 -13
- package/src/__tests__/call-recovery.test.ts +2 -1
- package/src/__tests__/call-routes-http.test.ts +3 -14
- package/src/__tests__/call-store.test.ts +2 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
- package/src/__tests__/canonical-guardian-store.test.ts +2 -2
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/catalog-files.test.ts +0 -26
- package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +79 -49
- package/src/__tests__/channel-approval.test.ts +9 -7
- package/src/__tests__/channel-approvals.test.ts +9 -180
- package/src/__tests__/channel-delivery-store.test.ts +11 -10
- package/src/__tests__/channel-guardian.test.ts +14 -25
- package/src/__tests__/channel-readiness-service.test.ts +8 -6
- package/src/__tests__/channel-reply-delivery.test.ts +3 -19
- package/src/__tests__/channel-retry-sweep.test.ts +2 -5
- package/src/__tests__/checker.test.ts +447 -3806
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
- package/src/__tests__/cli.test.ts +1 -38
- package/src/__tests__/compaction-events.test.ts +500 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +109 -0
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +25 -203
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
- package/src/__tests__/contact-store-user-file.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +71 -18
- package/src/__tests__/contacts-write.test.ts +6 -61
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
- package/src/__tests__/context-search-agent-runner.test.ts +998 -0
- package/src/__tests__/context-search-conversations-source.test.ts +320 -0
- package/src/__tests__/context-search-fanout.test.ts +380 -0
- package/src/__tests__/context-search-memory-source.test.ts +311 -0
- package/src/__tests__/context-search-pkb-source.test.ts +444 -0
- package/src/__tests__/context-search-types.test.ts +95 -0
- package/src/__tests__/context-search-workspace-source.test.ts +545 -0
- package/src/__tests__/context-window-manager.test.ts +380 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +14 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +631 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +41 -32
- package/src/__tests__/conversation-agent-loop.test.ts +54 -143
- package/src/__tests__/conversation-analysis-routes.test.ts +60 -82
- package/src/__tests__/conversation-attachments.test.ts +9 -20
- package/src/__tests__/conversation-attention-store.test.ts +2 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +4 -2
- package/src/__tests__/conversation-clear-safety.test.ts +53 -95
- package/src/__tests__/conversation-confirmation-signals.test.ts +7 -40
- package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +5 -4
- package/src/__tests__/conversation-fork-crud.test.ts +26 -55
- package/src/__tests__/conversation-fork-route.test.ts +5 -74
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +216 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +4 -95
- package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +0 -1
- package/src/__tests__/conversation-list-source.test.ts +2 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
- package/src/__tests__/conversation-pairing.test.ts +174 -11
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -294
- package/src/__tests__/conversation-process-callsite.test.ts +3 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +22 -8
- package/src/__tests__/conversation-queue.test.ts +30 -47
- package/src/__tests__/conversation-routes-disk-view.test.ts +131 -103
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +80 -55
- package/src/__tests__/conversation-routes-slash-commands.test.ts +83 -12
- package/src/__tests__/conversation-runtime-assembly.test.ts +196 -194
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-commands.test.ts +6 -43
- package/src/__tests__/conversation-slash-queue.test.ts +7 -3
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -3
- package/src/__tests__/conversation-speed-override.test.ts +6 -2
- package/src/__tests__/conversation-starter-routes.test.ts +177 -55
- package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +2 -375
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +42 -3
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
- package/src/__tests__/conversation-unread-route.test.ts +1 -1
- package/src/__tests__/conversation-usage.test.ts +3 -2
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -2
- package/src/__tests__/conversations-defer-cli.test.ts +150 -0
- package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
- package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
- package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
- package/src/__tests__/credential-execution-client.test.ts +1 -1
- package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +16 -2
- package/src/__tests__/credentials-cli.test.ts +45 -21
- package/src/__tests__/daemon-credential-client.test.ts +23 -108
- package/src/__tests__/db-acp-history.test.ts +284 -0
- package/src/__tests__/db-activation-state.test.ts +240 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/delete-propagation.test.ts +3 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +39 -32
- package/src/__tests__/dm-backfill.test.ts +3 -2
- package/src/__tests__/edit-propagation.test.ts +5 -7
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +1 -1
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/events-client-registration.test.ts +297 -0
- package/src/__tests__/file-write-tool.test.ts +2 -4
- package/src/__tests__/filing-service.test.ts +144 -17
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/followup-tools.test.ts +2 -1
- package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
- package/src/__tests__/gateway-only-guard.test.ts +4 -3
- package/src/__tests__/gemini-provider.test.ts +276 -10
- package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
- package/src/__tests__/guardian-action-store.test.ts +2 -1
- package/src/__tests__/guardian-action-sweep.test.ts +9 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
- package/src/__tests__/guardian-dispatch.test.ts +14 -11
- package/src/__tests__/guardian-grant-minting.test.ts +9 -15
- package/src/__tests__/guardian-outbound-http.test.ts +71 -106
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +34 -90
- package/src/__tests__/guardian-routing-state.test.ts +14 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +253 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +8 -4
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +39 -21
- package/src/__tests__/helpers/call-route-handler.ts +72 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
- package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
- package/src/__tests__/helpers/mock-logger.ts +36 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-browser-e2e-cloud.test.ts +309 -1
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +12 -2
- package/src/__tests__/host-browser-routes.test.ts +36 -91
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +10 -2
- package/src/__tests__/host-proxy-interface.test.ts +38 -4
- package/src/__tests__/host-shell-tool.test.ts +2 -4
- package/src/__tests__/host-transfer-pending-interactions.test.ts +160 -0
- package/src/__tests__/host-transfer-proxy.test.ts +733 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +20 -11
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/injector-chain.test.ts +525 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -206
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/invite-redemption-service.test.ts +2 -1
- package/src/__tests__/invite-routes-http.test.ts +80 -12
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
- package/src/__tests__/list-messages-attachments.test.ts +52 -55
- package/src/__tests__/list-messages-page-latest.test.ts +283 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
- package/src/__tests__/llm-call-pipeline.test.ts +284 -0
- package/src/__tests__/llm-context-normalization.test.ts +69 -4
- package/src/__tests__/llm-context-route-provider.test.ts +39 -113
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
- package/src/__tests__/llm-resolver.test.ts +211 -0
- package/src/__tests__/llm-schema.test.ts +56 -0
- package/src/__tests__/llm-usage-store.test.ts +2 -1
- package/src/__tests__/log-export-workspace.test.ts +28 -17
- package/src/__tests__/mcp-abort-signal.test.ts +2 -3
- package/src/__tests__/mcp-client-auth.test.ts +2 -3
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-admin-recall.test.ts +221 -0
- package/src/__tests__/memory-recall-log-store.test.ts +2 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +399 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +14 -13
- package/src/__tests__/migration-export-http.test.ts +17 -17
- package/src/__tests__/migration-export-to-gcs.test.ts +491 -0
- package/src/__tests__/migration-import-commit-http.test.ts +16 -16
- package/src/__tests__/migration-import-from-gcs.test.ts +533 -0
- package/src/__tests__/migration-import-from-url.test.ts +21 -91
- package/src/__tests__/migration-import-preflight-http.test.ts +13 -13
- package/src/__tests__/migration-jobs-status.test.ts +164 -0
- package/src/__tests__/migration-validate-http.test.ts +48 -83
- package/src/__tests__/mock-gateway-ipc.ts +32 -62
- package/src/__tests__/model-intents.test.ts +16 -1
- package/src/__tests__/nl-approval-parser.test.ts +13 -17
- package/src/__tests__/non-member-access-request.test.ts +13 -5
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +109 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +77 -123
- package/src/__tests__/oauth-cli.test.ts +28 -13
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +6 -6
- package/src/__tests__/oauth-providers-routes.test.ts +81 -103
- package/src/__tests__/oauth-store.test.ts +44 -77
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +105 -6
- package/src/__tests__/openai-responses-provider.test.ts +146 -4
- package/src/__tests__/openrouter-provider-only.test.ts +22 -4
- package/src/__tests__/overflow-reduce-pipeline.test.ts +671 -0
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +378 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +27 -20
- package/src/__tests__/platform.test.ts +10 -59
- package/src/__tests__/playbook-execution.test.ts +2 -1
- package/src/__tests__/playbook-tools.test.ts +2 -1
- package/src/__tests__/plugin-bootstrap.test.ts +529 -0
- package/src/__tests__/plugin-registry.test.ts +303 -0
- package/src/__tests__/plugin-route-contribution.test.ts +294 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +292 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +195 -14
- package/src/__tests__/profiler-routes.test.ts +112 -177
- package/src/__tests__/provider-send-message-override-profile.test.ts +223 -0
- package/src/__tests__/proxy-approval-callback.test.ts +6 -493
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +4 -2
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +0 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +1 -2
- package/src/__tests__/relay-server.test.ts +19 -4
- package/src/__tests__/require-fresh-approval.test.ts +19 -168
- package/src/__tests__/resolve-trust-class.test.ts +2 -1
- package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
- package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
- package/src/__tests__/runtime-events-sse-parity.test.ts +12 -13
- package/src/__tests__/runtime-events-sse.test.ts +13 -21
- package/src/__tests__/schedule-routes.test.ts +304 -77
- package/src/__tests__/schedule-store.test.ts +119 -1
- package/src/__tests__/schedule-tools.test.ts +2 -1
- package/src/__tests__/scheduler-recurrence.test.ts +16 -71
- package/src/__tests__/scheduler-reuse-conversation.test.ts +12 -51
- package/src/__tests__/scheduler-wake.test.ts +356 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
- package/src/__tests__/secret-detection-handler.test.ts +2 -19
- package/src/__tests__/secret-ingress-http.test.ts +38 -21
- package/src/__tests__/secret-routes-managed-proxy.test.ts +46 -102
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +38 -25
- package/src/__tests__/sequence-store.test.ts +2 -1
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
- package/src/__tests__/set-permission-mode.test.ts +0 -10
- package/src/__tests__/settings-routes.test.ts +35 -68
- package/src/__tests__/skill-boundary-guard.test.ts +105 -0
- package/src/__tests__/skill-load-inline-command.test.ts +2 -2
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-runtime-path.test.ts +64 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +11 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
- package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
- package/src/__tests__/slack-share-routes.test.ts +37 -72
- package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
- package/src/__tests__/subagent-notify-parent.test.ts +6 -29
- package/src/__tests__/subagent-role-registry.test.ts +3 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
- package/src/__tests__/subagent-tools.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +149 -57
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-management-tools.test.ts +2 -1
- package/src/__tests__/task-memory-cleanup.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +5 -16
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +5 -314
- package/src/__tests__/thread-backfill.test.ts +3 -2
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +484 -0
- package/src/__tests__/tool-approval-handler.test.ts +21 -63
- package/src/__tests__/tool-audit-listener.test.ts +3 -3
- package/src/__tests__/tool-domain-event-publisher.test.ts +3 -3
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +429 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +61 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +28 -56
- package/src/__tests__/tool-executor.test.ts +434 -1604
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
- package/src/__tests__/trusted-contact-verification.test.ts +2 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
- package/src/__tests__/twilio-routes.test.ts +25 -66
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
- package/src/__tests__/usage-routes.test.ts +73 -90
- package/src/__tests__/user-plugin-loader.test.ts +233 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -2
- package/src/__tests__/verification-control-plane-policy.test.ts +95 -14
- package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
- package/src/__tests__/voice-invite-redemption.test.ts +2 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
- package/src/__tests__/voice-session-bridge.test.ts +285 -106
- package/src/__tests__/volume-security-guard.test.ts +0 -2
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
- package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
- package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
- package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
- package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +274 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/acp/__tests__/client-handler.test.ts +64 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
- package/src/acp/__tests__/helpers/which-stub.ts +45 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
- package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
- package/src/acp/__tests__/session-manager.test.ts +83 -0
- package/src/acp/client-handler.ts +23 -139
- package/src/acp/resolve-agent.test.ts +291 -0
- package/src/acp/resolve-agent.ts +176 -0
- package/src/acp/session-manager.ts +166 -7
- package/src/acp/types.ts +2 -50
- package/src/agent/loop.ts +365 -104
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +296 -0
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +109 -103
- package/src/avatar/character-components.ts +6 -6
- package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -15
- package/src/backup/__tests__/paths.test.ts +3 -2
- package/src/backup/backup-worker.ts +3 -24
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +7 -11
- package/src/browser/__tests__/operations.test.ts +0 -35
- package/src/browser/operations.ts +1 -47
- package/src/bundler/app-compiler.ts +84 -1
- package/src/bundler/package-resolver.ts +2 -6
- package/src/calls/active-call-lease.ts +1 -1
- package/src/calls/call-constants.ts +1 -1
- package/src/calls/call-controller.ts +1 -5
- package/src/calls/call-domain.ts +14 -14
- package/src/calls/call-pointer-messages.ts +4 -9
- package/src/calls/call-state.ts +2 -2
- package/src/calls/call-store.ts +2 -1
- package/src/calls/guardian-action-sweep.ts +9 -25
- package/src/calls/guardian-dispatch.ts +1 -20
- package/src/calls/media-stream-audio-transcode.ts +2 -41
- package/src/calls/media-stream-server.ts +2 -3
- package/src/calls/media-stream-stt-session.ts +1 -3
- package/src/calls/relay-access-wait.ts +5 -8
- package/src/calls/relay-server.ts +15 -18
- package/src/calls/relay-setup-router.ts +2 -2
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/twilio-routes.ts +160 -78
- package/src/calls/voice-control-protocol.ts +10 -10
- package/src/calls/voice-ingress-preflight.ts +2 -2
- package/src/calls/voice-session-bridge.ts +137 -42
- package/src/channels/__tests__/types.test.ts +28 -6
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +48 -30
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +92 -214
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +4 -15
- package/src/cli/commands/__tests__/browser.test.ts +36 -31
- package/src/cli/commands/__tests__/cache.test.ts +23 -18
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +396 -0
- package/src/cli/commands/__tests__/task.test.ts +36 -35
- package/src/cli/commands/__tests__/trust.test.ts +602 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
- package/src/cli/commands/__tests__/ui.test.ts +17 -17
- package/src/cli/commands/__tests__/watchers.test.ts +29 -29
- package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
- package/src/cli/commands/attachment.ts +12 -8
- package/src/cli/commands/auth.ts +1 -1
- package/src/cli/commands/avatar.ts +192 -9
- package/src/cli/commands/backup.ts +16 -46
- package/src/cli/commands/browser.ts +52 -4
- package/src/cli/commands/cache.ts +7 -5
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/clients.ts +137 -0
- package/src/cli/commands/completions.ts +3 -10
- package/src/cli/commands/contacts.ts +10 -10
- package/src/cli/commands/conversations-defer.ts +364 -0
- package/src/cli/commands/conversations-import.ts +2 -3
- package/src/cli/commands/conversations.ts +115 -57
- package/src/cli/commands/credential-execution.ts +1 -1
- package/src/cli/commands/credentials.ts +139 -5
- package/src/cli/commands/default-action.ts +1 -1
- package/src/cli/commands/domain.ts +2 -2
- package/src/cli/commands/email.ts +7 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/keys.ts +2 -2
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory-v2.ts +343 -0
- package/src/cli/commands/memory.ts +8 -8
- package/src/cli/commands/notifications.ts +87 -121
- package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +4 -4
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/shared.ts +29 -2
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
- package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
- package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
- package/src/cli/commands/platform/connect.ts +3 -3
- package/src/cli/commands/platform/disconnect.ts +4 -6
- package/src/cli/commands/platform/index.ts +12 -10
- package/src/cli/commands/routes.ts +7 -1
- package/src/cli/commands/sequence.ts +7 -7
- package/src/cli/commands/skills.ts +189 -84
- package/src/cli/commands/task.ts +12 -10
- package/src/cli/commands/trust.ts +460 -162
- package/src/cli/commands/ui.ts +3 -3
- package/src/cli/commands/usage.ts +10 -5
- package/src/cli/commands/watchers.ts +8 -8
- package/src/cli/commands/webhooks.ts +270 -0
- package/src/cli/lib/daemon-avatar-client.ts +37 -0
- package/src/cli/lib/daemon-credential-client.ts +27 -189
- package/src/cli/lib/ipc-params.ts +22 -0
- package/src/cli/program.ts +29 -29
- package/src/cli.ts +1 -61
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/acp-defaults.test.ts +57 -0
- package/src/config/acp-defaults.ts +40 -0
- package/src/config/acp-schema.ts +1 -1
- package/src/config/assistant-feature-flags.ts +18 -142
- package/src/config/bundled-skills/acp/SKILL.md +44 -16
- package/src/config/bundled-skills/acp/TOOLS.json +45 -1
- package/src/config/bundled-skills/{screen-watch/tools/start-screen-watch.ts → acp/tools/acp-list-agents.ts} +2 -2
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +25 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +31 -44
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
- package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/SKILL.md +2 -17
- package/src/config/bundled-skills/settings/TOOLS.json +0 -56
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-tool-registry.ts +4 -21
- package/src/config/env.ts +7 -8
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +51 -33
- package/src/config/loader.ts +12 -15
- package/src/config/schema.ts +22 -70
- package/src/config/schemas/__tests__/filing.test.ts +58 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +186 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +12 -0
- package/src/config/schemas/host-browser.ts +2 -2
- package/src/config/schemas/inference.ts +0 -2
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +51 -10
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory-v2.ts +176 -0
- package/src/config/schemas/memory.ts +2 -0
- package/src/config/schemas/security.ts +0 -60
- package/src/config/schemas/services.ts +46 -7
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +95 -6
- package/src/config/types.ts +0 -41
- package/src/contacts/contact-store.ts +2 -2
- package/src/contacts/contacts-write.ts +0 -38
- package/src/contacts/types.ts +8 -10
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +4 -64
- package/src/context/window-manager.ts +191 -17
- package/src/credential-execution/approval-bridge.ts +7 -69
- package/src/credential-execution/client.ts +17 -422
- package/src/credential-execution/feature-gates.ts +1 -2
- package/src/credential-execution/managed-catalog.ts +1 -1
- package/src/credential-health/credential-health-service.ts +20 -7
- package/src/daemon/__tests__/conversation-feed-event.test.ts +304 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/__tests__/daemon-skill-host.test.ts +272 -0
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
- package/src/daemon/approval-generators.ts +2 -14
- package/src/daemon/classifier.ts +0 -106
- package/src/daemon/config-watcher.ts +14 -56
- package/src/daemon/connection-policy.ts +0 -14
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +120 -28
- package/src/daemon/conversation-agent-loop.ts +1113 -701
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +11 -20
- package/src/daemon/conversation-launch.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-notifiers.ts +3 -111
- package/src/daemon/conversation-process.ts +23 -20
- package/src/daemon/conversation-runtime-assembly.ts +530 -471
- package/src/daemon/conversation-slash.ts +4 -160
- package/src/daemon/conversation-store.ts +368 -0
- package/src/daemon/conversation-surfaces.ts +5 -4
- package/src/daemon/conversation-tool-setup.ts +49 -161
- package/src/daemon/conversation.ts +126 -217
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/daemon-skill-host.ts +262 -0
- package/src/daemon/external-plugins-bootstrap.ts +532 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-channels.ts +2 -2
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/config-ingress.ts +24 -2
- package/src/daemon/handlers/config-model.test.ts +17 -0
- package/src/daemon/handlers/config-model.ts +18 -52
- package/src/daemon/handlers/config-telegram.ts +6 -53
- package/src/daemon/handlers/config-voice.ts +1 -1
- package/src/daemon/handlers/conversations.ts +22 -156
- package/src/daemon/handlers/recording.ts +1 -1
- package/src/daemon/handlers/shared.ts +34 -35
- package/src/daemon/handlers/skills.ts +20 -24
- package/src/daemon/host-transfer-proxy.ts +500 -0
- package/src/daemon/lifecycle.ts +56 -326
- package/src/daemon/meet-host-startup.ts +51 -0
- package/src/daemon/meet-host-supervisor.ts +781 -0
- package/src/daemon/meet-manifest-loader.ts +410 -0
- package/src/daemon/memory-v2-startup.ts +35 -0
- package/src/daemon/message-protocol.ts +4 -7
- package/src/daemon/message-types/acp.ts +1 -0
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +65 -2
- package/src/daemon/message-types/host-transfer.ts +41 -0
- package/src/daemon/message-types/integrations.ts +6 -0
- package/src/daemon/message-types/messages.ts +26 -14
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +0 -6
- package/src/daemon/message-types/shared.ts +5 -2
- package/src/daemon/message-types/subagents.ts +2 -1
- package/src/daemon/message-types/workspace.ts +0 -2
- package/src/daemon/pkb-reminder-builder.test.ts +13 -12
- package/src/daemon/pkb-reminder-builder.ts +8 -16
- package/src/daemon/process-message.ts +616 -0
- package/src/daemon/providers-setup.ts +14 -6
- package/src/daemon/server.ts +79 -1272
- package/src/daemon/shutdown-handlers.ts +3 -13
- package/src/daemon/startup-error.ts +1 -1
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +223 -0
- package/src/email/feature-gate.ts +1 -1
- package/src/events/domain-events.ts +1 -8
- package/src/events/tool-audit-listener.ts +2 -8
- package/src/events/tool-metrics-listener.ts +1 -4
- package/src/filing/filing-service.ts +194 -54
- package/src/followups/followup-store.ts +3 -71
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +52 -8
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
- package/src/home/__tests__/rollup-producer.test.ts +67 -2
- package/src/home/assistant-feed-authoring.ts +8 -1
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +42 -3
- package/src/home/relationship-state-writer.ts +1 -1
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rewrite-feed-title.ts +58 -0
- package/src/home/rollup-producer.ts +16 -3
- package/src/inbound/platform-callback-registration.ts +1 -17
- package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
- package/src/ipc/__tests__/browser-ipc.test.ts +75 -51
- package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
- package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +254 -0
- package/src/ipc/__tests__/skill-server.test.ts +182 -0
- package/src/ipc/__tests__/socket-path.test.ts +44 -37
- package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
- package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
- package/src/ipc/assistant-server.ts +450 -0
- package/src/ipc/cli-client.ts +3 -3
- package/src/ipc/gateway-client.test.ts +131 -0
- package/src/ipc/gateway-client.ts +98 -120
- package/src/ipc/ipc-framing.ts +281 -0
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +152 -0
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +219 -0
- package/src/ipc/routes/db-proxy.ts +73 -0
- package/src/ipc/routes/route-adapter.ts +32 -0
- package/src/ipc/routes/trust-rules.test.ts +218 -0
- package/src/ipc/skill-ipc-types.ts +13 -0
- package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +402 -0
- package/src/ipc/skill-routes/__tests__/identity.test.ts +81 -0
- package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
- package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
- package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
- package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
- package/src/ipc/skill-routes/config.ts +47 -0
- package/src/ipc/skill-routes/events.ts +131 -0
- package/src/ipc/skill-routes/identity.ts +34 -0
- package/src/ipc/skill-routes/index.ts +37 -0
- package/src/ipc/skill-routes/log.ts +40 -0
- package/src/ipc/skill-routes/memory.ts +76 -0
- package/src/ipc/skill-routes/platform.ts +39 -0
- package/src/ipc/skill-routes/providers.ts +163 -0
- package/src/ipc/skill-routes/registries.ts +393 -0
- package/src/ipc/skill-server.ts +771 -0
- package/src/ipc/skill-socket-path.ts +20 -0
- package/src/ipc/socket-cleanup.ts +92 -0
- package/src/ipc/socket-path.ts +55 -48
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
- package/src/live-voice/__tests__/protocol.test.ts +295 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +421 -0
- package/src/live-voice/live-voice-archive.ts +758 -0
- package/src/live-voice/live-voice-metrics.ts +472 -0
- package/src/live-voice/live-voice-session-manager.ts +222 -0
- package/src/live-voice/live-voice-session.ts +1144 -0
- package/src/live-voice/live-voice-tts.ts +260 -0
- package/src/live-voice/protocol.ts +524 -0
- package/src/mcp/client.ts +2 -2
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
- package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
- package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
- package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
- package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
- package/src/memory/admin.ts +65 -7
- package/src/memory/app-git-service.ts +0 -14
- package/src/memory/attachments-store.ts +14 -16
- package/src/memory/auto-analysis-enqueue.ts +2 -17
- package/src/memory/canonical-guardian-store.ts +2 -1
- package/src/memory/channel-verification-sessions.ts +1 -1
- package/src/memory/checkpoints.ts +1 -1
- package/src/memory/context-search/agent-protocol.ts +424 -0
- package/src/memory/context-search/agent-runner.ts +1295 -0
- package/src/memory/context-search/format.ts +160 -0
- package/src/memory/context-search/limits.ts +106 -0
- package/src/memory/context-search/search.ts +387 -0
- package/src/memory/context-search/sources/conversations.ts +278 -0
- package/src/memory/context-search/sources/memory.ts +90 -0
- package/src/memory/context-search/sources/pkb.ts +468 -0
- package/src/memory/context-search/sources/workspace.ts +1255 -0
- package/src/memory/context-search/types.ts +49 -0
- package/src/memory/conversation-analyze-job.ts +3 -24
- package/src/memory/conversation-attention-store.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +117 -145
- package/src/memory/conversation-directories.ts +1 -11
- package/src/memory/conversation-display-order-migration.ts +11 -2
- package/src/memory/conversation-group-migration.ts +20 -4
- package/src/memory/conversation-key-store.ts +3 -4
- package/src/memory/conversation-queries.ts +69 -29
- package/src/memory/conversation-starter-validation.ts +88 -0
- package/src/memory/conversation-starters-cadence.ts +1 -1
- package/src/memory/conversation-title-service.ts +27 -1
- package/src/memory/db-init.ts +22 -4
- package/src/memory/db-maintenance.ts +1 -1
- package/src/memory/delivery-channels.ts +1 -14
- package/src/memory/delivery-crud.ts +2 -32
- package/src/memory/delivery-status.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +44 -5
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +412 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
- package/src/memory/graph/bootstrap.test.ts +277 -0
- package/src/memory/graph/bootstrap.ts +10 -6
- package/src/memory/graph/capability-seed.ts +3 -3
- package/src/memory/graph/compaction.ts +1 -1
- package/src/memory/graph/consolidation.ts +13 -10
- package/src/memory/graph/conversation-graph-memory.ts +151 -1
- package/src/memory/graph/decay.ts +1 -1
- package/src/memory/graph/extraction.ts +63 -23
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +95 -2
- package/src/memory/graph/graph-search.ts +22 -7
- package/src/memory/graph/image-ref-utils.ts +1 -1
- package/src/memory/graph/retriever.test.ts +158 -4
- package/src/memory/graph/retriever.ts +27 -8
- package/src/memory/graph/store.test.ts +2 -1
- package/src/memory/graph/store.ts +1 -1
- package/src/memory/graph/tool-handlers.ts +73 -247
- package/src/memory/graph/tools.ts +35 -53
- package/src/memory/group-crud.ts +1 -2
- package/src/memory/guardian-action-store.ts +2 -1
- package/src/memory/guardian-approvals.ts +1 -1
- package/src/memory/guardian-rate-limits.ts +1 -1
- package/src/memory/indexer.ts +43 -17
- package/src/memory/invite-store.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +1 -1
- package/src/memory/job-handlers/cleanup.ts +2 -1
- package/src/memory/job-handlers/conversation-starters.ts +18 -10
- package/src/memory/job-handlers/embedding.test.ts +2 -1
- package/src/memory/job-handlers/embedding.ts +1 -1
- package/src/memory/job-handlers/index-maintenance.ts +1 -1
- package/src/memory/job-handlers/summarization.ts +3 -3
- package/src/memory/job-utils.ts +3 -3
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
- package/src/memory/jobs/embed-concept-page.ts +210 -0
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/jobs-worker.ts +58 -5
- package/src/memory/lifecycle-events-store.ts +1 -1
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +1 -1
- package/src/memory/media-store.ts +1 -1
- package/src/memory/memory-recall-log-store.ts +1 -1
- package/src/memory/migrations/038-actor-token-records.ts +3 -0
- package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
- package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
- package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
- package/src/memory/migrations/230-acp-session-history.ts +41 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
- package/src/memory/migrations/232-activation-state.ts +38 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +7 -0
- package/src/memory/pkb/pkb-index.test.ts +5 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +5 -5
- package/src/memory/pkb/pkb-search.test.ts +148 -7
- package/src/memory/pkb/pkb-search.ts +65 -30
- package/src/memory/published-pages-store.ts +1 -1
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/acp.ts +30 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +2 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/scoped-approval-grants.ts +2 -1
- package/src/memory/search/semantic.ts +2 -2
- package/src/memory/shared-app-links-store.ts +2 -1
- package/src/memory/tool-usage-store.ts +1 -1
- package/src/memory/trace-event-store.ts +2 -1
- package/src/memory/turn-events-store.ts +1 -1
- package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
- package/src/memory/v2/__tests__/activation.test.ts +956 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +610 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +395 -0
- package/src/memory/v2/__tests__/edges.test.ts +435 -0
- package/src/memory/v2/__tests__/injection.test.ts +792 -0
- package/src/memory/v2/__tests__/migration.test.ts +812 -0
- package/src/memory/v2/__tests__/page-store.test.ts +334 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
- package/src/memory/v2/__tests__/sim.test.ts +549 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +351 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
- package/src/memory/v2/activation-store.ts +109 -0
- package/src/memory/v2/activation.ts +490 -0
- package/src/memory/v2/backfill-jobs.ts +442 -0
- package/src/memory/v2/consolidation-job.ts +304 -0
- package/src/memory/v2/edges.ts +217 -0
- package/src/memory/v2/injection.ts +307 -0
- package/src/memory/v2/migration.ts +654 -0
- package/src/memory/v2/now-text.ts +38 -0
- package/src/memory/v2/page-store.ts +245 -0
- package/src/memory/v2/prompts/consolidation.ts +185 -0
- package/src/memory/v2/prompts/sweep.ts +56 -0
- package/src/memory/v2/qdrant.ts +342 -0
- package/src/memory/v2/sim.ts +206 -0
- package/src/memory/v2/skill-content.ts +42 -0
- package/src/memory/v2/skill-qdrant.ts +395 -0
- package/src/memory/v2/skill-store.ts +128 -0
- package/src/memory/v2/sweep-job.ts +298 -0
- package/src/memory/v2/types.ts +116 -0
- package/src/memory/validation.ts +1 -1
- package/src/messaging/providers/index.ts +262 -0
- package/src/messaging/providers/slack/api.ts +242 -0
- package/src/messaging/providers/slack/message-metadata.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/messaging/providers/slack/send.ts +383 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
- package/src/messaging/providers/telegram-bot/api.ts +253 -0
- package/src/messaging/providers/telegram-bot/client.ts +17 -58
- package/src/messaging/providers/telegram-bot/send.ts +232 -0
- package/src/messaging/providers/whatsapp/adapter.ts +4 -36
- package/src/messaging/providers/whatsapp/api.ts +319 -0
- package/src/messaging/providers/whatsapp/client.ts +4 -48
- package/src/messaging/providers/whatsapp/send.ts +209 -0
- package/src/notifications/adapters/slack.ts +5 -23
- package/src/notifications/adapters/telegram.ts +8 -29
- package/src/notifications/conversation-candidates.ts +1 -1
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/conversation-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -6
- package/src/notifications/decision-engine.ts +1 -1
- package/src/notifications/decisions-store.ts +1 -1
- package/src/notifications/deliveries-store.ts +2 -1
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +1 -11
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/connection-resolver.ts +11 -2
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +32 -15
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/outbound-proxy/index.ts +0 -1
- package/src/permissions/approval-policy.test.ts +398 -106
- package/src/permissions/approval-policy.ts +134 -108
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +280 -345
- package/src/permissions/gateway-threshold-reader.ts +177 -0
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +8 -9
- package/src/permissions/risk-types.ts +24 -153
- package/src/permissions/types.ts +19 -47
- package/src/permissions/workspace-policy.ts +10 -7
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +488 -0
- package/src/plugins/defaults/llm-call.ts +79 -0
- package/src/plugins/defaults/memory-retrieval.ts +221 -0
- package/src/plugins/defaults/overflow-reduce.ts +185 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +103 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +301 -0
- package/src/plugins/types.ts +1133 -0
- package/src/plugins/user-loader.ts +203 -0
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +197 -0
- package/src/prompts/persona-resolver.ts +2 -4
- package/src/prompts/system-prompt.ts +39 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
- package/src/providers/__tests__/retry-callsite.test.ts +3 -6
- package/src/providers/anthropic/client.ts +71 -19
- package/src/providers/call-site-routing.ts +7 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/gemini/client.ts +96 -22
- package/src/providers/managed-proxy/context.ts +0 -12
- package/src/providers/model-catalog.ts +123 -25
- package/src/providers/model-intents.ts +6 -7
- package/src/providers/openai/chat-completions-provider.ts +37 -7
- package/src/providers/openai/responses-provider.ts +39 -4
- package/src/providers/openrouter/client.ts +9 -6
- package/src/providers/provider-env-vars.ts +4 -12
- package/src/providers/provider-send-message.ts +16 -11
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +52 -23
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
- package/src/providers/speech-to-text/openai-whisper.ts +3 -6
- package/src/providers/speech-to-text/provider-catalog.ts +75 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/providers/speech-to-text/xai.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +22 -10
- package/src/runtime/AGENTS.md +27 -17
- package/src/runtime/__tests__/agent-wake.test.ts +33 -9
- package/src/runtime/__tests__/client-registry.test.ts +271 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
- package/src/runtime/access-request-helper.ts +9 -20
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/agent-wake.ts +174 -68
- package/src/runtime/approval-conversation-turn.ts +2 -15
- package/src/runtime/approval-message-composer.ts +11 -60
- package/src/runtime/assistant-event.ts +18 -66
- package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
- package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
- package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
- package/src/runtime/auth/context.ts +9 -0
- package/src/runtime/auth/middleware.ts +4 -4
- package/src/runtime/auth/route-policy.ts +195 -4
- package/src/runtime/auth/token-service.ts +1 -100
- package/src/runtime/capability-tokens.ts +89 -313
- package/src/runtime/channel-approval-types.ts +1 -6
- package/src/runtime/channel-approvals.ts +7 -79
- package/src/runtime/channel-readiness-service.ts +2 -2
- package/src/runtime/channel-reply-delivery.ts +2 -8
- package/src/runtime/channel-retry-sweep.ts +20 -17
- package/src/runtime/client-registry.ts +254 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
- package/src/runtime/gateway-client.ts +37 -378
- package/src/runtime/guardian-action-grant-minter.ts +2 -3
- package/src/runtime/guardian-action-message-composer.ts +11 -52
- package/src/runtime/guardian-action-service.ts +19 -7
- package/src/runtime/guardian-decision-types.ts +4 -65
- package/src/runtime/guardian-reply-router.ts +10 -19
- package/src/runtime/guardian-vellum-migration.ts +5 -64
- package/src/runtime/http-errors.ts +3 -0
- package/src/runtime/http-router.ts +50 -7
- package/src/runtime/http-server.ts +345 -1041
- package/src/runtime/http-types.ts +15 -100
- package/src/runtime/interactive-ui-types.ts +145 -0
- package/src/runtime/interactive-ui.ts +38 -196
- package/src/runtime/invite-redemption-service.ts +1 -1
- package/src/runtime/invite-redemption-templates.ts +1 -1
- package/src/runtime/local-actor-identity.ts +13 -43
- package/src/runtime/message-composer-types.ts +134 -0
- package/src/runtime/middleware/rate-limiter.ts +1 -1
- package/src/runtime/middleware/request-logger.ts +5 -2
- package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +16 -0
- package/src/runtime/migrations/job-registry.ts +281 -0
- package/src/runtime/migrations/vbundle-builder.ts +4 -26
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -13
- package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
- package/src/runtime/nl-approval-parser.ts +16 -21
- package/src/runtime/pending-interactions.ts +29 -12
- package/src/runtime/routes/__tests__/acp-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +204 -320
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
- package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
- package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
- package/src/runtime/routes/access-request-decision.ts +25 -50
- package/src/runtime/routes/acp-routes.test.ts +371 -0
- package/src/runtime/routes/acp-routes.ts +392 -166
- package/src/runtime/routes/app-management-routes.ts +464 -660
- package/src/runtime/routes/app-routes.ts +192 -177
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +133 -434
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
- package/src/runtime/routes/attachment-routes.ts +409 -253
- package/src/runtime/routes/audio-routes.ts +51 -18
- package/src/runtime/routes/avatar-routes.ts +82 -75
- package/src/runtime/routes/background-tool-routes.ts +94 -0
- package/src/runtime/routes/backup-routes.ts +154 -336
- package/src/runtime/routes/brain-graph-routes.ts +83 -110
- package/src/runtime/routes/browser-routes.ts +141 -0
- package/src/runtime/routes/btw-routes.ts +62 -106
- package/src/runtime/routes/cache-routes.ts +96 -0
- package/src/runtime/routes/call-routes.ts +208 -247
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
- package/src/runtime/routes/channel-delivery-routes.ts +25 -27
- package/src/runtime/routes/channel-readiness-routes.ts +83 -120
- package/src/runtime/routes/channel-route-definitions.ts +62 -0
- package/src/runtime/routes/channel-route-shared.ts +14 -18
- package/src/runtime/routes/channel-verification-routes.ts +207 -187
- package/src/runtime/routes/client-routes.ts +48 -0
- package/src/runtime/routes/contact-routes.ts +533 -407
- package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
- package/src/runtime/routes/conversation-attention-routes.ts +55 -67
- package/src/runtime/routes/conversation-list-routes.ts +265 -0
- package/src/runtime/routes/conversation-management-routes.ts +626 -715
- package/src/runtime/routes/conversation-query-routes.ts +510 -460
- package/src/runtime/routes/conversation-routes.ts +652 -457
- package/src/runtime/routes/conversation-starter-routes.ts +121 -71
- package/src/runtime/routes/credential-prompt-routes.ts +124 -0
- package/src/runtime/routes/debug-routes.ts +34 -39
- package/src/runtime/routes/defer-routes.ts +230 -0
- package/src/runtime/routes/diagnostics-routes.ts +79 -70
- package/src/runtime/routes/documents-routes.ts +117 -106
- package/src/runtime/routes/errors.ts +132 -0
- package/src/runtime/routes/events-routes.ts +97 -58
- package/src/runtime/routes/filing-routes.ts +65 -78
- package/src/runtime/routes/global-search-routes.ts +51 -57
- package/src/runtime/routes/group-routes.ts +199 -181
- package/src/runtime/routes/guardian-action-routes.ts +103 -169
- package/src/runtime/routes/guardian-approval-interception.ts +27 -58
- package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
- package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
- package/src/runtime/routes/heartbeat-routes.ts +194 -209
- package/src/runtime/routes/home-feed-routes.ts +85 -187
- package/src/runtime/routes/home-state-routes.ts +27 -24
- package/src/runtime/routes/host-bash-routes.ts +42 -52
- package/src/runtime/routes/host-browser-routes.ts +38 -69
- package/src/runtime/routes/host-cu-routes.ts +74 -70
- package/src/runtime/routes/host-file-routes.ts +50 -60
- package/src/runtime/routes/host-transfer-routes.ts +220 -0
- package/src/runtime/routes/http-adapter.ts +172 -0
- package/src/runtime/routes/identity-routes.ts +83 -79
- package/src/runtime/routes/inbound-conversation.ts +11 -18
- package/src/runtime/routes/inbound-message-handler.ts +162 -123
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +79 -138
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +54 -90
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +19 -26
- package/src/runtime/routes/index.ts +197 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
- package/src/runtime/routes/integrations/slack/channel.ts +69 -66
- package/src/runtime/routes/integrations/slack/share.ts +49 -58
- package/src/runtime/routes/integrations/telegram.ts +91 -74
- package/src/runtime/routes/integrations/twilio.ts +163 -240
- package/src/runtime/routes/integrations/vercel.ts +57 -54
- package/src/runtime/routes/interface-routes.ts +43 -0
- package/src/runtime/routes/internal-oauth-routes.ts +56 -0
- package/src/runtime/routes/internal-twilio-routes.ts +46 -0
- package/src/runtime/routes/llm-context-normalization.ts +4 -2
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +90 -100
- package/src/runtime/routes/memory-item-routes.test.ts +153 -175
- package/src/runtime/routes/memory-item-routes.ts +243 -323
- package/src/runtime/routes/memory-v2-routes.ts +193 -0
- package/src/runtime/routes/migration-rollback-routes.ts +167 -212
- package/src/runtime/routes/migration-routes.ts +877 -377
- package/src/runtime/routes/notification-routes.ts +199 -70
- package/src/runtime/routes/oauth-apps.ts +254 -251
- package/src/runtime/routes/oauth-providers.ts +66 -57
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +224 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +60 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +250 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +195 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +159 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +207 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +175 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +27 -0
- package/src/runtime/routes/playground/force-compact.ts +60 -0
- package/src/runtime/routes/playground/guard.ts +36 -0
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +18 -0
- package/src/runtime/routes/playground/inject-failures.ts +143 -0
- package/src/runtime/routes/playground/reset-circuit.ts +89 -0
- package/src/runtime/routes/playground/seed-conversation.ts +113 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +74 -0
- package/src/runtime/routes/playground/state.ts +77 -0
- package/src/runtime/routes/profiler-routes.ts +132 -167
- package/src/runtime/routes/ps-routes.ts +120 -0
- package/src/runtime/routes/recording-routes.ts +197 -258
- package/src/runtime/routes/rename-conversation-routes.ts +89 -0
- package/src/runtime/routes/schedule-routes.ts +284 -207
- package/src/runtime/routes/secret-routes.ts +219 -265
- package/src/runtime/routes/secrets-deps.ts +24 -0
- package/src/runtime/routes/settings-routes.ts +361 -441
- package/src/runtime/routes/skills-routes.ts +434 -469
- package/src/runtime/routes/stt-routes.ts +196 -206
- package/src/runtime/routes/subagents-routes.ts +125 -141
- package/src/runtime/routes/suggest-trust-rule-routes.ts +244 -0
- package/src/runtime/routes/surface-action-routes.ts +135 -190
- package/src/runtime/routes/surface-content-routes.ts +84 -118
- package/src/runtime/routes/task-routes.ts +354 -0
- package/src/runtime/routes/telemetry-routes.ts +33 -49
- package/src/runtime/routes/trace-event-routes.ts +55 -74
- package/src/runtime/routes/trust-rules-routes.ts +147 -239
- package/src/runtime/routes/tts-routes.ts +187 -169
- package/src/runtime/routes/types.ts +139 -0
- package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
- package/src/runtime/routes/upgrade-broadcast-routes.ts +156 -197
- package/src/runtime/routes/usage-routes.ts +143 -169
- package/src/runtime/routes/user-routes.ts +102 -18
- package/src/runtime/routes/wake-conversation-routes.ts +49 -0
- package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
- package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
- package/src/runtime/routes/work-items-routes.test.ts +10 -20
- package/src/runtime/routes/work-items-routes.ts +418 -433
- package/src/runtime/routes/workspace-commit-routes.ts +30 -61
- package/src/runtime/routes/workspace-routes.test.ts +254 -381
- package/src/runtime/routes/workspace-routes.ts +238 -246
- package/src/runtime/runtime-mode.ts +8 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +80 -118
- package/src/runtime/services/analyze-conversation.ts +14 -41
- package/src/runtime/services/conversation-serializer.ts +181 -0
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/runtime/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +13 -49
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +70 -2
- package/src/schedule/scheduler.ts +149 -8
- package/src/security/ces-credential-client.ts +32 -169
- package/src/security/ces-rpc-credential-backend.ts +1 -1
- package/src/security/credential-backend.ts +6 -6
- package/src/security/oauth-completion-page.ts +1 -1
- package/src/security/oauth2.ts +3 -6
- package/src/sequence/analytics.ts +1 -1
- package/src/sequence/guardrails.ts +3 -3
- package/src/sequence/store.ts +2 -1
- package/src/signals/bash.ts +1 -1
- package/src/signals/event-stream.ts +1 -1
- package/src/skills/catalog-cache.ts +19 -5
- package/src/skills/catalog-files.ts +0 -5
- package/src/skills/catalog-install.ts +28 -18
- package/src/skills/category-inference.ts +0 -11
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/remote-skill-policy.ts +6 -7
- package/src/subagent/index.ts +2 -6
- package/src/subagent/manager.ts +27 -23
- package/src/subagent/types.ts +9 -0
- package/src/tasks/SPEC.md +2 -2
- package/src/tasks/task-compiler.ts +1 -1
- package/src/tasks/task-runner.ts +2 -22
- package/src/tasks/task-store.ts +1 -1
- package/src/tools/acp/list-agents.test.ts +115 -0
- package/src/tools/acp/list-agents.ts +31 -0
- package/src/tools/acp/spawn.test.ts +379 -0
- package/src/tools/acp/spawn.ts +142 -62
- package/src/tools/acp/steer.test.ts +101 -0
- package/src/tools/acp/steer.ts +38 -0
- package/src/tools/background-tool-registry.ts +98 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +122 -26
- package/src/tools/browser/browser-manager.ts +1 -8
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/browser/cdp-client/types.ts +4 -1
- package/src/tools/computer-use/definitions.ts +1 -1
- package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
- package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
- package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
- package/src/tools/credentials/broker-types.ts +2 -1
- package/src/tools/document/editor-template.ts +1 -1
- package/src/tools/execution-timeout.ts +1 -1
- package/src/tools/executor.ts +123 -76
- package/src/tools/host-filesystem/transfer.test.ts +268 -0
- package/src/tools/host-filesystem/transfer.ts +234 -0
- package/src/tools/host-terminal/host-shell.ts +189 -11
- package/src/tools/mcp/mcp-tool-factory.ts +1 -1
- package/src/tools/memory/register.test.ts +161 -1
- package/src/tools/memory/register.ts +19 -34
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +103 -255
- package/src/tools/policy-context.ts +5 -8
- package/src/tools/registry.ts +156 -4
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +13 -154
- package/src/tools/shared/shell-output.ts +4 -1
- package/src/tools/side-effects.ts +2 -2
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/subagent/spawn.ts +35 -11
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/safe-env.ts +9 -1
- package/src/tools/terminal/shell.ts +161 -31
- package/src/tools/tool-approval-handler.ts +4 -70
- package/src/tools/tool-input-summary.ts +10 -0
- package/src/tools/types.ts +157 -151
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/debounce.ts +0 -21
- package/src/util/errors.ts +0 -8
- package/src/util/log-redact.ts +0 -1
- package/src/util/platform.ts +85 -119
- package/src/util/pricing.ts +135 -9
- package/src/watcher/engine.ts +42 -20
- package/src/watcher/watcher-store.ts +2 -1
- package/src/work-items/work-item-store.ts +1 -1
- package/src/workspace/git-service.ts +1 -6
- package/src/workspace/migrations/006-services-config.ts +11 -4
- package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
- package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
- package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
- package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
- package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
- package/src/workspace/migrations/060-memory-v2-init.ts +53 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
- package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
- package/src/__tests__/ephemeral-permissions.test.ts +0 -474
- package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/pairing-concurrent.test.ts +0 -84
- package/src/__tests__/pairing-routes.test.ts +0 -181
- package/src/__tests__/parser.test.ts +0 -595
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -512
- package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
- package/src/__tests__/permission-mode.test.ts +0 -89
- package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
- package/src/__tests__/risk-classifier-parity.test.ts +0 -230
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/shell-identity.test.ts +0 -370
- package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
- package/src/__tests__/shell-parser-property.test.ts +0 -936
- package/src/__tests__/starter-bundle.test.ts +0 -173
- package/src/__tests__/stt-catalog-parity.test.ts +0 -282
- package/src/__tests__/task-runner.test.ts +0 -224
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -357
- package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
- package/src/__tests__/trust-store.test.ts +0 -2013
- package/src/__tests__/v2-consent-policy.test.ts +0 -103
- package/src/browser/identifiers.ts +0 -51
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/cli/db.ts +0 -1
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/external-skills-bootstrap.ts +0 -41
- package/src/daemon/message-types/trust.ts +0 -71
- package/src/daemon/pairing-store.ts +0 -229
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -61
- package/src/ipc/routes/browser.ts +0 -96
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/index.ts +0 -21
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/oauth/scope-policy.ts +0 -89
- package/src/permissions/bash-risk-classifier.test.ts +0 -1208
- package/src/permissions/bash-risk-classifier.ts +0 -707
- package/src/permissions/command-registry.test.ts +0 -535
- package/src/permissions/command-registry.ts +0 -825
- package/src/permissions/defaults.ts +0 -313
- package/src/permissions/file-risk-classifier.test.ts +0 -535
- package/src/permissions/file-risk-classifier.ts +0 -274
- package/src/permissions/permission-mode.ts +0 -24
- package/src/permissions/shell-identity.ts +0 -337
- package/src/permissions/skill-risk-classifier.test.ts +0 -311
- package/src/permissions/skill-risk-classifier.ts +0 -214
- package/src/permissions/trust-client.ts +0 -359
- package/src/permissions/trust-store-interface.ts +0 -100
- package/src/permissions/trust-store.ts +0 -1330
- package/src/permissions/v2-consent-policy.ts +0 -87
- package/src/permissions/web-risk-classifier.test.ts +0 -170
- package/src/permissions/web-risk-classifier.ts +0 -89
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
- package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
- package/src/runtime/actor-refresh-token-store.ts +0 -156
- package/src/runtime/actor-token-store.ts +0 -207
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
- package/src/runtime/auth/credential-service.ts +0 -352
- package/src/runtime/conversation-approval-overrides.ts +0 -86
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/browser-extension-pair-routes.ts +0 -556
- package/src/runtime/routes/channel-routes.ts +0 -112
- package/src/runtime/routes/contact-routes.test.ts +0 -298
- package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
- package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
- package/src/runtime/routes/invite-routes.ts +0 -280
- package/src/runtime/routes/pairing-routes.ts +0 -431
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/signals/shotgun.ts +0 -203
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/terminal/parser.ts +0 -623
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/types/qrcode.d.ts +0 -13
- package/src/util/network-info.ts +0 -55
- /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
|
@@ -37,8 +37,9 @@ import {
|
|
|
37
37
|
} from "../context/token-estimator.js";
|
|
38
38
|
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
39
39
|
import type { ToolProfiler } from "../events/tool-profiling-listener.js";
|
|
40
|
+
import { emitFeedEvent } from "../home/emit-feed-event.js";
|
|
40
41
|
import { writeRelationshipState } from "../home/relationship-state-writer.js";
|
|
41
|
-
import {
|
|
42
|
+
import { rewriteFeedTitle } from "../home/rewrite-feed-title.js";
|
|
42
43
|
import {
|
|
43
44
|
clearSentryConversationContext,
|
|
44
45
|
setSentryConversationContext,
|
|
@@ -47,32 +48,63 @@ import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
|
47
48
|
import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
48
49
|
import { enqueueAutoAnalysisOnCompaction } from "../memory/auto-analysis-enqueue.js";
|
|
49
50
|
import {
|
|
50
|
-
|
|
51
|
-
clearPkbSystemReminderMetadataForConversation,
|
|
52
|
-
deleteMessageById,
|
|
51
|
+
clearStrippedInjectionMetadataForConversation,
|
|
53
52
|
getConversation,
|
|
54
53
|
getConversationOriginChannel,
|
|
55
54
|
getConversationOriginInterface,
|
|
55
|
+
getConversationOverrideProfileFromRow,
|
|
56
56
|
getLastUserTimestampBefore,
|
|
57
57
|
getMessageById,
|
|
58
58
|
provenanceFromTrustContext,
|
|
59
59
|
updateConversationContextWindow,
|
|
60
|
-
updateConversationTitle,
|
|
61
|
-
updateMessageMetadata,
|
|
62
60
|
} from "../memory/conversation-crud.js";
|
|
63
61
|
import { getResolvedConversationDirPath } from "../memory/conversation-directories.js";
|
|
64
62
|
import { syncMessageToDisk } from "../memory/conversation-disk-view.js";
|
|
65
63
|
import {
|
|
66
64
|
isReplaceableTitle,
|
|
67
|
-
queueGenerateConversationTitle,
|
|
68
65
|
queueRegenerateConversationTitle,
|
|
69
|
-
UNTITLED_FALLBACK,
|
|
70
66
|
} from "../memory/conversation-title-service.js";
|
|
71
67
|
import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
72
68
|
import { recordMemoryRecallLog } from "../memory/memory-recall-log-store.js";
|
|
73
69
|
import { PKB_WORKSPACE_SCOPE } from "../memory/pkb/types.js";
|
|
70
|
+
import type { QdrantSparseVector } from "../memory/qdrant-client.js";
|
|
74
71
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
75
|
-
import
|
|
72
|
+
import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
|
|
73
|
+
import { defaultHistoryRepairTerminal } from "../plugins/defaults/history-repair.js";
|
|
74
|
+
import {
|
|
75
|
+
asDefaultGraphPayload,
|
|
76
|
+
type DefaultMemoryRetrievalDeps,
|
|
77
|
+
type GraphMemoryPayload,
|
|
78
|
+
runDefaultMemoryRetrieval,
|
|
79
|
+
} from "../plugins/defaults/memory-retrieval.js";
|
|
80
|
+
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
81
|
+
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate.js";
|
|
82
|
+
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate.js";
|
|
83
|
+
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
84
|
+
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
85
|
+
import type {
|
|
86
|
+
CircuitBreakerArgs,
|
|
87
|
+
CircuitBreakerResult,
|
|
88
|
+
CompactionArgs,
|
|
89
|
+
CompactionResult,
|
|
90
|
+
EstimateArgs,
|
|
91
|
+
EstimateResult,
|
|
92
|
+
HistoryRepairArgs,
|
|
93
|
+
HistoryRepairResult,
|
|
94
|
+
MemoryArgs,
|
|
95
|
+
MemoryResult,
|
|
96
|
+
OverflowReduceArgs,
|
|
97
|
+
OverflowReduceResult,
|
|
98
|
+
PersistArgs,
|
|
99
|
+
PersistResult,
|
|
100
|
+
TurnContext as PluginTurnContext,
|
|
101
|
+
} from "../plugins/types.js";
|
|
102
|
+
import { PluginExecutionError, PluginTimeoutError } from "../plugins/types.js";
|
|
103
|
+
import type {
|
|
104
|
+
ContentBlock,
|
|
105
|
+
Message,
|
|
106
|
+
ToolDefinition,
|
|
107
|
+
} from "../providers/types.js";
|
|
76
108
|
import type { Provider } from "../providers/types.js";
|
|
77
109
|
import { resolveActorTrust } from "../runtime/actor-trust-resolver.js";
|
|
78
110
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
@@ -88,7 +120,6 @@ import {
|
|
|
88
120
|
type AssistantAttachmentDraft,
|
|
89
121
|
cleanAssistantContent,
|
|
90
122
|
} from "./assistant-attachments.js";
|
|
91
|
-
import { requestCompressionApproval } from "./context-overflow-approval.js";
|
|
92
123
|
import { resolveOverflowAction } from "./context-overflow-policy.js";
|
|
93
124
|
import {
|
|
94
125
|
createInitialReducerState,
|
|
@@ -117,7 +148,6 @@ import type {
|
|
|
117
148
|
ChannelCapabilities,
|
|
118
149
|
InboundActorContext,
|
|
119
150
|
InjectionMode,
|
|
120
|
-
TrustContext,
|
|
121
151
|
} from "./conversation-runtime-assembly.js";
|
|
122
152
|
import {
|
|
123
153
|
applyRuntimeInjections,
|
|
@@ -129,8 +159,6 @@ import {
|
|
|
129
159
|
inboundActorContextFromTrustContext,
|
|
130
160
|
loadSlackActiveThreadFocusBlock,
|
|
131
161
|
loadSlackChronologicalMessages,
|
|
132
|
-
readNowScratchpad,
|
|
133
|
-
readPkbContext,
|
|
134
162
|
stripInjectionsForCompaction,
|
|
135
163
|
} from "./conversation-runtime-assembly.js";
|
|
136
164
|
import type { SkillProjectionCache } from "./conversation-skill-tools.js";
|
|
@@ -138,7 +166,7 @@ import { markSurfaceCompleted } from "./conversation-surfaces.js";
|
|
|
138
166
|
import { resolveTrustClass } from "./conversation-tool-setup.js";
|
|
139
167
|
import { recordUsage } from "./conversation-usage.js";
|
|
140
168
|
import { formatTurnTimestamp } from "./date-context.js";
|
|
141
|
-
import { deepRepairHistory
|
|
169
|
+
import { deepRepairHistory } from "./history-repair.js";
|
|
142
170
|
import type {
|
|
143
171
|
DynamicPageSurfaceData,
|
|
144
172
|
ServerMessage,
|
|
@@ -147,8 +175,10 @@ import type {
|
|
|
147
175
|
UsageStats,
|
|
148
176
|
} from "./message-protocol.js";
|
|
149
177
|
import type { MemoryRecalled } from "./message-types/memory.js";
|
|
178
|
+
import type { ConfirmationStateChanged } from "./message-types/messages.js";
|
|
150
179
|
import { parseActualTokensFromError } from "./parse-actual-tokens-from-error.js";
|
|
151
180
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
181
|
+
import type { TrustContext } from "./trust-context.js";
|
|
152
182
|
import { stripHistoricalWebSearchResults } from "./web-search-history.js";
|
|
153
183
|
|
|
154
184
|
const log = getLogger("conversation-agent-loop");
|
|
@@ -171,77 +201,210 @@ type GitServiceInitializer = {
|
|
|
171
201
|
ensureInitialized(): Promise<void>;
|
|
172
202
|
};
|
|
173
203
|
|
|
174
|
-
// ── Compaction circuit-breaker
|
|
204
|
+
// ── Compaction circuit-breaker pipeline helpers ─────────────────────
|
|
205
|
+
//
|
|
206
|
+
// The circuit-breaker behavior (3 consecutive summary-LLM failures trips a
|
|
207
|
+
// 1-hour cooldown) is now implemented by the `circuitBreaker` plugin
|
|
208
|
+
// pipeline. The default plugin (`plugins/defaults/circuit-breaker.ts`)
|
|
209
|
+
// replicates the legacy threshold/cooldown constants and event-emission
|
|
210
|
+
// semantics exactly — it operates on the `consecutiveCompactionFailures` /
|
|
211
|
+
// `compactionCircuitOpenUntil` fields the conversation still owns so the
|
|
212
|
+
// dev-only playground routes (`POST /playground/reset-compaction-circuit`,
|
|
213
|
+
// `POST /playground/inject-compaction-failures`) continue to read and
|
|
214
|
+
// mutate those fields directly.
|
|
175
215
|
//
|
|
176
|
-
// The
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
216
|
+
// The helpers below build the pipeline inputs and invoke the runner. They
|
|
217
|
+
// are the sole entry points the rest of the daemon uses to query or update
|
|
218
|
+
// the compaction circuit.
|
|
219
|
+
|
|
220
|
+
/** Circuit-breaker key for a specific conversation's compaction pipeline. */
|
|
221
|
+
function compactionCircuitKey(conversationId: string): string {
|
|
222
|
+
return `compaction:${conversationId}`;
|
|
223
|
+
}
|
|
182
224
|
|
|
183
225
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
226
|
+
* Build the minimal {@link TurnContext} the pipeline runner requires. Called
|
|
227
|
+
* both from inside the agent loop (where turn identifiers are available) and
|
|
228
|
+
* from non-turn invocations like `Conversation.forceCompact` (which falls
|
|
229
|
+
* back to stable placeholders so the runner's log records still carry the
|
|
230
|
+
* conversation identifier).
|
|
187
231
|
*/
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
function buildCircuitTurnContext(ctx: {
|
|
233
|
+
readonly conversationId: string;
|
|
234
|
+
currentRequestId?: string;
|
|
235
|
+
currentTurnTrustContext?: TrustContext;
|
|
236
|
+
trustContext?: TrustContext;
|
|
237
|
+
turnCount: number;
|
|
238
|
+
}): PluginTurnContext {
|
|
239
|
+
const trust: TrustContext =
|
|
240
|
+
ctx.currentTurnTrustContext ?? ctx.trustContext ?? FALLBACK_TURN_TRUST;
|
|
241
|
+
return {
|
|
242
|
+
requestId: ctx.currentRequestId ?? "circuit-breaker",
|
|
243
|
+
conversationId: ctx.conversationId,
|
|
244
|
+
turnIndex: ctx.turnCount,
|
|
245
|
+
trust,
|
|
246
|
+
};
|
|
195
247
|
}
|
|
196
248
|
|
|
197
249
|
/**
|
|
198
|
-
*
|
|
250
|
+
* Run the `circuitBreaker` pipeline for the compaction circuit on this
|
|
251
|
+
* conversation. When `outcome` is provided, state is updated (and transition
|
|
252
|
+
* events emit via `onEvent`); when omitted the call is query-only.
|
|
199
253
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
254
|
+
* Returns the post-call decision from the pipeline. Callers gate auto-paths
|
|
255
|
+
* on `!result.open` and admit forced paths regardless of the decision.
|
|
256
|
+
*/
|
|
257
|
+
async function runCompactionCircuitPipeline(
|
|
258
|
+
ctx: {
|
|
259
|
+
readonly conversationId: string;
|
|
260
|
+
consecutiveCompactionFailures: number;
|
|
261
|
+
compactionCircuitOpenUntil: number | null;
|
|
262
|
+
currentRequestId?: string;
|
|
263
|
+
currentTurnTrustContext?: TrustContext;
|
|
264
|
+
trustContext?: TrustContext;
|
|
265
|
+
turnCount: number;
|
|
266
|
+
},
|
|
267
|
+
args: {
|
|
268
|
+
outcome?: "success" | "failure";
|
|
269
|
+
onEvent?: (msg: ServerMessage) => void;
|
|
270
|
+
},
|
|
271
|
+
): Promise<CircuitBreakerResult> {
|
|
272
|
+
const turnContext = buildCircuitTurnContext(ctx);
|
|
273
|
+
return runPipeline<CircuitBreakerArgs, CircuitBreakerResult>(
|
|
274
|
+
"circuitBreaker",
|
|
275
|
+
getMiddlewaresFor("circuitBreaker"),
|
|
276
|
+
async (terminalArgs) => {
|
|
277
|
+
// No plugin in the chain produced a decision. This should be
|
|
278
|
+
// unreachable in production because the default plugin registers a
|
|
279
|
+
// `circuitBreaker` middleware that always returns a decision, but we
|
|
280
|
+
// defensively derive the state here so test setups that intentionally
|
|
281
|
+
// omit the default plugin still get a sensible response.
|
|
282
|
+
const openUntil = terminalArgs.state.compactionCircuitOpenUntil;
|
|
283
|
+
const now = Date.now();
|
|
284
|
+
if (openUntil !== null && now < openUntil) {
|
|
285
|
+
return { open: true, cooldownRemainingMs: openUntil - now };
|
|
286
|
+
}
|
|
287
|
+
return { open: false };
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
key: compactionCircuitKey(ctx.conversationId),
|
|
291
|
+
// Pass the ctx directly as the mutable state container. The
|
|
292
|
+
// `CircuitBreakerArgs.state` shape deliberately matches the subset of
|
|
293
|
+
// fields the conversation owns so plugins mutate the same object the
|
|
294
|
+
// playground routes read and write.
|
|
295
|
+
state: ctx,
|
|
296
|
+
...(args.outcome !== undefined ? { outcome: args.outcome } : {}),
|
|
297
|
+
...(args.onEvent ? { onEvent: args.onEvent } : {}),
|
|
298
|
+
},
|
|
299
|
+
turnContext,
|
|
300
|
+
DEFAULT_TIMEOUTS.circuitBreaker,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Query-only: is the compaction circuit breaker currently open for this
|
|
306
|
+
* conversation? Thin wrapper around {@link runCompactionCircuitPipeline}
|
|
307
|
+
* with no outcome. Async because the pipeline runner is async, but the
|
|
308
|
+
* default plugin resolves synchronously on its microtask.
|
|
309
|
+
*/
|
|
310
|
+
async function isCompactionCircuitOpen(ctx: {
|
|
311
|
+
readonly conversationId: string;
|
|
312
|
+
consecutiveCompactionFailures: number;
|
|
313
|
+
compactionCircuitOpenUntil: number | null;
|
|
314
|
+
currentRequestId?: string;
|
|
315
|
+
currentTurnTrustContext?: TrustContext;
|
|
316
|
+
trustContext?: TrustContext;
|
|
317
|
+
turnCount: number;
|
|
318
|
+
}): Promise<boolean> {
|
|
319
|
+
const decision = await runCompactionCircuitPipeline(ctx, {});
|
|
320
|
+
return decision.open;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Update the compaction circuit breaker with the outcome of a `maybeCompact`
|
|
325
|
+
* call and emit any transition event. A `summaryFailed` value of `undefined`
|
|
326
|
+
* means the summary LLM never ran (early return) — callers must guard with
|
|
327
|
+
* `summaryFailed !== undefined` before invoking this helper so early-return
|
|
328
|
+
* paths don't silently reset the 3-strike counter.
|
|
205
329
|
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* whether the caller bypassed the breaker.
|
|
330
|
+
* The default plugin handles threshold-based tripping and cooldown reset;
|
|
331
|
+
* see `plugins/defaults/circuit-breaker.ts` for the canonical semantics.
|
|
209
332
|
*/
|
|
210
|
-
export function trackCompactionOutcome(
|
|
333
|
+
export async function trackCompactionOutcome(
|
|
211
334
|
ctx: {
|
|
335
|
+
readonly conversationId: string;
|
|
212
336
|
consecutiveCompactionFailures: number;
|
|
213
337
|
compactionCircuitOpenUntil: number | null;
|
|
338
|
+
currentRequestId?: string;
|
|
339
|
+
currentTurnTrustContext?: TrustContext;
|
|
340
|
+
trustContext?: TrustContext;
|
|
341
|
+
turnCount: number;
|
|
214
342
|
},
|
|
215
|
-
summaryFailed: boolean
|
|
343
|
+
summaryFailed: boolean,
|
|
216
344
|
onEvent: (msg: ServerMessage) => void,
|
|
217
|
-
): void {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
345
|
+
): Promise<void> {
|
|
346
|
+
await runCompactionCircuitPipeline(ctx, {
|
|
347
|
+
outcome: summaryFailed ? "failure" : "success",
|
|
348
|
+
onEvent,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ── Plugin pipeline helpers ──────────────────────────────────────────
|
|
353
|
+
//
|
|
354
|
+
// Canonical {@link PluginTurnContext} builder threaded into every
|
|
355
|
+
// `runPipeline` call inside `runAgentLoopImpl`. The orchestrator composes
|
|
356
|
+
// the context on demand at each call site from ambient state rather than
|
|
357
|
+
// carrying a persistent `TurnContext` instance across the turn.
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Synthetic fallback trust context used when the orchestrator fires a pipeline
|
|
361
|
+
* before the per-turn trust snapshot has been captured (e.g. invocations that
|
|
362
|
+
* bypass `processMessage` / `drainQueue`). We bias to `unknown` rather than
|
|
363
|
+
* `guardian` so a missing snapshot cannot accidentally grant elevated trust
|
|
364
|
+
* to a custom plugin reading `ctx.trust`.
|
|
365
|
+
*/
|
|
366
|
+
const FALLBACK_TURN_TRUST: TrustContext = {
|
|
367
|
+
sourceChannel: "vellum",
|
|
368
|
+
trustClass: "unknown",
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Build the {@link TurnContext} passed to {@link runPipeline}.
|
|
373
|
+
*
|
|
374
|
+
* Canonical source of truth for every pipeline call site inside the agent
|
|
375
|
+
* loop. Every `runPipeline` invocation in `runAgentLoopImpl` (and in the
|
|
376
|
+
* handlers that share its ambient state) must route through this helper
|
|
377
|
+
* rather than constructing a `TurnContext` literal inline — this keeps
|
|
378
|
+
* `turnIndex`, trust resolution, and the `contextWindowManager` attachment
|
|
379
|
+
* consistent across pipeline slots, which in turn keeps structured logs
|
|
380
|
+
* filtered by `conversationId`/`turnIndex` coherent across slots.
|
|
381
|
+
*
|
|
382
|
+
* Behavior:
|
|
383
|
+
* - `turnIndex` is always `ctx.turnCount` — the orchestrator-owned
|
|
384
|
+
* 0-based turn counter. Reading from a single source avoids the
|
|
385
|
+
* earlier inconsistency (`ctx.turnCount`, `ctx.messages.length - 1`,
|
|
386
|
+
* `ctx.messages.length`, and `0` were all used for the same turn).
|
|
387
|
+
* - Trust pulls from the per-turn snapshot first, then the conversation-
|
|
388
|
+
* level context, then {@link FALLBACK_TURN_TRUST}. The cascade matches
|
|
389
|
+
* the one inside the orchestrator's inline injection assembly so
|
|
390
|
+
* middleware reads the same trust class the runtime sees.
|
|
391
|
+
* - `contextWindowManager` is attached unconditionally. Pipelines that
|
|
392
|
+
* don't need it can ignore it; the default compaction plugin reads it
|
|
393
|
+
* via the typed optional field on `TurnContext`.
|
|
394
|
+
*/
|
|
395
|
+
function buildPluginTurnContext(
|
|
396
|
+
ctx: AgentLoopConversationContext,
|
|
397
|
+
requestId: string,
|
|
398
|
+
): PluginTurnContext {
|
|
399
|
+
const trust =
|
|
400
|
+
ctx.currentTurnTrustContext ?? ctx.trustContext ?? FALLBACK_TURN_TRUST;
|
|
401
|
+
return {
|
|
402
|
+
requestId,
|
|
403
|
+
conversationId: ctx.conversationId,
|
|
404
|
+
turnIndex: ctx.turnCount,
|
|
405
|
+
trust,
|
|
406
|
+
contextWindowManager: ctx.contextWindowManager,
|
|
407
|
+
};
|
|
245
408
|
}
|
|
246
409
|
|
|
247
410
|
// ── Context Interface ────────────────────────────────────────────────
|
|
@@ -305,6 +468,15 @@ export interface AgentLoopConversationContext {
|
|
|
305
468
|
currentTurnTrustContext?: TrustContext;
|
|
306
469
|
/** Per-turn snapshot of channelCapabilities, frozen at message-processing start. */
|
|
307
470
|
currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
471
|
+
/**
|
|
472
|
+
* Per-turn snapshot of the resolved inference-profile override. Read by
|
|
473
|
+
* `createToolExecutor` so `ToolContext.overrideProfile` carries the same
|
|
474
|
+
* profile the agent loop is sending to the provider. Without this, a tool
|
|
475
|
+
* that spawns nested subagents (e.g. `subagent_spawn`) cannot recover the
|
|
476
|
+
* override from a row read because the in-flight subagent's own row never
|
|
477
|
+
* had `inferenceProfile` set.
|
|
478
|
+
*/
|
|
479
|
+
currentTurnOverrideProfile?: string;
|
|
308
480
|
commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
309
481
|
trustContext?: TrustContext;
|
|
310
482
|
/** Task-run scope for the current turn. Cleared at turn end so queued/drained turns don't inherit it. */
|
|
@@ -361,13 +533,10 @@ export interface AgentLoopConversationContext {
|
|
|
361
533
|
statusText?: string,
|
|
362
534
|
): void;
|
|
363
535
|
emitConfirmationStateChanged(
|
|
364
|
-
params:
|
|
536
|
+
params: ConfirmationStateChanged extends {
|
|
365
537
|
type: infer _;
|
|
366
538
|
}
|
|
367
|
-
? Omit<
|
|
368
|
-
import("./message-types/messages.js").ConfirmationStateChanged,
|
|
369
|
-
"type"
|
|
370
|
-
>
|
|
539
|
+
? Omit<ConfirmationStateChanged, "type">
|
|
371
540
|
: never,
|
|
372
541
|
): void;
|
|
373
542
|
|
|
@@ -404,7 +573,6 @@ export async function runAgentLoopImpl(
|
|
|
404
573
|
userMessageId: string,
|
|
405
574
|
onEvent: (msg: ServerMessage) => void,
|
|
406
575
|
options?: {
|
|
407
|
-
skipPreMessageRollback?: boolean;
|
|
408
576
|
isInteractive?: boolean;
|
|
409
577
|
isUserMessage?: boolean;
|
|
410
578
|
titleText?: string;
|
|
@@ -415,6 +583,16 @@ export async function runAgentLoopImpl(
|
|
|
415
583
|
* the agent loop defaults to `'mainAgent'` for user-initiated turns.
|
|
416
584
|
*/
|
|
417
585
|
callSite?: LLMCallSite;
|
|
586
|
+
/**
|
|
587
|
+
* Optional ad-hoc inference-profile override applied to every LLM call
|
|
588
|
+
* the loop issues. When set, the agent loop sets
|
|
589
|
+
* `SendMessageOptions.config.overrideProfile` on each provider call so
|
|
590
|
+
* the resolver layers `llm.profiles[<name>]` between the workspace's
|
|
591
|
+
* `activeProfile` and the call-site's named profile. Used by
|
|
592
|
+
* per-conversation pinned profiles (and inherited by subagents the loop
|
|
593
|
+
* spawns).
|
|
594
|
+
*/
|
|
595
|
+
overrideProfile?: string;
|
|
418
596
|
},
|
|
419
597
|
): Promise<void> {
|
|
420
598
|
if (!ctx.abortController) {
|
|
@@ -445,6 +623,28 @@ export async function runAgentLoopImpl(
|
|
|
445
623
|
// `llm.callSites.mainAgent` (falling back to `llm.default` when absent).
|
|
446
624
|
const turnCallSite: LLMCallSite = options?.callSite ?? "mainAgent";
|
|
447
625
|
|
|
626
|
+
// Read the conversation row once for both the override-profile derivation
|
|
627
|
+
// below and the title-replaceability check at turn start. Later reads in
|
|
628
|
+
// this function (post-turn truncation, disk sync, home-feed emission)
|
|
629
|
+
// intentionally re-read because state can change during the turn.
|
|
630
|
+
const turnStartConversation = getConversation(ctx.conversationId);
|
|
631
|
+
|
|
632
|
+
// Optional per-turn inference-profile override. Plumbed through to every
|
|
633
|
+
// LLM call the loop emits and inherited by any subagents spawned during
|
|
634
|
+
// this turn. Caller-supplied `options.overrideProfile` (e.g.
|
|
635
|
+
// SubagentManager forwarding the parent's pinned profile into the
|
|
636
|
+
// spawned subagent's background conversation) wins over the row read
|
|
637
|
+
// so the agent loop's own background-skip rule doesn't zero out an
|
|
638
|
+
// explicitly inherited override.
|
|
639
|
+
const turnOverrideProfile =
|
|
640
|
+
options?.overrideProfile ??
|
|
641
|
+
getConversationOverrideProfileFromRow(turnStartConversation);
|
|
642
|
+
|
|
643
|
+
// Snapshot for `createToolExecutor` to read into `ToolContext.overrideProfile`
|
|
644
|
+
// — see field doc on `AgentLoopConversationContext` for why the tool needs
|
|
645
|
+
// it (nested subagent spawns can't recover the override from a row read).
|
|
646
|
+
ctx.currentTurnOverrideProfile = turnOverrideProfile;
|
|
647
|
+
|
|
448
648
|
// Capture the turn channel context *before* any awaits so a second
|
|
449
649
|
// message from a different channel can't overwrite it mid-flight.
|
|
450
650
|
// When context is unavailable (e.g. regenerate after daemon restart),
|
|
@@ -475,8 +675,8 @@ export async function runAgentLoopImpl(
|
|
|
475
675
|
assistantMessageInterface: origin,
|
|
476
676
|
};
|
|
477
677
|
return {
|
|
478
|
-
userMessageInterface: "
|
|
479
|
-
assistantMessageInterface: "
|
|
678
|
+
userMessageInterface: "web" as InterfaceId,
|
|
679
|
+
assistantMessageInterface: "web" as InterfaceId,
|
|
480
680
|
};
|
|
481
681
|
})();
|
|
482
682
|
|
|
@@ -528,59 +728,47 @@ export async function runAgentLoopImpl(
|
|
|
528
728
|
}
|
|
529
729
|
}
|
|
530
730
|
|
|
531
|
-
const preMessageResult = await getHookManager().trigger("pre-message", {
|
|
532
|
-
conversationId: ctx.conversationId,
|
|
533
|
-
messagePreview: truncate(content, 200, ""),
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
if (preMessageResult.blocked) {
|
|
537
|
-
if (!options?.skipPreMessageRollback) {
|
|
538
|
-
ctx.messages.pop();
|
|
539
|
-
deleteMessageById(userMessageId);
|
|
540
|
-
}
|
|
541
|
-
// Replace loading placeholder so the conversation isn't stuck as "Generating title..."
|
|
542
|
-
const currentConv = getConversation(ctx.conversationId);
|
|
543
|
-
if (
|
|
544
|
-
isReplaceableTitle(currentConv?.title ?? null) &&
|
|
545
|
-
currentConv?.title !== UNTITLED_FALLBACK
|
|
546
|
-
) {
|
|
547
|
-
updateConversationTitle(ctx.conversationId, UNTITLED_FALLBACK);
|
|
548
|
-
onEvent({
|
|
549
|
-
type: "conversation_title_updated",
|
|
550
|
-
conversationId: ctx.conversationId,
|
|
551
|
-
title: UNTITLED_FALLBACK,
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
onEvent({
|
|
555
|
-
type: "error",
|
|
556
|
-
message: `Message blocked by hook "${preMessageResult.blockedBy}"`,
|
|
557
|
-
});
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
731
|
// Generate title early — the user message alone is sufficient context.
|
|
562
|
-
// Firing
|
|
563
|
-
//
|
|
564
|
-
//
|
|
732
|
+
// Firing before the main LLM call removes the delay of waiting for the
|
|
733
|
+
// full assistant response. The second-pass regeneration at turn 3 will
|
|
734
|
+
// refine the title with more context.
|
|
565
735
|
// No abort signal — title generation should complete even if the user
|
|
566
736
|
// cancels the response, since the user message is already persisted.
|
|
567
737
|
// Deferred via setTimeout so the main agent loop LLM call enqueues
|
|
568
738
|
// first, avoiding rate-limit slot contention on strict configs.
|
|
569
|
-
if (
|
|
570
|
-
|
|
571
|
-
|
|
739
|
+
if (isReplaceableTitle(turnStartConversation?.title ?? null)) {
|
|
740
|
+
// TurnContext routed through the canonical builder so the pipeline's
|
|
741
|
+
// log record reports the same `conversationId`/`turnIndex` shape as
|
|
742
|
+
// every other slot in this turn. Title generation does not depend on
|
|
743
|
+
// the context-window manager attached by the builder, but sharing the
|
|
744
|
+
// builder keeps the invariant enforced in one place.
|
|
745
|
+
const titlePipelineCtx = buildPluginTurnContext(ctx, reqId);
|
|
746
|
+
const titleArgs = {
|
|
747
|
+
conversationId: ctx.conversationId,
|
|
748
|
+
provider: ctx.provider,
|
|
749
|
+
userMessage: options?.titleText ?? content,
|
|
750
|
+
onTitleUpdated: (title: string) => {
|
|
751
|
+
onEvent({
|
|
752
|
+
type: "conversation_title_updated",
|
|
753
|
+
conversationId: ctx.conversationId,
|
|
754
|
+
title,
|
|
755
|
+
});
|
|
756
|
+
},
|
|
757
|
+
};
|
|
572
758
|
setTimeout(() => {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
759
|
+
runPipeline(
|
|
760
|
+
"titleGenerate",
|
|
761
|
+
getMiddlewaresFor("titleGenerate"),
|
|
762
|
+
defaultTitleGenerateTerminal,
|
|
763
|
+
titleArgs,
|
|
764
|
+
titlePipelineCtx,
|
|
765
|
+
DEFAULT_TIMEOUTS.titleGenerate,
|
|
766
|
+
).catch((err) => {
|
|
767
|
+
// Fire-and-forget — keep previous non-propagating semantics.
|
|
768
|
+
// queueGenerateConversationTitle already swallows internal
|
|
769
|
+
// errors; this catch covers pipeline-layer errors (timeouts,
|
|
770
|
+
// middleware throws) without surfacing them to the agent loop.
|
|
771
|
+
rlog.warn({ err }, "titleGenerate pipeline failed (non-fatal)");
|
|
584
772
|
});
|
|
585
773
|
}, 0);
|
|
586
774
|
}
|
|
@@ -592,7 +780,7 @@ export async function runAgentLoopImpl(
|
|
|
592
780
|
const compactCheck = ctx.contextWindowManager.shouldCompact(ctx.messages);
|
|
593
781
|
// Skip auto-compaction while the circuit breaker is open. Force paths
|
|
594
782
|
// and user-initiated /compact bypass this check.
|
|
595
|
-
const autoCompactAllowed = !isCompactionCircuitOpen(ctx);
|
|
783
|
+
const autoCompactAllowed = !(await isCompactionCircuitOpen(ctx));
|
|
596
784
|
if (compactCheck.needed && autoCompactAllowed) {
|
|
597
785
|
ctx.emitActivityState(
|
|
598
786
|
"thinking",
|
|
@@ -601,69 +789,59 @@ export async function runAgentLoopImpl(
|
|
|
601
789
|
reqId,
|
|
602
790
|
);
|
|
603
791
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
792
|
+
let compacted: Awaited<
|
|
793
|
+
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
794
|
+
> | null = null;
|
|
795
|
+
if (autoCompactAllowed) {
|
|
796
|
+
try {
|
|
797
|
+
compacted = (await runPipeline<CompactionArgs, CompactionResult>(
|
|
798
|
+
"compaction",
|
|
799
|
+
getMiddlewaresFor("compaction"),
|
|
800
|
+
(args) =>
|
|
801
|
+
defaultCompactionTerminal(args, buildPluginTurnContext(ctx, reqId)),
|
|
608
802
|
{
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
803
|
+
messages: ctx.messages,
|
|
804
|
+
signal: abortController.signal,
|
|
805
|
+
options: {
|
|
806
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
807
|
+
precomputedEstimate: compactCheck.estimatedTokens,
|
|
808
|
+
conversationOriginChannel:
|
|
809
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
810
|
+
},
|
|
613
811
|
},
|
|
614
|
-
|
|
615
|
-
|
|
812
|
+
buildPluginTurnContext(ctx, reqId),
|
|
813
|
+
DEFAULT_TIMEOUTS.compaction,
|
|
814
|
+
)) as Awaited<ReturnType<typeof ctx.contextWindowManager.maybeCompact>>;
|
|
815
|
+
} catch (err) {
|
|
816
|
+
if (err instanceof PluginTimeoutError) {
|
|
817
|
+
// Pipeline exceeded its budget. Record the failure so the circuit
|
|
818
|
+
// breaker tracks consecutive timeouts (it trips after three),
|
|
819
|
+
// then degrade gracefully by skipping compaction this turn —
|
|
820
|
+
// the turn proceeds with the un-compacted history rather than
|
|
821
|
+
// hard-failing. The inner summary call has been aborted by the
|
|
822
|
+
// runner's signal-linking, so updateSummary's local fallback
|
|
823
|
+
// also ran before this catch block is reached.
|
|
824
|
+
rlog.warn(
|
|
825
|
+
{ err, phase: "start-of-turn-compaction" },
|
|
826
|
+
"Compaction pipeline timed out — skipping compaction this turn",
|
|
827
|
+
);
|
|
828
|
+
await trackCompactionOutcome(ctx, true, onEvent);
|
|
829
|
+
compacted = null;
|
|
830
|
+
} else {
|
|
831
|
+
throw err;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
616
835
|
// Only track circuit-breaker state when a summary LLM call actually ran.
|
|
617
836
|
// `summaryFailed` is `undefined` on early returns (compaction disabled,
|
|
618
837
|
// below threshold, cooldown active, no eligible messages, truncation-only
|
|
619
838
|
// path) — treating those as "successful" compactions would silently reset
|
|
620
839
|
// the 3-strike counter and break the invariant.
|
|
621
840
|
if (compacted && compacted.summaryFailed !== undefined) {
|
|
622
|
-
trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent);
|
|
841
|
+
await trackCompactionOutcome(ctx, compacted.summaryFailed, onEvent);
|
|
623
842
|
}
|
|
624
843
|
if (compacted?.compacted) {
|
|
625
|
-
ctx
|
|
626
|
-
ctx.contextCompactedMessageCount += compacted.compactedPersistedMessages;
|
|
627
|
-
ctx.contextCompactedAt = Date.now();
|
|
628
|
-
// Notify memory graph that compaction happened — triggers full context
|
|
629
|
-
// reload on the next turn to replenish lost memory context.
|
|
630
|
-
ctx.graphMemory.onCompacted(compacted.compactedPersistedMessages);
|
|
631
|
-
updateConversationContextWindow(
|
|
632
|
-
ctx.conversationId,
|
|
633
|
-
compacted.summaryText,
|
|
634
|
-
ctx.contextCompactedMessageCount,
|
|
635
|
-
);
|
|
636
|
-
// Fire auto-analysis on compaction so the reflective agent can
|
|
637
|
-
// crystallize anything worth remembering before the context window
|
|
638
|
-
// narrows further.
|
|
639
|
-
enqueueAutoAnalysisOnCompaction(
|
|
640
|
-
ctx.conversationId,
|
|
641
|
-
ctx.trustContext?.trustClass,
|
|
642
|
-
);
|
|
643
|
-
onEvent({
|
|
644
|
-
type: "context_compacted",
|
|
645
|
-
previousEstimatedInputTokens: compacted.previousEstimatedInputTokens,
|
|
646
|
-
estimatedInputTokens: compacted.estimatedInputTokens,
|
|
647
|
-
maxInputTokens: compacted.maxInputTokens,
|
|
648
|
-
thresholdTokens: compacted.thresholdTokens,
|
|
649
|
-
compactedMessages: compacted.compactedMessages,
|
|
650
|
-
summaryCalls: compacted.summaryCalls,
|
|
651
|
-
summaryInputTokens: compacted.summaryInputTokens,
|
|
652
|
-
summaryOutputTokens: compacted.summaryOutputTokens,
|
|
653
|
-
summaryModel: compacted.summaryModel,
|
|
654
|
-
});
|
|
655
|
-
emitUsage(
|
|
656
|
-
ctx,
|
|
657
|
-
compacted.summaryInputTokens,
|
|
658
|
-
compacted.summaryOutputTokens,
|
|
659
|
-
compacted.summaryModel,
|
|
660
|
-
onEvent,
|
|
661
|
-
"context_compactor",
|
|
662
|
-
reqId,
|
|
663
|
-
compacted.summaryCacheCreationInputTokens ?? 0,
|
|
664
|
-
compacted.summaryCacheReadInputTokens ?? 0,
|
|
665
|
-
collapseRawResponses(compacted.summaryRawResponses),
|
|
666
|
-
);
|
|
844
|
+
applyCompactionResult(ctx, compacted, onEvent, reqId);
|
|
667
845
|
shouldInjectWorkspace = true;
|
|
668
846
|
if (compacted.compactedPersistedMessages > 0) {
|
|
669
847
|
compactedThisTurn = true;
|
|
@@ -711,21 +889,58 @@ export async function runAgentLoopImpl(
|
|
|
711
889
|
|
|
712
890
|
let runMessages = ctx.messages;
|
|
713
891
|
|
|
714
|
-
// Memory
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
| undefined;
|
|
892
|
+
// Memory retrieval pipeline — fetches PKB, NOW.md, and memory-graph
|
|
893
|
+
// outputs through a single `memoryRetrieval` pipeline. Plugins may
|
|
894
|
+
// replace the terminal behavior by registering a middleware that
|
|
895
|
+
// short-circuits with its own `MemoryResult`; the default terminal
|
|
896
|
+
// below runs `runDefaultMemoryRetrieval` which reproduces the prior
|
|
897
|
+
// in-lined behavior (PKB/NOW reads + gated graph call).
|
|
721
898
|
const isTrustedActor = resolveTrustClass(ctx.trustContext) === "guardian";
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
899
|
+
// Canonical builder — pulls trust from per-turn snapshot, then
|
|
900
|
+
// conversation-level, then the synthetic fallback. Memory retrieval
|
|
901
|
+
// does not need the context-window handle the builder attaches, but
|
|
902
|
+
// keeping every call site on one helper is load-bearing for log
|
|
903
|
+
// coherence across pipeline slots.
|
|
904
|
+
const memoryPluginTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
905
|
+
const memoryArgs: MemoryArgs = {
|
|
906
|
+
conversationId: ctx.conversationId,
|
|
907
|
+
trustContext: ctx.trustContext,
|
|
908
|
+
turnIndex: ctx.turnCount,
|
|
909
|
+
// Pass the abort signal via `args` (not `deps`) so the pipeline
|
|
910
|
+
// runner's `linkAbortSignal` can swap it for a signal linked to the
|
|
911
|
+
// pipeline's internal controller — on a plugin-set timeout or
|
|
912
|
+
// external cancel, the linked signal aborts and `prepareMemory`
|
|
913
|
+
// stops mutating graph state / emitting events after the pipeline
|
|
914
|
+
// has already errored.
|
|
915
|
+
signal: abortController.signal,
|
|
916
|
+
};
|
|
917
|
+
const memoryDeps: DefaultMemoryRetrievalDeps = {
|
|
918
|
+
messages: ctx.messages,
|
|
919
|
+
graphMemory: ctx.graphMemory,
|
|
920
|
+
config: getConfig(),
|
|
921
|
+
onEvent,
|
|
922
|
+
isTrustedActor,
|
|
923
|
+
};
|
|
924
|
+
const memoryResult: MemoryResult = await runPipeline(
|
|
925
|
+
"memoryRetrieval",
|
|
926
|
+
getMiddlewaresFor("memoryRetrieval"),
|
|
927
|
+
(args) => runDefaultMemoryRetrieval(args, memoryDeps),
|
|
928
|
+
memoryArgs,
|
|
929
|
+
memoryPluginTurnCtx,
|
|
930
|
+
DEFAULT_TIMEOUTS.memoryRetrieval,
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
// Consume the memory-graph block when the default retriever emitted
|
|
934
|
+
// one. Custom plugins that substitute their own blocks without the
|
|
935
|
+
// default discriminator are expected to handle their own side effects
|
|
936
|
+
// (event emission, metric persistence) inside their middleware; this
|
|
937
|
+
// block short-circuits to the original no-op behavior in that case.
|
|
938
|
+
const defaultGraphPayload: GraphMemoryPayload | null =
|
|
939
|
+
asDefaultGraphPayload(memoryResult.memoryGraphBlocks);
|
|
940
|
+
let pkbQueryVector: number[] | undefined;
|
|
941
|
+
let pkbSparseVector: QdrantSparseVector | undefined;
|
|
942
|
+
if (defaultGraphPayload) {
|
|
943
|
+
const graphResult = defaultGraphPayload.result;
|
|
729
944
|
runMessages = graphResult.runMessages;
|
|
730
945
|
// Select dense+sparse as a matched pair so RRF fusion combines two
|
|
731
946
|
// signals aligned to the same query text:
|
|
@@ -746,12 +961,24 @@ export async function runAgentLoopImpl(
|
|
|
746
961
|
|
|
747
962
|
// Persist the injected block text in message metadata so it survives
|
|
748
963
|
// conversation reloads (eviction, restart, fork). loadFromDb re-injects
|
|
749
|
-
// from metadata.
|
|
964
|
+
// from metadata. Routed through the `persistence` pipeline so plugins
|
|
965
|
+
// can observe or override metadata updates alongside add/delete.
|
|
750
966
|
if (graphResult.injectedBlockText) {
|
|
751
967
|
try {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
968
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
969
|
+
"persistence",
|
|
970
|
+
getMiddlewaresFor("persistence"),
|
|
971
|
+
defaultPersistenceTerminal,
|
|
972
|
+
{
|
|
973
|
+
op: "update",
|
|
974
|
+
messageId: userMessageId,
|
|
975
|
+
updates: {
|
|
976
|
+
memoryInjectedBlock: graphResult.injectedBlockText,
|
|
977
|
+
},
|
|
978
|
+
},
|
|
979
|
+
buildPluginTurnContext(ctx, reqId),
|
|
980
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
981
|
+
);
|
|
755
982
|
} catch (err) {
|
|
756
983
|
rlog.warn(
|
|
757
984
|
{ err },
|
|
@@ -933,11 +1160,13 @@ export async function runAgentLoopImpl(
|
|
|
933
1160
|
// Inject NOW.md and PKB content only on the first turn (or after
|
|
934
1161
|
// compaction re-strips them). Old injections persist in history and
|
|
935
1162
|
// are never stripped on normal turns — this preserves the cached prefix.
|
|
936
|
-
|
|
1163
|
+
// PKB/NOW content is sourced from the `memoryRetrieval` pipeline above
|
|
1164
|
+
// so plugins can override either source without touching the agent loop.
|
|
1165
|
+
const currentNowContent = memoryResult.nowContent;
|
|
937
1166
|
const shouldInjectNowAndPkb = isFirstMessage || compactedThisTurn;
|
|
938
1167
|
const nowScratchpad = shouldInjectNowAndPkb ? currentNowContent : null;
|
|
939
1168
|
|
|
940
|
-
const currentPkbContent =
|
|
1169
|
+
const currentPkbContent = memoryResult.pkbContent;
|
|
941
1170
|
const pkbContext = shouldInjectNowAndPkb ? currentPkbContent : null;
|
|
942
1171
|
const pkbActive = currentPkbContent !== null;
|
|
943
1172
|
|
|
@@ -1030,12 +1259,19 @@ export async function runAgentLoopImpl(
|
|
|
1030
1259
|
|
|
1031
1260
|
let currentInjectionMode: InjectionMode = "full";
|
|
1032
1261
|
|
|
1262
|
+
// Canonical per-turn TurnContext forwarded to the injector chain. The
|
|
1263
|
+
// per-turn injection inputs are built inside `applyRuntimeInjections`
|
|
1264
|
+
// from the `injectionOpts` bag; we only need to hand in identity +
|
|
1265
|
+
// trust here so third-party injectors see the real turn metadata.
|
|
1266
|
+
const injectionTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
1267
|
+
|
|
1033
1268
|
const injection = await applyRuntimeInjections(runMessages, {
|
|
1034
1269
|
...injectionOpts,
|
|
1035
1270
|
slackChronologicalMessages: reducerCompacted
|
|
1036
1271
|
? null
|
|
1037
1272
|
: injectionOpts.slackChronologicalMessages,
|
|
1038
1273
|
mode: currentInjectionMode,
|
|
1274
|
+
turnContext: injectionTurnCtx,
|
|
1039
1275
|
});
|
|
1040
1276
|
runMessages = injection.messages;
|
|
1041
1277
|
|
|
@@ -1043,11 +1279,14 @@ export async function runAgentLoopImpl(
|
|
|
1043
1279
|
// reloads (eviction, restart, fork). loadFromDb re-injects from metadata.
|
|
1044
1280
|
// Only the first call site persists — the overflow-recovery re-entry sites
|
|
1045
1281
|
// send identical bytes and the tail row may not correspond to
|
|
1046
|
-
// `userMessageId`.
|
|
1282
|
+
// `userMessageId`. All blocks are written in a single call to avoid
|
|
1047
1283
|
// doubling SQLite SELECT+UPDATE work on every turn.
|
|
1048
1284
|
if (
|
|
1049
1285
|
injection.blocks.unifiedTurnContext ||
|
|
1050
|
-
injection.blocks.pkbSystemReminder
|
|
1286
|
+
injection.blocks.pkbSystemReminder ||
|
|
1287
|
+
injection.blocks.workspaceBlock ||
|
|
1288
|
+
injection.blocks.nowScratchpadBlock ||
|
|
1289
|
+
injection.blocks.pkbContextBlock
|
|
1051
1290
|
) {
|
|
1052
1291
|
try {
|
|
1053
1292
|
const metadataUpdates: Record<string, unknown> = {};
|
|
@@ -1059,7 +1298,28 @@ export async function runAgentLoopImpl(
|
|
|
1059
1298
|
metadataUpdates.pkbSystemReminderBlock =
|
|
1060
1299
|
injection.blocks.pkbSystemReminder;
|
|
1061
1300
|
}
|
|
1062
|
-
|
|
1301
|
+
if (injection.blocks.workspaceBlock) {
|
|
1302
|
+
metadataUpdates.workspaceBlock = injection.blocks.workspaceBlock;
|
|
1303
|
+
}
|
|
1304
|
+
if (injection.blocks.nowScratchpadBlock) {
|
|
1305
|
+
metadataUpdates.nowScratchpadBlock =
|
|
1306
|
+
injection.blocks.nowScratchpadBlock;
|
|
1307
|
+
}
|
|
1308
|
+
if (injection.blocks.pkbContextBlock) {
|
|
1309
|
+
metadataUpdates.pkbContextBlock = injection.blocks.pkbContextBlock;
|
|
1310
|
+
}
|
|
1311
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
1312
|
+
"persistence",
|
|
1313
|
+
getMiddlewaresFor("persistence"),
|
|
1314
|
+
defaultPersistenceTerminal,
|
|
1315
|
+
{
|
|
1316
|
+
op: "update",
|
|
1317
|
+
messageId: userMessageId,
|
|
1318
|
+
updates: metadataUpdates,
|
|
1319
|
+
},
|
|
1320
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1321
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
1322
|
+
);
|
|
1063
1323
|
} catch (err) {
|
|
1064
1324
|
rlog.warn({ err }, "Failed to persist injection metadata (non-fatal)");
|
|
1065
1325
|
}
|
|
@@ -1082,18 +1342,51 @@ export async function runAgentLoopImpl(
|
|
|
1082
1342
|
let reducerState: ReducerState | undefined;
|
|
1083
1343
|
|
|
1084
1344
|
const toolTokenBudget = ctx.agentLoop.getToolTokenBudget(runMessages);
|
|
1085
|
-
// Canonical calibration key
|
|
1086
|
-
//
|
|
1087
|
-
//
|
|
1345
|
+
// Canonical calibration key — passed to the `tokenEstimate` pipeline for
|
|
1346
|
+
// every preflight/mid-loop estimate, the overflow reducer config, and the
|
|
1347
|
+
// convergence-path `estimatePromptTokens` call. Matches the key recorded
|
|
1348
|
+
// by `handleUsage` for wrapper providers (OpenRouter routing to
|
|
1349
|
+
// Anthropic → key is `"anthropic"`).
|
|
1088
1350
|
const estimationProviderName = getCalibrationProviderKey(ctx.provider);
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1351
|
+
|
|
1352
|
+
// Shared `TurnContext` for every `tokenEstimate` pipeline invocation in
|
|
1353
|
+
// this turn. The pipeline is the extension point for plugins that want
|
|
1354
|
+
// to substitute an alternate estimator (e.g. provider-native tokenization)
|
|
1355
|
+
// without touching orchestrator code.
|
|
1356
|
+
//
|
|
1357
|
+
// Routed through the canonical builder — `turnIndex` is `ctx.turnCount`,
|
|
1358
|
+
// trust cascades through per-turn/conversation-level/fallback, and the
|
|
1359
|
+
// context-window handle rides along so any middleware that wants to
|
|
1360
|
+
// reuse the manager (e.g. to compute compaction-aware estimates) can.
|
|
1361
|
+
const pipelineTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
1362
|
+
|
|
1363
|
+
const runTokenEstimatePipeline = (
|
|
1364
|
+
history: Message[],
|
|
1365
|
+
): Promise<EstimateResult> =>
|
|
1366
|
+
runPipeline<EstimateArgs, EstimateResult>(
|
|
1367
|
+
"tokenEstimate",
|
|
1368
|
+
getMiddlewaresFor("tokenEstimate"),
|
|
1369
|
+
defaultTokenEstimateTerminal,
|
|
1370
|
+
{
|
|
1371
|
+
// Shallow-frozen copies so a misbehaving middleware that mutates
|
|
1372
|
+
// `args.history` or `args.tools` in place (e.g. trims the array
|
|
1373
|
+
// before calling next) can't silently strip prompt context from
|
|
1374
|
+
// the orchestrator's live `runMessages` / resolved-tools arrays.
|
|
1375
|
+
// TypeScript `readonly` on `EstimateArgs` does not prevent
|
|
1376
|
+
// `push`/`splice` at runtime; the frozen wrapper throws in strict
|
|
1377
|
+
// mode and isolates any mutation attempts from the call-site state.
|
|
1378
|
+
history: Object.freeze([...history]) as Message[],
|
|
1379
|
+
systemPrompt: ctx.systemPrompt,
|
|
1380
|
+
tools: Object.freeze([
|
|
1381
|
+
...ctx.agentLoop.getResolvedTools(history),
|
|
1382
|
+
]) as ToolDefinition[],
|
|
1383
|
+
providerName: estimationProviderName,
|
|
1384
|
+
},
|
|
1385
|
+
pipelineTurnCtx,
|
|
1386
|
+
DEFAULT_TIMEOUTS.tokenEstimate,
|
|
1387
|
+
);
|
|
1388
|
+
|
|
1389
|
+
const preflightTokens = await runTokenEstimatePipeline(runMessages);
|
|
1097
1390
|
|
|
1098
1391
|
if (overflowRecovery.enabled && preflightTokens > preflightBudget) {
|
|
1099
1392
|
rlog.warn(
|
|
@@ -1105,163 +1398,246 @@ export async function runAgentLoopImpl(
|
|
|
1105
1398
|
"Preflight budget exceeded — running overflow reducer before provider call",
|
|
1106
1399
|
);
|
|
1107
1400
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
"
|
|
1401
|
+
// Overflow reduction runs through the plugin pipeline. The default
|
|
1402
|
+
// middleware (`default-overflow-reduce`, registered at bootstrap)
|
|
1403
|
+
// contains the historical tier loop — forced compaction → tool-result
|
|
1404
|
+
// truncation → media stubbing → injection downgrade — plus the
|
|
1405
|
+
// re-inject/re-estimate convergence check. The callbacks below are
|
|
1406
|
+
// the orchestrator-specific side effects that the plugin coordinates
|
|
1407
|
+
// per iteration (activity emission, compaction application, runtime
|
|
1408
|
+
// injection reassembly, token re-estimation). Registered plugins that
|
|
1409
|
+
// wrap the `overflowReduce` slot see each iteration through their own
|
|
1410
|
+
// middleware `next` callback.
|
|
1411
|
+
const overflowArgs: OverflowReduceArgs = {
|
|
1412
|
+
messages: ctx.messages,
|
|
1413
|
+
runMessages,
|
|
1414
|
+
systemPrompt: ctx.systemPrompt,
|
|
1415
|
+
providerName: estimationProviderName,
|
|
1416
|
+
contextWindow: config.llm.default.contextWindow,
|
|
1417
|
+
preflightBudget,
|
|
1418
|
+
toolTokenBudget,
|
|
1419
|
+
maxAttempts: overflowRecovery.maxAttempts,
|
|
1420
|
+
abortSignal: abortController.signal,
|
|
1421
|
+
compactFn: async (msgs, signal, opts) => {
|
|
1422
|
+
// Route the reducer's forced-compaction tier through the
|
|
1423
|
+
// `compaction` pipeline so registered plugins observe these
|
|
1424
|
+
// invocations. Without this, custom compaction middleware only
|
|
1425
|
+
// sees the three orchestrator-owned call sites and misses the
|
|
1426
|
+
// reducer-initiated forced compactions entirely.
|
|
1427
|
+
//
|
|
1428
|
+
// Pipeline timeouts must be caught locally — a `PluginTimeoutError`
|
|
1429
|
+
// bubbling out of here would abort the overflow-reducer tier loop
|
|
1430
|
+
// entirely, skipping fallback tiers (tool-result truncation, media
|
|
1431
|
+
// stubbing, injection downgrade) and bypassing circuit-breaker
|
|
1432
|
+
// bookkeeping. On timeout, record the failure and return a
|
|
1433
|
+
// `compacted: false` result so the reducer falls through to the
|
|
1434
|
+
// next tier.
|
|
1435
|
+
try {
|
|
1436
|
+
return (await runPipeline<CompactionArgs, CompactionResult>(
|
|
1437
|
+
"compaction",
|
|
1438
|
+
getMiddlewaresFor("compaction"),
|
|
1439
|
+
(args) =>
|
|
1440
|
+
defaultCompactionTerminal(
|
|
1441
|
+
args,
|
|
1442
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1443
|
+
),
|
|
1444
|
+
{
|
|
1445
|
+
messages: msgs,
|
|
1446
|
+
signal,
|
|
1447
|
+
options: opts,
|
|
1448
|
+
},
|
|
1449
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1450
|
+
DEFAULT_TIMEOUTS.compaction,
|
|
1451
|
+
)) as Awaited<
|
|
1452
|
+
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
1453
|
+
>;
|
|
1454
|
+
} catch (err) {
|
|
1455
|
+
if (err instanceof PluginTimeoutError) {
|
|
1456
|
+
rlog.warn(
|
|
1457
|
+
{ err, phase: "overflow-reducer-forced-compaction" },
|
|
1458
|
+
"Compaction pipeline timed out — falling through to next reducer tier",
|
|
1459
|
+
);
|
|
1460
|
+
await trackCompactionOutcome(ctx, true, onEvent);
|
|
1461
|
+
return {
|
|
1462
|
+
messages: msgs,
|
|
1463
|
+
compacted: false,
|
|
1464
|
+
previousEstimatedInputTokens: 0,
|
|
1465
|
+
estimatedInputTokens: 0,
|
|
1466
|
+
maxInputTokens: 0,
|
|
1467
|
+
thresholdTokens: 0,
|
|
1468
|
+
compactedMessages: 0,
|
|
1469
|
+
compactedPersistedMessages: 0,
|
|
1470
|
+
summaryCalls: 0,
|
|
1471
|
+
summaryInputTokens: 0,
|
|
1472
|
+
summaryOutputTokens: 0,
|
|
1473
|
+
summaryModel: "",
|
|
1474
|
+
summaryText: "",
|
|
1475
|
+
reason: "compaction pipeline timed out",
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
throw err;
|
|
1479
|
+
}
|
|
1480
|
+
},
|
|
1481
|
+
emitActivityState: () => {
|
|
1482
|
+
ctx.emitActivityState(
|
|
1483
|
+
"thinking",
|
|
1484
|
+
"context_compacting",
|
|
1485
|
+
"assistant_turn",
|
|
1193
1486
|
reqId,
|
|
1194
|
-
step.compactionResult.summaryCacheCreationInputTokens ?? 0,
|
|
1195
|
-
step.compactionResult.summaryCacheReadInputTokens ?? 0,
|
|
1196
|
-
collapseRawResponses(step.compactionResult.summaryRawResponses),
|
|
1197
|
-
);
|
|
1198
|
-
ctx.graphMemory.onCompacted(
|
|
1199
|
-
step.compactionResult.compactedPersistedMessages,
|
|
1200
1487
|
);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
{
|
|
1488
|
+
},
|
|
1489
|
+
onCompactionResult: async (result) => {
|
|
1490
|
+
// Track circuit-breaker state whenever the reducer invoked
|
|
1491
|
+
// compaction. The reducer's forced_compaction tier uses
|
|
1492
|
+
// force:true, so it bypasses the open-circuit check, but we
|
|
1493
|
+
// still want failure tracking to detect a run of broken
|
|
1494
|
+
// summaries and clear the counter on success. Only track when
|
|
1495
|
+
// the summary LLM actually ran — `summaryFailed === undefined`
|
|
1496
|
+
// indicates an early return (no eligible messages,
|
|
1497
|
+
// truncation-only path, etc.) that shouldn't influence the
|
|
1498
|
+
// breaker.
|
|
1499
|
+
if (result.summaryFailed !== undefined) {
|
|
1500
|
+
await trackCompactionOutcome(ctx, result.summaryFailed, onEvent);
|
|
1501
|
+
}
|
|
1502
|
+
if (result.compacted) {
|
|
1503
|
+
applyCompactionResult(ctx, result, onEvent, reqId);
|
|
1504
|
+
shouldInjectWorkspace = true;
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
reinjectForMode: async (
|
|
1508
|
+
reducedMessages,
|
|
1509
|
+
mode,
|
|
1510
|
+
stepCompacted,
|
|
1511
|
+
accumulatedCompacted,
|
|
1512
|
+
) => {
|
|
1513
|
+
// Mirror the pre-PR-23 behavior: `ctx.messages` must track the
|
|
1514
|
+
// reducer's latest output before re-injection runs, because other
|
|
1515
|
+
// sites consulted through `injectionOpts` (`workspaceTopLevelContext`,
|
|
1516
|
+
// slack history, etc.) depend on it and `applyCompactionResult`
|
|
1517
|
+
// only updates `ctx.messages` on a compaction tier. Assigning here
|
|
1518
|
+
// keeps non-compaction tiers (tool-result truncation, media
|
|
1519
|
+
// stubbing, injection downgrade) observable to downstream
|
|
1520
|
+
// injection assembly on the same turn.
|
|
1521
|
+
ctx.messages = reducedMessages;
|
|
1522
|
+
|
|
1523
|
+
// When THIS iteration compacted, it stripped existing NOW.md /
|
|
1524
|
+
// PKB blocks — so we re-inject current content. A later iteration
|
|
1525
|
+
// that only truncates or downgrades must NOT re-force PKB/NOW,
|
|
1526
|
+
// or each round would grow the token count.
|
|
1527
|
+
// Gate: only the iteration that actually compacted re-injects.
|
|
1528
|
+
const injection = await applyRuntimeInjections(reducedMessages, {
|
|
1529
|
+
...injectionOpts,
|
|
1530
|
+
...(stepCompacted && { pkbContext: currentPkbContent }),
|
|
1531
|
+
...(stepCompacted && { nowScratchpad: currentNowContent }),
|
|
1532
|
+
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1533
|
+
? ctx.workspaceTopLevelContext
|
|
1534
|
+
: null,
|
|
1535
|
+
// Once ANY iteration has compacted `ctx.messages`, the captured
|
|
1536
|
+
// `slackChronologicalMessages` snapshot (built from the full
|
|
1537
|
+
// persisted transcript) would overwrite the compacted history
|
|
1538
|
+
// and undo compaction. Suppress the override from here on —
|
|
1539
|
+
// sticky across subsequent non-compacting iterations.
|
|
1540
|
+
slackChronologicalMessages: accumulatedCompacted
|
|
1541
|
+
? null
|
|
1542
|
+
: injectionOpts.slackChronologicalMessages,
|
|
1543
|
+
mode,
|
|
1544
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
1545
|
+
});
|
|
1546
|
+
let next = injection.messages;
|
|
1547
|
+
if (isTrustedActor && mode !== "minimal") {
|
|
1548
|
+
const memResult = ctx.graphMemory.reinjectCachedMemory(next);
|
|
1549
|
+
next = memResult.runMessages;
|
|
1550
|
+
}
|
|
1551
|
+
return next;
|
|
1552
|
+
},
|
|
1553
|
+
estimatePostInjection: (runMsgs) =>
|
|
1554
|
+
estimatePromptTokens(runMsgs, ctx.systemPrompt, {
|
|
1242
1555
|
providerName: estimationProviderName,
|
|
1243
1556
|
toolTokenBudget,
|
|
1244
|
-
},
|
|
1245
|
-
|
|
1557
|
+
}),
|
|
1558
|
+
};
|
|
1246
1559
|
|
|
1247
|
-
|
|
1560
|
+
const overflowResult = await runPipeline<
|
|
1561
|
+
OverflowReduceArgs,
|
|
1562
|
+
OverflowReduceResult
|
|
1563
|
+
>(
|
|
1564
|
+
"overflowReduce",
|
|
1565
|
+
getMiddlewaresFor("overflowReduce"),
|
|
1566
|
+
// Terminal — only reached when every registered middleware calls
|
|
1567
|
+
// `next` and delegates past the innermost layer. The default plugin
|
|
1568
|
+
// is a terminal itself (it doesn't call `next`), so in practice
|
|
1569
|
+
// this fallback fires only when the default has been explicitly
|
|
1570
|
+
// deregistered (tests) and no user plugin replaces it. Strict-fail
|
|
1571
|
+
// semantics: throw so the missing terminal surfaces as a visible
|
|
1572
|
+
// error instead of silently returning the history untouched.
|
|
1573
|
+
async () => {
|
|
1574
|
+
throw new PluginExecutionError(
|
|
1575
|
+
"overflowReduce pipeline has no terminal handler — every reducer middleware called next() without providing a replacement",
|
|
1576
|
+
"overflowReduce",
|
|
1577
|
+
);
|
|
1578
|
+
},
|
|
1579
|
+
overflowArgs,
|
|
1580
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1581
|
+
DEFAULT_TIMEOUTS.overflowReduce,
|
|
1582
|
+
);
|
|
1583
|
+
|
|
1584
|
+
ctx.messages = overflowResult.messages;
|
|
1585
|
+
runMessages = overflowResult.runMessages;
|
|
1586
|
+
currentInjectionMode = overflowResult.injectionMode;
|
|
1587
|
+
reducerState = overflowResult.reducerState;
|
|
1588
|
+
if (overflowResult.reducerCompacted) {
|
|
1589
|
+
reducerCompacted = true;
|
|
1248
1590
|
}
|
|
1249
1591
|
}
|
|
1250
1592
|
|
|
1251
|
-
// Pre-run repair
|
|
1593
|
+
// Pre-run repair — routed through the `historyRepair` plugin pipeline so
|
|
1594
|
+
// plugins can observe or override repair behavior. The default plugin's
|
|
1595
|
+
// middleware is a passthrough; the actual repair runs in the terminal
|
|
1596
|
+
// (`defaultHistoryRepairTerminal`).
|
|
1252
1597
|
let preRepairMessages = runMessages;
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
preRunRepair
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
"Repaired runtime history before provider call",
|
|
1598
|
+
let preRunRepair: HistoryRepairResult | null = null;
|
|
1599
|
+
try {
|
|
1600
|
+
preRunRepair = await runPipeline<HistoryRepairArgs, HistoryRepairResult>(
|
|
1601
|
+
"historyRepair",
|
|
1602
|
+
getMiddlewaresFor("historyRepair"),
|
|
1603
|
+
async (args) => defaultHistoryRepairTerminal(args),
|
|
1604
|
+
{ history: runMessages, provider: ctx.provider.name },
|
|
1605
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1606
|
+
DEFAULT_TIMEOUTS.historyRepair,
|
|
1263
1607
|
);
|
|
1608
|
+
} catch (err) {
|
|
1609
|
+
if (err instanceof PluginTimeoutError) {
|
|
1610
|
+
// Pipeline exceeded its budget — likely a misbehaving third-party
|
|
1611
|
+
// middleware. Degrade gracefully by proceeding with the un-repaired
|
|
1612
|
+
// history rather than turn-fatal-erroring; un-repaired history is
|
|
1613
|
+
// strictly better than no turn at all, and the provider call itself
|
|
1614
|
+
// will still error visibly if the drift is unrecoverable.
|
|
1615
|
+
rlog.warn(
|
|
1616
|
+
{ err, phase: "pre_run" },
|
|
1617
|
+
"historyRepair pipeline timed out — proceeding with un-repaired history",
|
|
1618
|
+
);
|
|
1619
|
+
} else {
|
|
1620
|
+
throw err;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
if (preRunRepair !== null) {
|
|
1624
|
+
// Always adopt the pipeline's output history — a user `historyRepair`
|
|
1625
|
+
// middleware may rewrite `messages` (e.g. provider-specific
|
|
1626
|
+
// normalization) without incrementing any of the built-in repair
|
|
1627
|
+
// counters. Gating the assignment on `stats` would silently discard
|
|
1628
|
+
// those edits and send the un-rewritten history to the provider.
|
|
1264
1629
|
runMessages = preRunRepair.messages;
|
|
1630
|
+
if (
|
|
1631
|
+
preRunRepair.stats.assistantToolResultsMigrated > 0 ||
|
|
1632
|
+
preRunRepair.stats.missingToolResultsInserted > 0 ||
|
|
1633
|
+
preRunRepair.stats.orphanToolResultsDowngraded > 0 ||
|
|
1634
|
+
preRunRepair.stats.consecutiveSameRoleMerged > 0
|
|
1635
|
+
) {
|
|
1636
|
+
rlog.warn(
|
|
1637
|
+
{ phase: "pre_run", ...preRunRepair.stats },
|
|
1638
|
+
"Repaired runtime history before provider call",
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1265
1641
|
}
|
|
1266
1642
|
|
|
1267
1643
|
// Replace historical web_search_tool_result blocks with text summaries.
|
|
@@ -1299,7 +1675,9 @@ export async function runAgentLoopImpl(
|
|
|
1299
1675
|
|
|
1300
1676
|
let yieldedForBudget = false;
|
|
1301
1677
|
|
|
1302
|
-
const onCheckpoint = (
|
|
1678
|
+
const onCheckpoint = async (
|
|
1679
|
+
checkpoint: CheckpointInfo,
|
|
1680
|
+
): Promise<CheckpointDecision> => {
|
|
1303
1681
|
state.currentTurnToolNames = [];
|
|
1304
1682
|
|
|
1305
1683
|
if (ctx.canHandoffAtCheckpoint()) {
|
|
@@ -1312,14 +1690,7 @@ export async function runAgentLoopImpl(
|
|
|
1312
1690
|
// conversation-agent-loop run compaction before the provider rejects.
|
|
1313
1691
|
if (overflowRecovery.enabled) {
|
|
1314
1692
|
const midLoopThreshold = preflightBudget * 0.85;
|
|
1315
|
-
const estimated =
|
|
1316
|
-
checkpoint.history,
|
|
1317
|
-
ctx.systemPrompt,
|
|
1318
|
-
{
|
|
1319
|
-
providerName: estimationProviderName,
|
|
1320
|
-
toolTokenBudget,
|
|
1321
|
-
},
|
|
1322
|
-
);
|
|
1693
|
+
const estimated = await runTokenEstimatePipeline(checkpoint.history);
|
|
1323
1694
|
if (estimated > midLoopThreshold) {
|
|
1324
1695
|
rlog.warn(
|
|
1325
1696
|
{ phase: "mid-loop", estimated, threshold: midLoopThreshold },
|
|
@@ -1335,10 +1706,16 @@ export async function runAgentLoopImpl(
|
|
|
1335
1706
|
|
|
1336
1707
|
turnStarted = true;
|
|
1337
1708
|
|
|
1338
|
-
let denyCompressionMessage: Message | null = null;
|
|
1339
|
-
|
|
1340
1709
|
rlog.info({ callSite: turnCallSite }, "Starting agent loop run");
|
|
1341
1710
|
|
|
1711
|
+
// Thread the orchestrator's canonical per-turn context into the agent
|
|
1712
|
+
// loop so its internal pipeline invocations (llmCall, emptyResponse,
|
|
1713
|
+
// toolError, toolResultTruncate, toolExecute) see the real
|
|
1714
|
+
// conversation identity / trust / contextWindowManager instead of the
|
|
1715
|
+
// synthesized `"agent-loop"` placeholder. The loop clones this value
|
|
1716
|
+
// and overwrites `turnIndex` with its own tool-use iteration counter.
|
|
1717
|
+
const loopTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
1718
|
+
|
|
1342
1719
|
let updatedHistory = await ctx.agentLoop.run(
|
|
1343
1720
|
runMessages,
|
|
1344
1721
|
eventHandler,
|
|
@@ -1346,6 +1723,8 @@ export async function runAgentLoopImpl(
|
|
|
1346
1723
|
reqId,
|
|
1347
1724
|
onCheckpoint,
|
|
1348
1725
|
turnCallSite,
|
|
1726
|
+
loopTurnCtx,
|
|
1727
|
+
turnOverrideProfile,
|
|
1349
1728
|
);
|
|
1350
1729
|
|
|
1351
1730
|
rlog.info(
|
|
@@ -1379,11 +1758,11 @@ export async function runAgentLoopImpl(
|
|
|
1379
1758
|
const rawHistory = stripInjectionsForCompaction(updatedHistory);
|
|
1380
1759
|
ctx.messages = rawHistory;
|
|
1381
1760
|
try {
|
|
1382
|
-
|
|
1761
|
+
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
1383
1762
|
} catch (err) {
|
|
1384
1763
|
rlog.warn(
|
|
1385
1764
|
{ err },
|
|
1386
|
-
"Failed to clear
|
|
1765
|
+
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
1387
1766
|
);
|
|
1388
1767
|
}
|
|
1389
1768
|
|
|
@@ -1394,65 +1773,61 @@ export async function runAgentLoopImpl(
|
|
|
1394
1773
|
reqId,
|
|
1395
1774
|
"Compacting context",
|
|
1396
1775
|
);
|
|
1397
|
-
|
|
1398
|
-
ctx.
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1776
|
+
let midLoopCompact: Awaited<
|
|
1777
|
+
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
1778
|
+
>;
|
|
1779
|
+
try {
|
|
1780
|
+
midLoopCompact = (await runPipeline<CompactionArgs, CompactionResult>(
|
|
1781
|
+
"compaction",
|
|
1782
|
+
getMiddlewaresFor("compaction"),
|
|
1783
|
+
(args) =>
|
|
1784
|
+
defaultCompactionTerminal(args, buildPluginTurnContext(ctx, reqId)),
|
|
1785
|
+
{
|
|
1786
|
+
messages: ctx.messages,
|
|
1787
|
+
signal: abortController.signal,
|
|
1788
|
+
options: {
|
|
1789
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1790
|
+
force: true,
|
|
1791
|
+
targetInputTokensOverride: preflightBudget,
|
|
1792
|
+
conversationOriginChannel:
|
|
1793
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
1794
|
+
},
|
|
1795
|
+
},
|
|
1796
|
+
buildPluginTurnContext(ctx, reqId),
|
|
1797
|
+
DEFAULT_TIMEOUTS.compaction,
|
|
1798
|
+
)) as Awaited<ReturnType<typeof ctx.contextWindowManager.maybeCompact>>;
|
|
1799
|
+
} catch (err) {
|
|
1800
|
+
if (err instanceof PluginTimeoutError) {
|
|
1801
|
+
// Mid-loop compaction timed out. Record the failure for the
|
|
1802
|
+
// circuit breaker and escalate to the convergence loop's more
|
|
1803
|
+
// aggressive reducer tiers (tool-result truncation, media
|
|
1804
|
+
// stubbing, injection downgrade) by flipping the overflow flag
|
|
1805
|
+
// and breaking out of the mid-loop retry. The existing
|
|
1806
|
+
// "exhausted all attempts" block further down handles the
|
|
1807
|
+
// escalation.
|
|
1808
|
+
rlog.warn(
|
|
1809
|
+
{ err, phase: "mid-loop-compact" },
|
|
1810
|
+
"Compaction pipeline timed out — escalating to convergence loop",
|
|
1811
|
+
);
|
|
1812
|
+
await trackCompactionOutcome(ctx, true, onEvent);
|
|
1813
|
+
state.contextTooLargeDetected = true;
|
|
1814
|
+
break;
|
|
1815
|
+
}
|
|
1816
|
+
throw err;
|
|
1817
|
+
}
|
|
1408
1818
|
// `force: true` bypasses the cooldown/threshold gates but early returns
|
|
1409
1819
|
// for "no eligible messages" / "insufficient messages" still leave
|
|
1410
1820
|
// `summaryFailed` undefined. Only track when the summary LLM actually ran.
|
|
1411
1821
|
if (midLoopCompact.summaryFailed !== undefined) {
|
|
1412
|
-
trackCompactionOutcome(
|
|
1413
|
-
}
|
|
1414
|
-
if (midLoopCompact.compacted) {
|
|
1415
|
-
ctx.messages = midLoopCompact.messages;
|
|
1416
|
-
reducerCompacted = true;
|
|
1417
|
-
ctx.contextCompactedMessageCount +=
|
|
1418
|
-
midLoopCompact.compactedPersistedMessages;
|
|
1419
|
-
ctx.contextCompactedAt = Date.now();
|
|
1420
|
-
updateConversationContextWindow(
|
|
1421
|
-
ctx.conversationId,
|
|
1422
|
-
midLoopCompact.summaryText,
|
|
1423
|
-
ctx.contextCompactedMessageCount,
|
|
1424
|
-
);
|
|
1425
|
-
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1426
|
-
enqueueAutoAnalysisOnCompaction(
|
|
1427
|
-
ctx.conversationId,
|
|
1428
|
-
ctx.trustContext?.trustClass,
|
|
1429
|
-
);
|
|
1430
|
-
onEvent({
|
|
1431
|
-
type: "context_compacted",
|
|
1432
|
-
previousEstimatedInputTokens:
|
|
1433
|
-
midLoopCompact.previousEstimatedInputTokens,
|
|
1434
|
-
estimatedInputTokens: midLoopCompact.estimatedInputTokens,
|
|
1435
|
-
maxInputTokens: midLoopCompact.maxInputTokens,
|
|
1436
|
-
thresholdTokens: midLoopCompact.thresholdTokens,
|
|
1437
|
-
compactedMessages: midLoopCompact.compactedMessages,
|
|
1438
|
-
summaryCalls: midLoopCompact.summaryCalls,
|
|
1439
|
-
summaryInputTokens: midLoopCompact.summaryInputTokens,
|
|
1440
|
-
summaryOutputTokens: midLoopCompact.summaryOutputTokens,
|
|
1441
|
-
summaryModel: midLoopCompact.summaryModel,
|
|
1442
|
-
});
|
|
1443
|
-
emitUsage(
|
|
1822
|
+
await trackCompactionOutcome(
|
|
1444
1823
|
ctx,
|
|
1445
|
-
midLoopCompact.
|
|
1446
|
-
midLoopCompact.summaryOutputTokens,
|
|
1447
|
-
midLoopCompact.summaryModel,
|
|
1824
|
+
midLoopCompact.summaryFailed,
|
|
1448
1825
|
onEvent,
|
|
1449
|
-
"context_compactor",
|
|
1450
|
-
reqId,
|
|
1451
|
-
midLoopCompact.summaryCacheCreationInputTokens ?? 0,
|
|
1452
|
-
midLoopCompact.summaryCacheReadInputTokens ?? 0,
|
|
1453
|
-
collapseRawResponses(midLoopCompact.summaryRawResponses),
|
|
1454
1826
|
);
|
|
1455
|
-
|
|
1827
|
+
}
|
|
1828
|
+
if (midLoopCompact.compacted) {
|
|
1829
|
+
applyCompactionResult(ctx, midLoopCompact, onEvent, reqId);
|
|
1830
|
+
reducerCompacted = true;
|
|
1456
1831
|
shouldInjectWorkspace = true;
|
|
1457
1832
|
}
|
|
1458
1833
|
|
|
@@ -1474,6 +1849,7 @@ export async function runAgentLoopImpl(
|
|
|
1474
1849
|
? null
|
|
1475
1850
|
: injectionOpts.slackChronologicalMessages,
|
|
1476
1851
|
mode: currentInjectionMode,
|
|
1852
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
1477
1853
|
});
|
|
1478
1854
|
runMessages = injection.messages;
|
|
1479
1855
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
@@ -1497,6 +1873,8 @@ export async function runAgentLoopImpl(
|
|
|
1497
1873
|
reqId,
|
|
1498
1874
|
onCheckpoint,
|
|
1499
1875
|
turnCallSite,
|
|
1876
|
+
loopTurnCtx,
|
|
1877
|
+
turnOverrideProfile,
|
|
1500
1878
|
);
|
|
1501
1879
|
}
|
|
1502
1880
|
|
|
@@ -1526,6 +1904,15 @@ export async function runAgentLoopImpl(
|
|
|
1526
1904
|
{ phase: "retry" },
|
|
1527
1905
|
"Provider ordering error detected, attempting one-shot deep-repair retry",
|
|
1528
1906
|
);
|
|
1907
|
+
// Design note: deep-repair intentionally bypasses the `historyRepair`
|
|
1908
|
+
// plugin pipeline. Deep-repair is a recovery-only path triggered by a
|
|
1909
|
+
// provider ordering error — it must be deterministic and unaffected by
|
|
1910
|
+
// user middleware that might have caused (or be unable to recover from)
|
|
1911
|
+
// the original drift. Plugins can already observe / override the
|
|
1912
|
+
// pre-run repair via the `historyRepair` pipeline above; widening that
|
|
1913
|
+
// surface to deep-repair is intentionally deferred until there's a
|
|
1914
|
+
// concrete plugin-level use case. Do not route this call through
|
|
1915
|
+
// `runPipeline` without first revisiting that contract.
|
|
1529
1916
|
const retryRepair = deepRepairHistory(runMessages);
|
|
1530
1917
|
runMessages = retryRepair.messages;
|
|
1531
1918
|
const retryStrip = stripHistoricalWebSearchResults(runMessages);
|
|
@@ -1542,6 +1929,8 @@ export async function runAgentLoopImpl(
|
|
|
1542
1929
|
reqId,
|
|
1543
1930
|
onCheckpoint,
|
|
1544
1931
|
turnCallSite,
|
|
1932
|
+
loopTurnCtx,
|
|
1933
|
+
turnOverrideProfile,
|
|
1545
1934
|
);
|
|
1546
1935
|
|
|
1547
1936
|
if (state.orderingErrorDetected) {
|
|
@@ -1555,8 +1944,7 @@ export async function runAgentLoopImpl(
|
|
|
1555
1944
|
// ── Bounded context overflow convergence loop ──────────────────
|
|
1556
1945
|
// When the provider rejects with context-too-large, iterate through
|
|
1557
1946
|
// reducer tiers (forced compaction, tool-result truncation, media
|
|
1558
|
-
// stubbing, injection downgrade)
|
|
1559
|
-
// interactive latest-turn compression.
|
|
1947
|
+
// stubbing, injection downgrade).
|
|
1560
1948
|
//
|
|
1561
1949
|
// When progress was made (agent added messages before hitting the
|
|
1562
1950
|
// limit), incorporate those new messages into ctx.messages so the
|
|
@@ -1572,11 +1960,11 @@ export async function runAgentLoopImpl(
|
|
|
1572
1960
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
1573
1961
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
1574
1962
|
try {
|
|
1575
|
-
|
|
1963
|
+
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
1576
1964
|
} catch (err) {
|
|
1577
1965
|
rlog.warn(
|
|
1578
1966
|
{ err },
|
|
1579
|
-
"Failed to clear
|
|
1967
|
+
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
1580
1968
|
);
|
|
1581
1969
|
}
|
|
1582
1970
|
convergenceStripped = true;
|
|
@@ -1675,7 +2063,7 @@ export async function runAgentLoopImpl(
|
|
|
1675
2063
|
step.compactionResult &&
|
|
1676
2064
|
step.compactionResult.summaryFailed !== undefined
|
|
1677
2065
|
) {
|
|
1678
|
-
trackCompactionOutcome(
|
|
2066
|
+
await trackCompactionOutcome(
|
|
1679
2067
|
ctx,
|
|
1680
2068
|
step.compactionResult.summaryFailed,
|
|
1681
2069
|
onEvent,
|
|
@@ -1683,47 +2071,7 @@ export async function runAgentLoopImpl(
|
|
|
1683
2071
|
}
|
|
1684
2072
|
|
|
1685
2073
|
if (step.compactionResult?.compacted) {
|
|
1686
|
-
ctx.
|
|
1687
|
-
step.compactionResult.compactedPersistedMessages;
|
|
1688
|
-
ctx.contextCompactedAt = Date.now();
|
|
1689
|
-
updateConversationContextWindow(
|
|
1690
|
-
ctx.conversationId,
|
|
1691
|
-
step.compactionResult.summaryText,
|
|
1692
|
-
ctx.contextCompactedMessageCount,
|
|
1693
|
-
);
|
|
1694
|
-
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1695
|
-
enqueueAutoAnalysisOnCompaction(
|
|
1696
|
-
ctx.conversationId,
|
|
1697
|
-
ctx.trustContext?.trustClass,
|
|
1698
|
-
);
|
|
1699
|
-
onEvent({
|
|
1700
|
-
type: "context_compacted",
|
|
1701
|
-
previousEstimatedInputTokens:
|
|
1702
|
-
step.compactionResult.previousEstimatedInputTokens,
|
|
1703
|
-
estimatedInputTokens: step.compactionResult.estimatedInputTokens,
|
|
1704
|
-
maxInputTokens: step.compactionResult.maxInputTokens,
|
|
1705
|
-
thresholdTokens: step.compactionResult.thresholdTokens,
|
|
1706
|
-
compactedMessages: step.compactionResult.compactedMessages,
|
|
1707
|
-
summaryCalls: step.compactionResult.summaryCalls,
|
|
1708
|
-
summaryInputTokens: step.compactionResult.summaryInputTokens,
|
|
1709
|
-
summaryOutputTokens: step.compactionResult.summaryOutputTokens,
|
|
1710
|
-
summaryModel: step.compactionResult.summaryModel,
|
|
1711
|
-
});
|
|
1712
|
-
emitUsage(
|
|
1713
|
-
ctx,
|
|
1714
|
-
step.compactionResult.summaryInputTokens,
|
|
1715
|
-
step.compactionResult.summaryOutputTokens,
|
|
1716
|
-
step.compactionResult.summaryModel,
|
|
1717
|
-
onEvent,
|
|
1718
|
-
"context_compactor",
|
|
1719
|
-
reqId,
|
|
1720
|
-
step.compactionResult.summaryCacheCreationInputTokens ?? 0,
|
|
1721
|
-
step.compactionResult.summaryCacheReadInputTokens ?? 0,
|
|
1722
|
-
collapseRawResponses(step.compactionResult.summaryRawResponses),
|
|
1723
|
-
);
|
|
1724
|
-
ctx.graphMemory.onCompacted(
|
|
1725
|
-
step.compactionResult.compactedPersistedMessages,
|
|
1726
|
-
);
|
|
2074
|
+
applyCompactionResult(ctx, step.compactionResult, onEvent, reqId);
|
|
1727
2075
|
shouldInjectWorkspace = true;
|
|
1728
2076
|
reducerCompacted = true;
|
|
1729
2077
|
}
|
|
@@ -1742,6 +2090,7 @@ export async function runAgentLoopImpl(
|
|
|
1742
2090
|
? null
|
|
1743
2091
|
: injectionOpts.slackChronologicalMessages,
|
|
1744
2092
|
mode: currentInjectionMode,
|
|
2093
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
1745
2094
|
});
|
|
1746
2095
|
runMessages = injection.messages;
|
|
1747
2096
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
@@ -1767,6 +2116,8 @@ export async function runAgentLoopImpl(
|
|
|
1767
2116
|
reqId,
|
|
1768
2117
|
onCheckpoint,
|
|
1769
2118
|
turnCallSite,
|
|
2119
|
+
loopTurnCtx,
|
|
2120
|
+
turnOverrideProfile,
|
|
1770
2121
|
);
|
|
1771
2122
|
|
|
1772
2123
|
// If the rerun still yields at checkpoint, the turn is still
|
|
@@ -1789,11 +2140,11 @@ export async function runAgentLoopImpl(
|
|
|
1789
2140
|
if (updatedHistory.length > preRunHistoryLength) {
|
|
1790
2141
|
ctx.messages = stripInjectionsForCompaction(updatedHistory);
|
|
1791
2142
|
try {
|
|
1792
|
-
|
|
2143
|
+
clearStrippedInjectionMetadataForConversation(ctx.conversationId);
|
|
1793
2144
|
} catch (err) {
|
|
1794
2145
|
rlog.warn(
|
|
1795
2146
|
{ err },
|
|
1796
|
-
"Failed to clear
|
|
2147
|
+
"Failed to clear stripped-injection metadata after compaction strip (non-fatal)",
|
|
1797
2148
|
);
|
|
1798
2149
|
}
|
|
1799
2150
|
convergenceStripped = true;
|
|
@@ -1805,231 +2156,83 @@ export async function runAgentLoopImpl(
|
|
|
1805
2156
|
|
|
1806
2157
|
// All reducer tiers exhausted but provider still rejects —
|
|
1807
2158
|
// consult the overflow policy for latest-turn compression.
|
|
1808
|
-
//
|
|
1809
|
-
//
|
|
2159
|
+
// The policy either auto-compresses the latest turn or falls
|
|
2160
|
+
// through to the final graceful-error fallback below.
|
|
1810
2161
|
if (state.contextTooLargeDetected) {
|
|
1811
2162
|
const action = resolveOverflowAction({
|
|
1812
2163
|
overflowRecovery,
|
|
1813
2164
|
isInteractive: isInteractiveResolved,
|
|
1814
2165
|
});
|
|
1815
2166
|
|
|
1816
|
-
if (action === "
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
2167
|
+
if (action === "auto_compress_latest_turn") {
|
|
2168
|
+
// Auto-compress without asking — users opt out via the "drop" policy.
|
|
2169
|
+
ctx.emitActivityState(
|
|
2170
|
+
"thinking",
|
|
2171
|
+
"context_compacting",
|
|
2172
|
+
"assistant_turn",
|
|
2173
|
+
reqId,
|
|
2174
|
+
);
|
|
2175
|
+
let emergencyCompact: Awaited<
|
|
2176
|
+
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2177
|
+
> | null = null;
|
|
2178
|
+
try {
|
|
2179
|
+
emergencyCompact = (await runPipeline<
|
|
2180
|
+
CompactionArgs,
|
|
2181
|
+
CompactionResult
|
|
2182
|
+
>(
|
|
2183
|
+
"compaction",
|
|
2184
|
+
getMiddlewaresFor("compaction"),
|
|
2185
|
+
(args) =>
|
|
2186
|
+
defaultCompactionTerminal(
|
|
2187
|
+
args,
|
|
2188
|
+
buildPluginTurnContext(ctx, reqId),
|
|
2189
|
+
),
|
|
2190
|
+
{
|
|
2191
|
+
messages: ctx.messages,
|
|
2192
|
+
signal: abortController.signal,
|
|
2193
|
+
options: {
|
|
1828
2194
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1829
2195
|
force: true,
|
|
1830
2196
|
minKeepRecentUserTurns: 0,
|
|
1831
2197
|
targetInputTokensOverride: correctedTarget,
|
|
1832
2198
|
},
|
|
2199
|
+
},
|
|
2200
|
+
buildPluginTurnContext(ctx, reqId),
|
|
2201
|
+
DEFAULT_TIMEOUTS.compaction,
|
|
2202
|
+
)) as Awaited<
|
|
2203
|
+
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2204
|
+
>;
|
|
2205
|
+
} catch (err) {
|
|
2206
|
+
if (err instanceof PluginTimeoutError) {
|
|
2207
|
+
// Emergency compaction timed out. Record the circuit-breaker
|
|
2208
|
+
// failure and fall through to the graceful-error path below
|
|
2209
|
+
// (the unsuccessful-compaction fallback) rather than hard-
|
|
2210
|
+
// failing the turn.
|
|
2211
|
+
rlog.warn(
|
|
2212
|
+
{ err, phase: "emergency-compaction" },
|
|
2213
|
+
"Emergency compaction pipeline timed out — continuing with overflow fallback",
|
|
1833
2214
|
);
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
ctx,
|
|
1839
|
-
emergencyCompact.summaryFailed,
|
|
1840
|
-
onEvent,
|
|
1841
|
-
);
|
|
1842
|
-
}
|
|
1843
|
-
if (emergencyCompact.compacted) {
|
|
1844
|
-
ctx.messages = emergencyCompact.messages;
|
|
1845
|
-
reducerCompacted = true;
|
|
1846
|
-
ctx.contextCompactedMessageCount +=
|
|
1847
|
-
emergencyCompact.compactedPersistedMessages;
|
|
1848
|
-
ctx.contextCompactedAt = Date.now();
|
|
1849
|
-
updateConversationContextWindow(
|
|
1850
|
-
ctx.conversationId,
|
|
1851
|
-
emergencyCompact.summaryText,
|
|
1852
|
-
ctx.contextCompactedMessageCount,
|
|
1853
|
-
);
|
|
1854
|
-
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
1855
|
-
enqueueAutoAnalysisOnCompaction(
|
|
1856
|
-
ctx.conversationId,
|
|
1857
|
-
ctx.trustContext?.trustClass,
|
|
1858
|
-
);
|
|
1859
|
-
onEvent({
|
|
1860
|
-
type: "context_compacted",
|
|
1861
|
-
previousEstimatedInputTokens:
|
|
1862
|
-
emergencyCompact.previousEstimatedInputTokens,
|
|
1863
|
-
estimatedInputTokens: emergencyCompact.estimatedInputTokens,
|
|
1864
|
-
maxInputTokens: emergencyCompact.maxInputTokens,
|
|
1865
|
-
thresholdTokens: emergencyCompact.thresholdTokens,
|
|
1866
|
-
compactedMessages: emergencyCompact.compactedMessages,
|
|
1867
|
-
summaryCalls: emergencyCompact.summaryCalls,
|
|
1868
|
-
summaryInputTokens: emergencyCompact.summaryInputTokens,
|
|
1869
|
-
summaryOutputTokens: emergencyCompact.summaryOutputTokens,
|
|
1870
|
-
summaryModel: emergencyCompact.summaryModel,
|
|
1871
|
-
});
|
|
1872
|
-
emitUsage(
|
|
1873
|
-
ctx,
|
|
1874
|
-
emergencyCompact.summaryInputTokens,
|
|
1875
|
-
emergencyCompact.summaryOutputTokens,
|
|
1876
|
-
emergencyCompact.summaryModel,
|
|
1877
|
-
onEvent,
|
|
1878
|
-
"context_compactor",
|
|
1879
|
-
reqId,
|
|
1880
|
-
emergencyCompact.summaryCacheCreationInputTokens ?? 0,
|
|
1881
|
-
emergencyCompact.summaryCacheReadInputTokens ?? 0,
|
|
1882
|
-
collapseRawResponses(emergencyCompact.summaryRawResponses),
|
|
1883
|
-
);
|
|
1884
|
-
ctx.graphMemory.onCompacted(
|
|
1885
|
-
emergencyCompact.compactedPersistedMessages,
|
|
1886
|
-
);
|
|
1887
|
-
shouldInjectWorkspace = true;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
// Only re-inject NOW.md when ctx.messages was actually stripped;
|
|
1891
|
-
// otherwise the existing block is still present.
|
|
1892
|
-
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
1893
|
-
...injectionOpts,
|
|
1894
|
-
pkbContext: currentPkbContent,
|
|
1895
|
-
nowScratchpad: convergenceStripped ? currentNowContent : null,
|
|
1896
|
-
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1897
|
-
? ctx.workspaceTopLevelContext
|
|
1898
|
-
: null,
|
|
1899
|
-
slackChronologicalMessages: reducerCompacted
|
|
1900
|
-
? null
|
|
1901
|
-
: injectionOpts.slackChronologicalMessages,
|
|
1902
|
-
mode: currentInjectionMode,
|
|
1903
|
-
});
|
|
1904
|
-
runMessages = injection.messages;
|
|
1905
|
-
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
1906
|
-
ctx.graphMemory.retrackCachedNodes();
|
|
1907
|
-
}
|
|
1908
|
-
const emergencyStrip = stripHistoricalWebSearchResults(runMessages);
|
|
1909
|
-
if (emergencyStrip.stats.blocksStripped > 0) {
|
|
1910
|
-
rlog.info(
|
|
1911
|
-
{ phase: "emergency_compact", ...emergencyStrip.stats },
|
|
1912
|
-
"Converted historical web_search_tool_result blocks to text summaries",
|
|
1913
|
-
);
|
|
1914
|
-
runMessages = emergencyStrip.messages;
|
|
2215
|
+
await trackCompactionOutcome(ctx, true, onEvent);
|
|
2216
|
+
emergencyCompact = null;
|
|
2217
|
+
} else {
|
|
2218
|
+
throw err;
|
|
1915
2219
|
}
|
|
1916
|
-
preRepairMessages = runMessages;
|
|
1917
|
-
preRunHistoryLength = runMessages.length;
|
|
1918
|
-
state.contextTooLargeDetected = false;
|
|
1919
|
-
|
|
1920
|
-
updatedHistory = await ctx.agentLoop.run(
|
|
1921
|
-
runMessages,
|
|
1922
|
-
eventHandler,
|
|
1923
|
-
abortController.signal,
|
|
1924
|
-
reqId,
|
|
1925
|
-
onCheckpoint,
|
|
1926
|
-
turnCallSite,
|
|
1927
|
-
);
|
|
1928
|
-
} else {
|
|
1929
|
-
// User denied compression — emit a graceful assistant explanation
|
|
1930
|
-
// instead of a conversation_error, and end the turn cleanly.
|
|
1931
|
-
state.contextTooLargeDetected = false;
|
|
1932
|
-
const denyText =
|
|
1933
|
-
"The conversation has grown too long for the model to process, " +
|
|
1934
|
-
"and compression was declined. Please start a new conversation " +
|
|
1935
|
-
"or manually shorten the conversation to continue.";
|
|
1936
|
-
const loopChannelMeta = {
|
|
1937
|
-
...provenanceFromTrustContext(ctx.trustContext),
|
|
1938
|
-
userMessageChannel: capturedTurnChannelContext.userMessageChannel,
|
|
1939
|
-
assistantMessageChannel:
|
|
1940
|
-
capturedTurnChannelContext.assistantMessageChannel,
|
|
1941
|
-
userMessageInterface:
|
|
1942
|
-
capturedTurnInterfaceContext.userMessageInterface,
|
|
1943
|
-
assistantMessageInterface:
|
|
1944
|
-
capturedTurnInterfaceContext.assistantMessageInterface,
|
|
1945
|
-
};
|
|
1946
|
-
const denyMessage = createAssistantMessage(denyText);
|
|
1947
|
-
await addMessage(
|
|
1948
|
-
ctx.conversationId,
|
|
1949
|
-
"assistant",
|
|
1950
|
-
JSON.stringify(denyMessage.content),
|
|
1951
|
-
loopChannelMeta,
|
|
1952
|
-
);
|
|
1953
|
-
denyCompressionMessage = denyMessage;
|
|
1954
|
-
onEvent({
|
|
1955
|
-
type: "assistant_text_delta",
|
|
1956
|
-
text: denyText,
|
|
1957
|
-
conversationId: ctx.conversationId,
|
|
1958
|
-
});
|
|
1959
|
-
// Prevent the final error fallback from firing
|
|
1960
|
-
state.providerErrorUserMessage = null;
|
|
1961
2220
|
}
|
|
1962
|
-
} else if (action === "auto_compress_latest_turn") {
|
|
1963
|
-
// Non-interactive — auto-compress without asking
|
|
1964
|
-
ctx.emitActivityState(
|
|
1965
|
-
"thinking",
|
|
1966
|
-
"context_compacting",
|
|
1967
|
-
"assistant_turn",
|
|
1968
|
-
reqId,
|
|
1969
|
-
);
|
|
1970
|
-
const emergencyCompact = await ctx.contextWindowManager.maybeCompact(
|
|
1971
|
-
ctx.messages,
|
|
1972
|
-
abortController.signal,
|
|
1973
|
-
{
|
|
1974
|
-
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1975
|
-
force: true,
|
|
1976
|
-
minKeepRecentUserTurns: 0,
|
|
1977
|
-
targetInputTokensOverride: correctedTarget,
|
|
1978
|
-
},
|
|
1979
|
-
);
|
|
1980
2221
|
// Only track when the summary LLM actually ran; `force: true`
|
|
1981
2222
|
// bypasses the cooldown but not the early-return paths.
|
|
1982
|
-
if (
|
|
1983
|
-
|
|
2223
|
+
if (
|
|
2224
|
+
emergencyCompact &&
|
|
2225
|
+
emergencyCompact.summaryFailed !== undefined
|
|
2226
|
+
) {
|
|
2227
|
+
await trackCompactionOutcome(
|
|
1984
2228
|
ctx,
|
|
1985
2229
|
emergencyCompact.summaryFailed,
|
|
1986
2230
|
onEvent,
|
|
1987
2231
|
);
|
|
1988
2232
|
}
|
|
1989
|
-
if (emergencyCompact
|
|
1990
|
-
ctx
|
|
2233
|
+
if (emergencyCompact?.compacted) {
|
|
2234
|
+
applyCompactionResult(ctx, emergencyCompact, onEvent, reqId);
|
|
1991
2235
|
reducerCompacted = true;
|
|
1992
|
-
ctx.contextCompactedMessageCount +=
|
|
1993
|
-
emergencyCompact.compactedPersistedMessages;
|
|
1994
|
-
ctx.contextCompactedAt = Date.now();
|
|
1995
|
-
updateConversationContextWindow(
|
|
1996
|
-
ctx.conversationId,
|
|
1997
|
-
emergencyCompact.summaryText,
|
|
1998
|
-
ctx.contextCompactedMessageCount,
|
|
1999
|
-
);
|
|
2000
|
-
// Fire auto-analysis on compaction — see forceCompact() for rationale.
|
|
2001
|
-
enqueueAutoAnalysisOnCompaction(
|
|
2002
|
-
ctx.conversationId,
|
|
2003
|
-
ctx.trustContext?.trustClass,
|
|
2004
|
-
);
|
|
2005
|
-
onEvent({
|
|
2006
|
-
type: "context_compacted",
|
|
2007
|
-
previousEstimatedInputTokens:
|
|
2008
|
-
emergencyCompact.previousEstimatedInputTokens,
|
|
2009
|
-
estimatedInputTokens: emergencyCompact.estimatedInputTokens,
|
|
2010
|
-
maxInputTokens: emergencyCompact.maxInputTokens,
|
|
2011
|
-
thresholdTokens: emergencyCompact.thresholdTokens,
|
|
2012
|
-
compactedMessages: emergencyCompact.compactedMessages,
|
|
2013
|
-
summaryCalls: emergencyCompact.summaryCalls,
|
|
2014
|
-
summaryInputTokens: emergencyCompact.summaryInputTokens,
|
|
2015
|
-
summaryOutputTokens: emergencyCompact.summaryOutputTokens,
|
|
2016
|
-
summaryModel: emergencyCompact.summaryModel,
|
|
2017
|
-
});
|
|
2018
|
-
emitUsage(
|
|
2019
|
-
ctx,
|
|
2020
|
-
emergencyCompact.summaryInputTokens,
|
|
2021
|
-
emergencyCompact.summaryOutputTokens,
|
|
2022
|
-
emergencyCompact.summaryModel,
|
|
2023
|
-
onEvent,
|
|
2024
|
-
"context_compactor",
|
|
2025
|
-
reqId,
|
|
2026
|
-
emergencyCompact.summaryCacheCreationInputTokens ?? 0,
|
|
2027
|
-
emergencyCompact.summaryCacheReadInputTokens ?? 0,
|
|
2028
|
-
collapseRawResponses(emergencyCompact.summaryRawResponses),
|
|
2029
|
-
);
|
|
2030
|
-
ctx.graphMemory.onCompacted(
|
|
2031
|
-
emergencyCompact.compactedPersistedMessages,
|
|
2032
|
-
);
|
|
2033
2236
|
shouldInjectWorkspace = true;
|
|
2034
2237
|
}
|
|
2035
2238
|
|
|
@@ -2046,6 +2249,7 @@ export async function runAgentLoopImpl(
|
|
|
2046
2249
|
? null
|
|
2047
2250
|
: injectionOpts.slackChronologicalMessages,
|
|
2048
2251
|
mode: currentInjectionMode,
|
|
2252
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
2049
2253
|
});
|
|
2050
2254
|
runMessages = injection.messages;
|
|
2051
2255
|
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
@@ -2070,6 +2274,8 @@ export async function runAgentLoopImpl(
|
|
|
2070
2274
|
reqId,
|
|
2071
2275
|
onCheckpoint,
|
|
2072
2276
|
turnCallSite,
|
|
2277
|
+
loopTurnCtx,
|
|
2278
|
+
turnOverrideProfile,
|
|
2073
2279
|
);
|
|
2074
2280
|
}
|
|
2075
2281
|
// action === "fail_gracefully" falls through to the final error below
|
|
@@ -2134,11 +2340,19 @@ export async function runAgentLoopImpl(
|
|
|
2134
2340
|
assistantMessageInterface:
|
|
2135
2341
|
capturedTurnInterfaceContext.assistantMessageInterface,
|
|
2136
2342
|
};
|
|
2137
|
-
await
|
|
2138
|
-
|
|
2139
|
-
"
|
|
2140
|
-
|
|
2141
|
-
|
|
2343
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
2344
|
+
"persistence",
|
|
2345
|
+
getMiddlewaresFor("persistence"),
|
|
2346
|
+
defaultPersistenceTerminal,
|
|
2347
|
+
{
|
|
2348
|
+
op: "add",
|
|
2349
|
+
conversationId: ctx.conversationId,
|
|
2350
|
+
role: "user",
|
|
2351
|
+
content: JSON.stringify(toolResultBlocks),
|
|
2352
|
+
metadata: toolResultMetadata,
|
|
2353
|
+
},
|
|
2354
|
+
buildPluginTurnContext(ctx, reqId),
|
|
2355
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
2142
2356
|
);
|
|
2143
2357
|
state.pendingToolResults.clear();
|
|
2144
2358
|
}
|
|
@@ -2151,10 +2365,6 @@ export async function runAgentLoopImpl(
|
|
|
2151
2365
|
return { ...msg, content: cleanedBlocks };
|
|
2152
2366
|
});
|
|
2153
2367
|
|
|
2154
|
-
if (denyCompressionMessage) {
|
|
2155
|
-
newMessages.push(denyCompressionMessage);
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
2368
|
const hasAssistantResponse = newMessages.some(
|
|
2159
2369
|
(msg) => msg.role === "assistant",
|
|
2160
2370
|
);
|
|
@@ -2176,11 +2386,19 @@ export async function runAgentLoopImpl(
|
|
|
2176
2386
|
const errorAssistantMessage = createAssistantMessage(
|
|
2177
2387
|
state.providerErrorUserMessage,
|
|
2178
2388
|
);
|
|
2179
|
-
await
|
|
2180
|
-
|
|
2181
|
-
"
|
|
2182
|
-
|
|
2183
|
-
|
|
2389
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
2390
|
+
"persistence",
|
|
2391
|
+
getMiddlewaresFor("persistence"),
|
|
2392
|
+
defaultPersistenceTerminal,
|
|
2393
|
+
{
|
|
2394
|
+
op: "add",
|
|
2395
|
+
conversationId: ctx.conversationId,
|
|
2396
|
+
role: "assistant",
|
|
2397
|
+
content: JSON.stringify(errorAssistantMessage.content),
|
|
2398
|
+
metadata: errChannelMeta,
|
|
2399
|
+
},
|
|
2400
|
+
buildPluginTurnContext(ctx, reqId),
|
|
2401
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
2184
2402
|
);
|
|
2185
2403
|
newMessages.push(errorAssistantMessage);
|
|
2186
2404
|
// Do NOT send assistant_text_delta here — handleProviderError already
|
|
@@ -2248,10 +2466,6 @@ export async function runAgentLoopImpl(
|
|
|
2248
2466
|
},
|
|
2249
2467
|
);
|
|
2250
2468
|
|
|
2251
|
-
void getHookManager().trigger("post-message", {
|
|
2252
|
-
conversationId: ctx.conversationId,
|
|
2253
|
-
});
|
|
2254
|
-
|
|
2255
2469
|
const syncLastAssistantMessageToDisk = (): void => {
|
|
2256
2470
|
if (!state.lastAssistantMessageId) return;
|
|
2257
2471
|
const convForDisk = getConversation(ctx.conversationId);
|
|
@@ -2368,13 +2582,92 @@ export async function runAgentLoopImpl(
|
|
|
2368
2582
|
? { messageId: state.lastAssistantMessageId }
|
|
2369
2583
|
: {}),
|
|
2370
2584
|
});
|
|
2585
|
+
|
|
2586
|
+
// Emit a home-feed event for background/scheduled conversation completions.
|
|
2587
|
+
// Scoped to message_complete only (not cancelled/handoff), wrapped in
|
|
2588
|
+
// try-catch so malformed message content can never propagate errors.
|
|
2589
|
+
try {
|
|
2590
|
+
const conv = getConversation(ctx.conversationId);
|
|
2591
|
+
if (
|
|
2592
|
+
conv &&
|
|
2593
|
+
(conv.conversationType === "background" ||
|
|
2594
|
+
conv.conversationType === "scheduled")
|
|
2595
|
+
) {
|
|
2596
|
+
const lastMsg = state.lastAssistantMessageId
|
|
2597
|
+
? getMessageById(state.lastAssistantMessageId, ctx.conversationId)
|
|
2598
|
+
: undefined;
|
|
2599
|
+
let summary: string;
|
|
2600
|
+
if (lastMsg) {
|
|
2601
|
+
const parsed: unknown = JSON.parse(lastMsg.content);
|
|
2602
|
+
if (typeof parsed === "string") {
|
|
2603
|
+
summary = parsed.slice(0, 200);
|
|
2604
|
+
} else if (Array.isArray(parsed)) {
|
|
2605
|
+
const textBlock = parsed.find(
|
|
2606
|
+
(b: { type?: string }) => b.type === "text",
|
|
2607
|
+
);
|
|
2608
|
+
summary =
|
|
2609
|
+
typeof textBlock?.text === "string"
|
|
2610
|
+
? textBlock.text.slice(0, 200)
|
|
2611
|
+
: (conv.title ?? "Background task completed.");
|
|
2612
|
+
} else {
|
|
2613
|
+
summary = conv.title ?? "Background task completed.";
|
|
2614
|
+
}
|
|
2615
|
+
} else {
|
|
2616
|
+
summary = conv.title ?? "Background task completed.";
|
|
2617
|
+
}
|
|
2618
|
+
const feedTitle =
|
|
2619
|
+
conv.title && !isReplaceableTitle(conv.title)
|
|
2620
|
+
? conv.title
|
|
2621
|
+
: "Background task";
|
|
2622
|
+
const dedupKey = `bg-conv:${ctx.conversationId}`;
|
|
2623
|
+
void emitFeedEvent({
|
|
2624
|
+
source: "assistant",
|
|
2625
|
+
title: feedTitle,
|
|
2626
|
+
summary,
|
|
2627
|
+
dedupKey,
|
|
2628
|
+
conversationId: ctx.conversationId,
|
|
2629
|
+
}).catch((err) => {
|
|
2630
|
+
log.warn(
|
|
2631
|
+
{ err, conversationId: ctx.conversationId },
|
|
2632
|
+
"Failed to emit background conversation feed event",
|
|
2633
|
+
);
|
|
2634
|
+
});
|
|
2635
|
+
|
|
2636
|
+
if (isReplaceableTitle(conv.title ?? null)) {
|
|
2637
|
+
void rewriteFeedTitle(feedTitle)
|
|
2638
|
+
.then((prose) => {
|
|
2639
|
+
if (prose && prose !== feedTitle) {
|
|
2640
|
+
return emitFeedEvent({
|
|
2641
|
+
source: "assistant",
|
|
2642
|
+
title: prose,
|
|
2643
|
+
summary,
|
|
2644
|
+
dedupKey,
|
|
2645
|
+
conversationId: ctx.conversationId,
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
})
|
|
2649
|
+
.catch((err) => {
|
|
2650
|
+
log.warn(
|
|
2651
|
+
{ err, conversationId: ctx.conversationId },
|
|
2652
|
+
"Failed to update feed event with prose title rewrite",
|
|
2653
|
+
);
|
|
2654
|
+
});
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
} catch (feedErr) {
|
|
2658
|
+
log.warn(
|
|
2659
|
+
{ err: feedErr, conversationId: ctx.conversationId },
|
|
2660
|
+
"Failed to build home-feed event for background conversation",
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2371
2663
|
}
|
|
2372
2664
|
}
|
|
2373
2665
|
|
|
2374
2666
|
// Second title pass: after 3 completed turns, re-generate the title
|
|
2375
2667
|
// using the last 3 messages for better context. Only fires when the
|
|
2376
|
-
// current title was auto-generated (isAutoTitle = 1)
|
|
2377
|
-
|
|
2668
|
+
// current title was auto-generated (isAutoTitle = 1) and the user
|
|
2669
|
+
// has not opted out via `conversations.skipAutoRetitling`.
|
|
2670
|
+
if (ctx.turnCount === 2 && !getConfig().conversations.skipAutoRetitling) {
|
|
2378
2671
|
// turnCount is 0-indexed, incremented in finally; 2 = about to become 3rd turn
|
|
2379
2672
|
queueRegenerateConversationTitle({
|
|
2380
2673
|
conversationId: ctx.conversationId,
|
|
@@ -2427,12 +2720,6 @@ export async function runAgentLoopImpl(
|
|
|
2427
2720
|
});
|
|
2428
2721
|
onEvent({ type: "error", message: classified.userMessage });
|
|
2429
2722
|
onEvent(buildConversationErrorMessage(ctx.conversationId, classified));
|
|
2430
|
-
void getHookManager().trigger("on-error", {
|
|
2431
|
-
error: err instanceof Error ? err.name : "Error",
|
|
2432
|
-
message,
|
|
2433
|
-
stack: err instanceof Error ? err.stack : undefined,
|
|
2434
|
-
conversationId: ctx.conversationId,
|
|
2435
|
-
});
|
|
2436
2723
|
}
|
|
2437
2724
|
} finally {
|
|
2438
2725
|
if (turnStarted) {
|
|
@@ -2481,6 +2768,7 @@ export async function runAgentLoopImpl(
|
|
|
2481
2768
|
ctx.currentActiveSurfaceId = undefined;
|
|
2482
2769
|
ctx.allowedToolNames = undefined;
|
|
2483
2770
|
ctx.preactivatedSkillIds = undefined;
|
|
2771
|
+
ctx.currentTurnOverrideProfile = undefined;
|
|
2484
2772
|
// Channel command intents (e.g. Telegram /start) are single-turn metadata.
|
|
2485
2773
|
// Clear at turn end so they never leak into subsequent unrelated messages.
|
|
2486
2774
|
ctx.commandIntent = undefined;
|
|
@@ -2542,7 +2830,131 @@ function emitUsage(
|
|
|
2542
2830
|
);
|
|
2543
2831
|
}
|
|
2544
2832
|
|
|
2833
|
+
/**
|
|
2834
|
+
* Minimal context shape consumed by `applyCompactionResult`. Both
|
|
2835
|
+
* `AgentLoopConversationContext` and `Conversation` satisfy this via structural
|
|
2836
|
+
* typing, so the helper can back both the 5 agent-loop auto-compaction sites
|
|
2837
|
+
* and the single `forceCompact` user-initiated site.
|
|
2838
|
+
*/
|
|
2839
|
+
export interface CompactionApplyContext {
|
|
2840
|
+
readonly conversationId: string;
|
|
2841
|
+
messages: Message[];
|
|
2842
|
+
contextCompactedMessageCount: number;
|
|
2843
|
+
contextCompactedAt: number | null;
|
|
2844
|
+
readonly graphMemory: ConversationGraphMemory;
|
|
2845
|
+
readonly provider: Provider;
|
|
2846
|
+
usageStats: UsageStats;
|
|
2847
|
+
trustContext?: TrustContext;
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
/**
|
|
2851
|
+
* Applies a successful `ContextWindowResult` to a conversation: updates the
|
|
2852
|
+
* in-memory message buffer and compaction counters, notifies the graph memory
|
|
2853
|
+
* and conversation-summary store, enqueues auto-analysis, emits the
|
|
2854
|
+
* `context_compacted` event, and records a `context_compactor` usage event.
|
|
2855
|
+
*
|
|
2856
|
+
* The emitted `usage_update` intentionally omits `contextWindow` — the
|
|
2857
|
+
* `context_compacted` event already carries the fresh
|
|
2858
|
+
* `estimatedInputTokens` / `maxInputTokens` and is the single source of
|
|
2859
|
+
* truth for the UI indicator after compaction. Emitting both caused a
|
|
2860
|
+
* redundant SwiftUI invalidation on every compaction.
|
|
2861
|
+
*/
|
|
2862
|
+
export function applyCompactionResult(
|
|
2863
|
+
ctx: CompactionApplyContext,
|
|
2864
|
+
result: {
|
|
2865
|
+
messages: Message[];
|
|
2866
|
+
compactedPersistedMessages: number;
|
|
2867
|
+
previousEstimatedInputTokens: number;
|
|
2868
|
+
estimatedInputTokens: number;
|
|
2869
|
+
maxInputTokens: number;
|
|
2870
|
+
thresholdTokens: number;
|
|
2871
|
+
compactedMessages: number;
|
|
2872
|
+
summaryCalls: number;
|
|
2873
|
+
summaryInputTokens: number;
|
|
2874
|
+
summaryOutputTokens: number;
|
|
2875
|
+
summaryModel: string;
|
|
2876
|
+
summaryText: string;
|
|
2877
|
+
summaryCacheCreationInputTokens?: number;
|
|
2878
|
+
summaryCacheReadInputTokens?: number;
|
|
2879
|
+
summaryRawResponses?: unknown[];
|
|
2880
|
+
},
|
|
2881
|
+
onEvent: (msg: ServerMessage) => void,
|
|
2882
|
+
reqId: string | null,
|
|
2883
|
+
): void {
|
|
2884
|
+
ctx.messages = result.messages;
|
|
2885
|
+
ctx.contextCompactedMessageCount += result.compactedPersistedMessages;
|
|
2886
|
+
ctx.contextCompactedAt = Date.now();
|
|
2887
|
+
ctx.graphMemory.onCompacted(result.compactedPersistedMessages);
|
|
2888
|
+
updateConversationContextWindow(
|
|
2889
|
+
ctx.conversationId,
|
|
2890
|
+
result.summaryText,
|
|
2891
|
+
ctx.contextCompactedMessageCount,
|
|
2892
|
+
);
|
|
2893
|
+
enqueueAutoAnalysisOnCompaction(
|
|
2894
|
+
ctx.conversationId,
|
|
2895
|
+
ctx.trustContext?.trustClass,
|
|
2896
|
+
);
|
|
2897
|
+
const summarySignals = computeSummaryQualitySignals(result.summaryText);
|
|
2898
|
+
onEvent({
|
|
2899
|
+
type: "context_compacted",
|
|
2900
|
+
conversationId: ctx.conversationId,
|
|
2901
|
+
previousEstimatedInputTokens: result.previousEstimatedInputTokens,
|
|
2902
|
+
estimatedInputTokens: result.estimatedInputTokens,
|
|
2903
|
+
maxInputTokens: result.maxInputTokens,
|
|
2904
|
+
thresholdTokens: result.thresholdTokens,
|
|
2905
|
+
compactedMessages: result.compactedMessages,
|
|
2906
|
+
summaryCalls: result.summaryCalls,
|
|
2907
|
+
summaryInputTokens: result.summaryInputTokens,
|
|
2908
|
+
summaryOutputTokens: result.summaryOutputTokens,
|
|
2909
|
+
summaryModel: result.summaryModel,
|
|
2910
|
+
summaryCharCount: summarySignals.charCount,
|
|
2911
|
+
summaryHeaderCount: summarySignals.headerCount,
|
|
2912
|
+
summaryHadMemoryEcho: summarySignals.hadMemoryEcho,
|
|
2913
|
+
});
|
|
2914
|
+
emitUsage(
|
|
2915
|
+
ctx,
|
|
2916
|
+
result.summaryInputTokens,
|
|
2917
|
+
result.summaryOutputTokens,
|
|
2918
|
+
result.summaryModel,
|
|
2919
|
+
onEvent,
|
|
2920
|
+
"context_compactor",
|
|
2921
|
+
reqId,
|
|
2922
|
+
result.summaryCacheCreationInputTokens ?? 0,
|
|
2923
|
+
result.summaryCacheReadInputTokens ?? 0,
|
|
2924
|
+
collapseRawResponses(result.summaryRawResponses),
|
|
2925
|
+
undefined /* providerName */,
|
|
2926
|
+
1 /* llmCallCount */,
|
|
2927
|
+
);
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2545
2930
|
function collapseRawResponses(rawResponses?: unknown[]): unknown | undefined {
|
|
2546
2931
|
if (!rawResponses || rawResponses.length === 0) return undefined;
|
|
2547
2932
|
return rawResponses.length === 1 ? rawResponses[0] : rawResponses;
|
|
2548
2933
|
}
|
|
2934
|
+
|
|
2935
|
+
/**
|
|
2936
|
+
* Matches any runtime-injection tag that should never appear inside a
|
|
2937
|
+
* generated summary. If the regex hits, either the compaction strip logic
|
|
2938
|
+
* failed to drop an injected block from the summarizer input, or the
|
|
2939
|
+
* summarizer invented tag-like text on its own — both are quality bugs
|
|
2940
|
+
* worth surfacing via telemetry.
|
|
2941
|
+
*/
|
|
2942
|
+
const SUMMARY_MEMORY_ECHO_PATTERN =
|
|
2943
|
+
/<(?:memory|memory_context|memory_image|turn_context|workspace|workspace_top_level|knowledge_base|pkb|system_reminder|now_scratchpad|NOW\.md|active_thread|active_subagents|active_workspace|active_dynamic_page|channel_capabilities|transport_hints|system_notice|non_interactive_context|temporal_context|guardian_context|inbound_actor_context|channel_turn_context|interface_turn_context|channel_command_context|voice_call_control)\b/i;
|
|
2944
|
+
|
|
2945
|
+
/**
|
|
2946
|
+
* Compute light-weight quality signals for a compaction summary. Emitted
|
|
2947
|
+
* on every `context_compacted` event so regressions (short outputs,
|
|
2948
|
+
* header collapse, memory-injection leakage) are visible without having
|
|
2949
|
+
* to read the summary text from the DB.
|
|
2950
|
+
*/
|
|
2951
|
+
export function computeSummaryQualitySignals(summaryText: string): {
|
|
2952
|
+
charCount: number;
|
|
2953
|
+
headerCount: number;
|
|
2954
|
+
hadMemoryEcho: boolean;
|
|
2955
|
+
} {
|
|
2956
|
+
const charCount = summaryText.length;
|
|
2957
|
+
const headerCount = (summaryText.match(/^## /gm) ?? []).length;
|
|
2958
|
+
const hadMemoryEcho = SUMMARY_MEMORY_ECHO_PATTERN.test(summaryText);
|
|
2959
|
+
return { charCount, headerCount, hadMemoryEcho };
|
|
2960
|
+
}
|