@vellumai/assistant 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -4
- package/Dockerfile +1 -0
- package/bun.lock +11 -2
- package/docker-entrypoint.sh +8 -6
- package/docs/plugins.md +63 -28
- package/examples/plugins/echo/register.ts +4 -7
- package/knip.json +1 -0
- package/node_modules/@vellumai/environments/bun.lock +24 -0
- package/node_modules/@vellumai/environments/package.json +18 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
- package/node_modules/@vellumai/environments/src/index.ts +11 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
- package/node_modules/@vellumai/environments/src/types.ts +70 -0
- package/node_modules/@vellumai/environments/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +3 -4
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -2
- package/openapi.yaml +3735 -353
- package/package.json +7 -3
- package/scripts/generate-openapi.ts +20 -13
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
- package/src/__tests__/agent-loop-exit-reason.test.ts +240 -39
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +19 -32
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +6 -4
- package/src/__tests__/agent-loop-thinking.test.ts +17 -12
- package/src/__tests__/agent-loop.test.ts +207 -341
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +4 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +22 -40
- package/src/__tests__/anthropic-provider.test.ts +201 -55
- package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
- package/src/__tests__/app-control-flow.test.ts +5 -0
- package/src/__tests__/approval-cascade.test.ts +4 -11
- package/src/__tests__/approval-routes-http.test.ts +4 -2
- package/src/__tests__/assistant-event.test.ts +15 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +7 -37
- package/src/__tests__/avatar-generator.test.ts +12 -42
- package/src/__tests__/avatar-identity-sync.test.ts +28 -3
- package/src/__tests__/background-shell-bash.test.ts +3 -7
- package/src/__tests__/btw-routes.test.ts +7 -12
- package/src/__tests__/call-pointer-messages.test.ts +5 -3
- package/src/__tests__/call-site-routing-provider.test.ts +22 -40
- package/src/__tests__/catalog-files.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +48 -20
- package/src/__tests__/channel-approvals.test.ts +3 -1
- package/src/__tests__/channel-invite-transport.test.ts +1 -5
- package/src/__tests__/channel-readiness-routes.test.ts +0 -4
- package/src/__tests__/channel-readiness-slack-remote.test.ts +2 -7
- package/src/__tests__/channel-retry-sweep.test.ts +71 -79
- package/src/__tests__/circuit-breaker-pipeline.test.ts +3 -3
- package/src/__tests__/clawhub-files.test.ts +1 -0
- package/src/__tests__/compaction-events.test.ts +5 -17
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction-timeout-recovery.test.ts +37 -48
- package/src/__tests__/compaction-trail-store.test.ts +1 -79
- package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
- package/src/__tests__/computer-use-tools.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +28 -0
- package/src/__tests__/context-search-agent-runner.test.ts +6 -3
- package/src/__tests__/context-token-estimator.test.ts +34 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +14 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +12 -27
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +430 -90
- package/src/__tests__/conversation-agent-loop.test.ts +581 -62
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clear-safety.test.ts +20 -10
- package/src/__tests__/conversation-confirmation-signals.test.ts +15 -45
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +10 -17
- package/src/__tests__/conversation-fork-crud.test.ts +86 -172
- package/src/__tests__/conversation-fork-route.test.ts +16 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
- package/src/__tests__/conversation-lifecycle.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +3 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -1
- package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
- package/src/__tests__/conversation-pairing.test.ts +34 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -0
- package/src/__tests__/conversation-process-callsite.test.ts +27 -30
- package/src/__tests__/conversation-provider-retry-repair.test.ts +53 -44
- package/src/__tests__/conversation-queue.test.ts +270 -164
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +20 -22
- package/src/__tests__/conversation-runtime-workspace.test.ts +19 -1
- package/src/__tests__/conversation-slash-queue.test.ts +37 -31
- package/src/__tests__/conversation-slash-unknown.test.ts +13 -15
- package/src/__tests__/conversation-speed-override.test.ts +8 -22
- package/src/__tests__/conversation-stream-state.test.ts +484 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +6 -15
- package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
- package/src/__tests__/conversation-surfaces-state-update.test.ts +5 -2
- package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -15
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +23 -11
- package/src/__tests__/conversation-unread-route.test.ts +14 -2
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-wipe.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +3 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +48 -22
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +27 -7
- package/src/__tests__/credential-execution-tools.test.ts +1 -2
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/cross-provider-web-search.test.ts +6 -2
- package/src/__tests__/cu-unified-flow.test.ts +26 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +11 -0
- package/src/__tests__/disk-pressure-guard.test.ts +66 -0
- package/src/__tests__/disk-pressure-routes.test.ts +9 -2
- package/src/__tests__/dm-persistence.test.ts +7 -2
- package/src/__tests__/dynamic-page-surface.test.ts +68 -0
- package/src/__tests__/edit-propagation.test.ts +1 -2
- package/src/__tests__/empty-response-pipeline.test.ts +127 -5
- package/src/__tests__/filing-service.test.ts +2 -2
- package/src/__tests__/first-greeting.test.ts +55 -14
- package/src/__tests__/gemini-inline-media.test.ts +78 -0
- package/src/__tests__/gemini-provider.test.ts +351 -28
- package/src/__tests__/guardian-routing-state.test.ts +60 -71
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +9 -7
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -1
- package/src/__tests__/history-repair-hook.test.ts +161 -0
- package/src/__tests__/history-repair-observability.test.ts +1 -1
- package/src/__tests__/history-repair.test.ts +2 -1
- package/src/__tests__/host-app-control-proxy.test.ts +2 -0
- package/src/__tests__/host-cu-proxy.test.ts +2 -0
- package/src/__tests__/host-file-edit-tool.test.ts +4 -2
- package/src/__tests__/host-file-proxy.test.ts +31 -0
- package/src/__tests__/host-file-read-tool.test.ts +4 -2
- package/src/__tests__/host-file-write-tool.test.ts +9 -3
- package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
- package/src/__tests__/host-shell-tool.test.ts +9 -4
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +35 -14
- package/src/__tests__/inbound-slack-persistence.test.ts +7 -2
- package/src/__tests__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +1 -1
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
- package/src/__tests__/injector-v3-suppression.test.ts +220 -0
- package/src/__tests__/list-messages-attachments.test.ts +7 -8
- package/src/__tests__/list-messages-hidden-metadata.test.ts +17 -15
- package/src/__tests__/list-messages-page-latest.test.ts +0 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +36 -6
- package/src/__tests__/llm-call-pipeline.test.ts +21 -15
- package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
- package/src/__tests__/llm-resolver.test.ts +23 -47
- package/src/__tests__/llm-usage-store.test.ts +45 -0
- package/src/__tests__/log-export-routes.test.ts +59 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
- package/src/__tests__/mcp-auth-routes.test.ts +15 -10
- package/src/__tests__/mcp-health-check.test.ts +18 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +1 -1
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +8 -4
- package/src/__tests__/migration-export-http.test.ts +12 -12
- package/src/__tests__/migration-import-commit-http.test.ts +8 -8
- package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +14 -20
- package/src/__tests__/notification-decision-identity.test.ts +9 -18
- package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
- package/src/__tests__/oauth-commands-routes.test.ts +1 -1
- package/src/__tests__/onboarding-template-contract.test.ts +10 -0
- package/src/__tests__/openai-provider.test.ts +66 -70
- package/src/__tests__/openai-responses-provider.test.ts +21 -77
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -1
- package/src/__tests__/overflow-reduce-pipeline.test.ts +2 -4
- package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
- package/src/__tests__/persistence-pipeline.test.ts +15 -26
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -1
- package/src/__tests__/pipeline-runner.test.ts +2 -3
- package/src/__tests__/plugin-bootstrap.test.ts +51 -25
- package/src/__tests__/plugin-route-contribution.test.ts +6 -16
- package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +10 -26
- package/src/__tests__/plugin-types.test.ts +7 -14
- package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
- package/src/__tests__/process-message-background-slack.test.ts +17 -16
- package/src/__tests__/process-message-display-content.test.ts +30 -42
- package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
- package/src/__tests__/provider-error-scenarios.test.ts +7 -6
- package/src/__tests__/provider-platform-proxy-integration.test.ts +3 -8
- package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
- package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
- package/src/__tests__/provider-usage-tracking.test.ts +0 -6
- package/src/__tests__/ratelimit.test.ts +9 -4
- package/src/__tests__/relay-server.test.ts +20 -13
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
- package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
- package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +353 -0
- package/src/__tests__/schedule-routes.test.ts +80 -10
- package/src/__tests__/schedule-store.test.ts +67 -0
- package/src/__tests__/schedule-tools.test.ts +125 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
- package/src/__tests__/secret-response-routing.test.ts +13 -11
- package/src/__tests__/send-endpoint-busy.test.ts +2 -1
- package/src/__tests__/shell-observability.test.ts +249 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +11 -11
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +10 -10
- package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
- package/src/__tests__/skillssh-files.test.ts +1 -0
- package/src/__tests__/starter-task-flow.test.ts +6 -6
- package/src/__tests__/strip-memory-injections.test.ts +102 -14
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +19 -16
- package/src/__tests__/system-prompt.test.ts +54 -0
- package/src/__tests__/terminal-tools.test.ts +3 -24
- package/src/__tests__/thread-backfill.test.ts +4 -9
- package/src/__tests__/title-generate-pipeline.test.ts +1 -1
- package/src/__tests__/token-estimate-pipeline.test.ts +2 -4
- package/src/__tests__/tool-error-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execute-pipeline.test.ts +1 -1
- package/src/__tests__/tool-preview-lifecycle.test.ts +13 -11
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +9 -12
- package/src/__tests__/tool-result-truncation.test.ts +3 -1
- package/src/__tests__/tools-audio-read.test.ts +113 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
- package/src/__tests__/turn-events-store.test.ts +11 -7
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +8 -6
- package/src/__tests__/voice-session-bridge.test.ts +13 -7
- package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
- package/src/acp/prepare-agent-env.ts +52 -11
- package/src/agent/compaction-circuit.ts +140 -0
- package/src/agent/loop.ts +409 -85
- package/src/api/README.md +19 -17
- package/src/api/constants/tool-execution.ts +21 -0
- package/src/api/events/assistant-activity-state.ts +75 -0
- package/src/api/events/assistant-outbound-attachment.ts +25 -27
- package/src/api/events/assistant-text-delta.ts +6 -8
- package/src/api/events/assistant-turn-start.ts +5 -7
- package/src/api/events/avatar-updated.ts +24 -0
- package/src/api/events/compaction-circuit-closed.ts +26 -0
- package/src/api/events/compaction-circuit-open.ts +28 -0
- package/src/api/events/confirmation-request.ts +114 -0
- package/src/api/events/contact-request.ts +33 -0
- package/src/api/events/conversation-error.ts +77 -0
- package/src/api/events/conversation-list-invalidated.ts +38 -0
- package/src/api/events/conversation-title-updated.ts +24 -0
- package/src/api/events/disk-pressure-status-changed.ts +61 -0
- package/src/api/events/document-comment-created.ts +24 -28
- package/src/api/events/document-comment-deleted.ts +6 -8
- package/src/api/events/document-comment-reopened.ts +6 -8
- package/src/api/events/document-comment-resolved.ts +8 -10
- package/src/api/events/document-editor-update.ts +27 -0
- package/src/api/events/error.ts +32 -0
- package/src/api/events/generation-cancelled.ts +4 -6
- package/src/api/events/generation-handoff.ts +13 -15
- package/src/api/events/home-feed-updated.ts +26 -0
- package/src/api/events/identity-changed.ts +32 -0
- package/src/api/events/interaction-resolved.ts +50 -0
- package/src/api/events/message-complete.ts +10 -12
- package/src/api/events/message-dequeued.ts +21 -0
- package/src/api/events/message-queued-deleted.ts +23 -0
- package/src/api/events/message-queued.ts +22 -0
- package/src/api/events/message-request-complete.ts +29 -0
- package/src/api/events/navigate-settings.ts +20 -0
- package/src/api/events/notification-intent.ts +33 -0
- package/src/api/events/open-url.ts +6 -8
- package/src/api/events/question-request.ts +67 -0
- package/src/api/events/relationship-state-updated.ts +4 -6
- package/src/api/events/secret-request.ts +42 -0
- package/src/api/events/subagent-event.ts +79 -0
- package/src/api/events/subagent-spawned.ts +40 -0
- package/src/api/events/subagent-status-changed.ts +65 -0
- package/src/api/events/sync-changed.ts +29 -0
- package/src/api/events/tool-result.ts +129 -0
- package/src/api/events/tool-use-start.ts +8 -10
- package/src/api/events/turn-profile-auto-routed.ts +28 -0
- package/src/api/events/ui-surface-complete.ts +30 -0
- package/src/api/events/ui-surface-dismiss.ts +22 -0
- package/src/api/events/ui-surface-show.ts +67 -0
- package/src/api/events/ui-surface-update.ts +26 -0
- package/src/api/events/usage-update.ts +34 -0
- package/src/api/events/user-message-echo.ts +35 -0
- package/src/api/index.ts +354 -0
- package/src/api/requests/dictation.ts +45 -0
- package/src/api/responses/disk-pressure-status.ts +26 -0
- package/src/api/responses/home.ts +217 -0
- package/src/api/responses/llm-context-response.ts +2 -0
- package/src/api/responses/memory-v3-selection-log.ts +50 -0
- package/src/api/responses/subagent-detail.ts +48 -0
- package/src/approvals/guardian-decision-primitive.ts +7 -15
- package/src/approvals/guardian-request-resolvers.ts +6 -9
- package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
- package/src/avatar/__tests__/avatar-store.test.ts +193 -0
- package/src/avatar/avatar-manifest.ts +195 -0
- package/src/avatar/avatar-store.ts +113 -0
- package/src/avatar/traits-png-sync.ts +8 -2
- package/src/background-wake/next-wake.test.ts +31 -1
- package/src/background-wake/next-wake.ts +4 -1
- package/src/calls/call-conversation-messages.ts +6 -4
- package/src/calls/guardian-action-sweep.ts +6 -4
- package/src/calls/relay-server.ts +12 -8
- package/src/calls/voice-session-bridge.ts +13 -27
- package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
- package/src/cli/commands/avatar.ts +17 -11
- package/src/cli/commands/conversations.ts +15 -1
- package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
- package/src/cli/commands/db/__tests__/status.test.ts +253 -0
- package/src/cli/commands/db/format.ts +48 -0
- package/src/cli/commands/db/index.ts +29 -0
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
- package/src/cli/commands/db/repair-step-integrity.ts +146 -0
- package/src/cli/commands/db/repair-steps.ts +164 -0
- package/src/cli/commands/db/repair.ts +141 -0
- package/src/cli/commands/db/status.ts +366 -0
- package/src/cli/commands/memory-v3.ts +159 -445
- package/src/cli/lib/cli-colors.ts +24 -6
- package/src/cli/program.ts +4 -5
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/assistant-feature-flags.ts +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -3
- package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/call-site-defaults.ts +2 -7
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -226
- package/src/config/schemas/call-site-catalog.ts +8 -15
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/memory-lifecycle.ts +24 -0
- package/src/config/schemas/memory-v2.ts +0 -253
- package/src/config/schemas/memory-v3.ts +39 -0
- package/src/config/schemas/memory.ts +6 -1
- package/src/config/schemas/timeouts.ts +3 -1
- package/src/context/compactor.ts +54 -31
- package/src/context/token-estimator.ts +19 -0
- package/src/context/tool-result-truncation.ts +1 -43
- package/src/context/window-manager.ts +138 -20
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +2 -2
- package/src/daemon/__tests__/web-search-status-text.test.ts +10 -6
- package/src/daemon/approval-generators.ts +4 -4
- package/src/daemon/config-watcher.ts +7 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +225 -88
- package/src/daemon/conversation-agent-loop.ts +284 -584
- package/src/daemon/conversation-error.ts +7 -7
- package/src/daemon/conversation-history.ts +22 -6
- package/src/daemon/conversation-launch.ts +4 -8
- package/src/daemon/conversation-lifecycle.ts +10 -38
- package/src/daemon/conversation-messaging.ts +1 -3
- package/src/daemon/conversation-notifiers.ts +7 -5
- package/src/daemon/conversation-process.ts +100 -79
- package/src/daemon/conversation-runtime-assembly.ts +47 -21
- package/src/daemon/conversation-store.ts +6 -5
- package/src/daemon/conversation-surfaces.ts +55 -69
- package/src/daemon/conversation-tool-setup.ts +3 -0
- package/src/daemon/conversation.ts +91 -126
- package/src/daemon/daemon-skill-host.ts +2 -6
- package/src/daemon/disk-pressure-guard.ts +35 -29
- package/src/daemon/external-plugins-bootstrap.ts +46 -24
- package/src/daemon/first-greeting.ts +26 -4
- package/src/daemon/guardian-action-generators.ts +2 -2
- package/src/daemon/handlers/conversations.ts +6 -22
- package/src/daemon/handlers/shared.ts +4 -0
- package/src/daemon/handlers/skills.ts +15 -14
- package/src/daemon/host-app-control-proxy.ts +54 -1
- package/src/daemon/host-cu-proxy.ts +46 -22
- package/src/daemon/host-file-proxy.ts +25 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -6
- package/src/daemon/lifecycle.ts +28 -55
- package/src/daemon/message-protocol.ts +2 -3
- package/src/daemon/message-provenance.ts +49 -0
- package/src/daemon/message-types/contacts.ts +3 -20
- package/src/daemon/message-types/conversations.ts +13 -111
- package/src/daemon/message-types/documents.ts +3 -9
- package/src/daemon/message-types/home.ts +4 -17
- package/src/daemon/message-types/integrations.ts +2 -6
- package/src/daemon/message-types/messages.ts +28 -343
- package/src/daemon/message-types/notifications.ts +2 -32
- package/src/daemon/message-types/settings.ts +3 -8
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/sync.ts +12 -25
- package/src/daemon/message-types/workspace.ts +3 -11
- package/src/daemon/process-message.ts +49 -46
- package/src/daemon/server.ts +12 -0
- package/src/daemon/tool-side-effects.ts +10 -7
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +11 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -1
- package/src/heartbeat/heartbeat-run-store.ts +31 -0
- package/src/heartbeat/heartbeat-service.ts +16 -0
- package/src/home/feature-gate.ts +22 -0
- package/src/home/feed-types.ts +36 -221
- package/src/ipc/__tests__/email-ipc.test.ts +0 -9
- package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
- package/src/ipc/routes/route-adapter.ts +45 -6
- package/src/ipc/skill-routes/__tests__/memory.test.ts +18 -9
- package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
- package/src/ipc/skill-routes/__tests__/registries.test.ts +28 -18
- package/src/ipc/skill-routes/memory.ts +26 -13
- package/src/ipc/skill-routes/providers.ts +5 -6
- package/src/ipc/skill-routes/registries.ts +13 -61
- package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
- package/src/memory/__tests__/conversation-queries.test.ts +192 -8
- package/src/memory/__tests__/db-maintenance.test.ts +128 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
- package/src/memory/__tests__/memory-retrospective-job.test.ts +10 -6
- package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
- package/src/memory/context-search/agent-runner.ts +2 -4
- package/src/memory/conversation-crud.ts +39 -8
- package/src/memory/conversation-queries.ts +78 -22
- package/src/memory/db-init.ts +8 -0
- package/src/memory/db-maintenance.ts +18 -2
- package/src/memory/graph/consolidation.ts +8 -11
- package/src/memory/graph/conversation-graph-memory.ts +41 -8
- package/src/memory/graph/extraction.ts +6 -9
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.ts +20 -26
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/job-handlers/conversation-starters.ts +32 -32
- package/src/memory/job-handlers/summarization.ts +1 -2
- package/src/memory/jobs-store.ts +3 -1
- package/src/memory/jobs-worker.ts +51 -39
- package/src/memory/llm-request-log-source-clickhouse.ts +5 -31
- package/src/memory/llm-request-log-source-local.ts +0 -11
- package/src/memory/llm-request-log-source.ts +9 -25
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +10 -0
- package/src/memory/memory-marker.ts +17 -0
- package/src/memory/memory-retrospective-job.ts +6 -2
- package/src/memory/memory-v2-activation-log-store.ts +1 -83
- package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
- package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
- package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
- package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
- package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/schema/infrastructure.ts +11 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +124 -0
- package/src/memory/v2/__tests__/migration.test.ts +11 -3
- package/src/memory/v2/__tests__/page-index.test.ts +37 -1
- package/src/memory/v2/__tests__/router.test.ts +14 -4
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -5
- package/src/memory/v2/backfill-jobs.ts +6 -0
- package/src/memory/v2/consolidation-job.ts +89 -9
- package/src/memory/v2/migration.ts +5 -3
- package/src/memory/v2/page-index.ts +11 -0
- package/src/memory/v2/router.ts +8 -11
- package/src/memory/v2/sweep-job.ts +8 -11
- package/src/memory/v2/types.ts +1 -0
- package/src/memory/v3/__tests__/assign.test.ts +242 -0
- package/src/memory/v3/__tests__/capabilities.test.ts +118 -0
- package/src/memory/v3/__tests__/core.test.ts +39 -0
- package/src/memory/v3/__tests__/fixtures/eval-turns.json +36 -0
- package/src/memory/v3/__tests__/fixtures/live-turns.json +37 -0
- package/src/memory/v3/__tests__/health.test.ts +203 -0
- package/src/memory/v3/__tests__/live-integration.test.ts +330 -0
- package/src/memory/v3/__tests__/maintain-job.test.ts +288 -0
- package/src/memory/v3/__tests__/needle.test.ts +107 -0
- package/src/memory/v3/__tests__/orchestrate.test.ts +400 -0
- package/src/memory/v3/__tests__/reconcile.test.ts +274 -0
- package/src/memory/v3/__tests__/render-injection.test.ts +61 -0
- package/src/memory/v3/__tests__/router.test.ts +260 -0
- package/src/memory/v3/__tests__/selection-log-store.test.ts +179 -0
- package/src/memory/v3/__tests__/selector.test.ts +404 -0
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +414 -0
- package/src/memory/v3/__tests__/snapshot.test.ts +168 -0
- package/src/memory/v3/__tests__/tree.test.ts +192 -0
- package/src/memory/v3/__tests__/types.test.ts +54 -0
- package/src/memory/v3/__tests__/working-set-eviction.test.ts +106 -0
- package/src/memory/v3/__tests__/working-set-skeleton.test.ts +44 -0
- package/src/memory/v3/assign.ts +268 -0
- package/src/memory/v3/capabilities.ts +124 -0
- package/src/memory/v3/core.ts +26 -0
- package/src/memory/v3/data/README.md +84 -0
- package/src/memory/v3/data/assignments.json +5 -0
- package/src/memory/v3/data/core.json +1 -0
- package/src/memory/v3/data/leaves/domain-a/topic-x.md +9 -0
- package/src/memory/v3/data/leaves/domain-a/topic-y.md +9 -0
- package/src/memory/v3/data/leaves/domain-b/topic-z.md +9 -0
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +314 -0
- package/src/memory/v3/needle.ts +115 -0
- package/src/memory/v3/orchestrate.ts +114 -0
- package/src/memory/v3/page-content.ts +34 -0
- package/src/memory/v3/provider-blocks.ts +16 -0
- package/src/memory/v3/reconcile.ts +523 -0
- package/src/memory/v3/render-injection.ts +32 -0
- package/src/memory/v3/router.ts +184 -0
- package/src/memory/v3/selection-log-store.ts +84 -0
- package/src/memory/v3/selector.ts +211 -0
- package/src/memory/v3/shadow-plugin.ts +379 -0
- package/src/memory/v3/snapshot.ts +209 -0
- package/src/memory/v3/tree.ts +174 -0
- package/src/memory/v3/types.ts +46 -60
- package/src/memory/v3/working-set.ts +88 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.ts +2 -2
- package/src/messaging/style-analyzer.ts +8 -11
- package/src/notifications/conversation-pairing.ts +8 -6
- package/src/notifications/decision-engine.ts +10 -13
- package/src/notifications/preference-extractor.ts +11 -14
- package/src/permissions/prompter.ts +42 -36
- package/src/permissions/question-prompter.test.ts +35 -26
- package/src/permissions/question-prompter.ts +6 -10
- package/src/plugin-api/index.ts +2 -0
- package/src/plugin-api/types.ts +25 -3
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/circuit-breaker/package.json +15 -0
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +15 -0
- package/src/plugins/defaults/compaction/register.ts +35 -0
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +22 -0
- package/src/plugins/defaults/empty-response/package.json +15 -0
- package/src/plugins/defaults/empty-response/register.ts +28 -0
- package/src/plugins/defaults/empty-response/terminal.ts +106 -0
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/history-repair/package.json +15 -0
- package/src/plugins/defaults/history-repair/register.ts +24 -0
- package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
- package/src/plugins/defaults/index.ts +29 -40
- package/src/plugins/defaults/injectors/package.json +15 -0
- package/src/plugins/defaults/{injectors.ts → injectors/register.ts} +14 -38
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +17 -0
- package/src/plugins/defaults/llm-call/package.json +15 -0
- package/src/plugins/defaults/{llm-call.ts → llm-call/register.ts} +6 -38
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +17 -0
- package/src/plugins/defaults/memory-retrieval/package.json +15 -0
- package/src/plugins/defaults/{memory-retrieval.ts → memory-retrieval/register.ts} +10 -48
- package/src/plugins/defaults/{overflow-reduce.ts → overflow-reduce/middlewares/overflowReduce.ts} +18 -77
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +19 -0
- package/src/plugins/defaults/persistence/package.json +15 -0
- package/src/plugins/defaults/persistence/register.ts +38 -0
- package/src/plugins/defaults/persistence/terminal.ts +83 -0
- package/src/plugins/defaults/title-generate/package.json +15 -0
- package/src/plugins/defaults/title-generate/register.ts +35 -0
- package/src/plugins/defaults/title-generate/terminal.ts +31 -0
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +23 -0
- package/src/plugins/defaults/token-estimate/package.json +15 -0
- package/src/plugins/defaults/token-estimate/register.ts +34 -0
- package/src/plugins/defaults/token-estimate/terminal.ts +40 -0
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +21 -0
- package/src/plugins/defaults/tool-error/package.json +15 -0
- package/src/plugins/defaults/tool-error/register.ts +35 -0
- package/src/plugins/defaults/tool-error/terminal.ts +47 -0
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +23 -0
- package/src/plugins/defaults/tool-execute/package.json +15 -0
- package/src/plugins/defaults/{tool-execute.ts → tool-execute/register.ts} +8 -46
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +23 -0
- package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +35 -0
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +113 -0
- package/src/plugins/defaults/tool-result-truncate/types.ts +22 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/pipeline.ts +0 -12
- package/src/plugins/types.ts +51 -90
- package/src/plugins/user-loader.ts +4 -3
- package/src/proactive-artifact/aux-message-injector.ts +0 -1
- package/src/proactive-artifact/job.test.ts +20 -8
- package/src/proactive-artifact/job.ts +3 -1
- package/src/prompts/sections.ts +20 -7
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
- package/src/prompts/templates/BOOTSTRAP.md +5 -1
- package/src/prompts/templates/system-sections.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -25
- package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
- package/src/providers/anthropic/client.ts +24 -5
- package/src/providers/call-site-routing.ts +1 -9
- package/src/providers/gemini/client.ts +152 -34
- package/src/providers/gemini/inline-media.ts +74 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +0 -2
- package/src/providers/openai/chat-completions-provider.ts +1 -4
- package/src/providers/openai/responses-provider.ts +1 -4
- package/src/providers/openrouter/client.ts +1 -6
- package/src/providers/provider-send-message.ts +6 -6
- package/src/providers/ratelimit.ts +1 -9
- package/src/providers/retry.ts +0 -5
- package/src/providers/types.ts +11 -2
- package/src/providers/usage-tracking.ts +1 -9
- package/src/runtime/__tests__/agent-wake.test.ts +131 -26
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -3
- package/src/runtime/agent-wake.ts +93 -18
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
- package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
- package/src/runtime/auth/route-policy.ts +42 -1079
- package/src/runtime/background-job-runner.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -1
- package/src/runtime/channel-approvals.ts +3 -14
- package/src/runtime/channel-invite-transport.ts +5 -6
- package/src/runtime/channel-readiness-service.ts +2 -5
- package/src/runtime/channel-retry-sweep.ts +12 -16
- package/src/runtime/conversation-stream-state.ts +294 -0
- package/src/runtime/http-router.ts +19 -22
- package/src/runtime/http-types.ts +12 -6
- package/src/runtime/invite-instruction-generator.ts +3 -3
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +62 -32
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -22
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +7 -2
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
- package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
- package/src/runtime/routes/__tests__/tts-routes.test.ts +3 -3
- package/src/runtime/routes/acp-routes.test.ts +97 -75
- package/src/runtime/routes/acp-routes.ts +29 -6
- package/src/runtime/routes/app-management-routes.ts +97 -24
- package/src/runtime/routes/app-routes.ts +25 -5
- package/src/runtime/routes/approval-routes.ts +16 -4
- package/src/runtime/routes/attachment-routes.ts +25 -1
- package/src/runtime/routes/audio-routes.ts +1 -0
- package/src/runtime/routes/audit-routes.ts +5 -0
- package/src/runtime/routes/auth-routes.ts +5 -0
- package/src/runtime/routes/avatar-routes.ts +238 -59
- package/src/runtime/routes/background-tool-routes.ts +9 -0
- package/src/runtime/routes/background-wake-routes.ts +13 -3
- package/src/runtime/routes/backup-routes.ts +45 -0
- package/src/runtime/routes/bookmark-routes.ts +13 -0
- package/src/runtime/routes/brain-graph-routes.ts +9 -0
- package/src/runtime/routes/browser-routes.ts +5 -0
- package/src/runtime/routes/browser-tabs-routes.ts +5 -0
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/cache-routes.ts +13 -0
- package/src/runtime/routes/call-routes.ts +21 -10
- package/src/runtime/routes/channel-availability-routes.ts +5 -1
- package/src/runtime/routes/channel-readiness-routes.ts +37 -4
- package/src/runtime/routes/channel-route-definitions.ts +21 -0
- package/src/runtime/routes/channel-verification-routes.ts +21 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
- package/src/runtime/routes/client-routes.ts +9 -0
- package/src/runtime/routes/consolidation-routes.ts +13 -5
- package/src/runtime/routes/contact-prompt-routes.ts +9 -0
- package/src/runtime/routes/contact-routes.ts +90 -23
- package/src/runtime/routes/content-source-routes.ts +5 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +5 -1
- package/src/runtime/routes/conversation-attention-routes.ts +5 -0
- package/src/runtime/routes/conversation-cli-routes.ts +54 -7
- package/src/runtime/routes/conversation-compaction-routes.ts +54 -25
- package/src/runtime/routes/conversation-list-routes.ts +81 -12
- package/src/runtime/routes/conversation-management-routes.ts +57 -14
- package/src/runtime/routes/conversation-query-routes.ts +88 -41
- package/src/runtime/routes/conversation-routes.ts +74 -19
- package/src/runtime/routes/conversation-starter-routes.ts +22 -13
- package/src/runtime/routes/conversations-import-routes.ts +6 -1
- package/src/runtime/routes/credential-prompt-routes.ts +5 -0
- package/src/runtime/routes/credential-routes.ts +25 -6
- package/src/runtime/routes/debug-bash-routes.ts +5 -0
- package/src/runtime/routes/debug-routes.ts +11 -2
- package/src/runtime/routes/defer-routes.ts +13 -0
- package/src/runtime/routes/diagnostics-routes.ts +37 -46
- package/src/runtime/routes/disk-pressure-routes.ts +17 -31
- package/src/runtime/routes/document-comments-routes.ts +46 -27
- package/src/runtime/routes/documents-routes.ts +21 -10
- package/src/runtime/routes/domain-routes.ts +61 -28
- package/src/runtime/routes/email-routes.ts +33 -0
- package/src/runtime/routes/events-routes.ts +114 -9
- package/src/runtime/routes/filing-routes.ts +9 -4
- package/src/runtime/routes/gateway-log-routes.ts +5 -0
- package/src/runtime/routes/global-search-routes.ts +53 -50
- package/src/runtime/routes/group-routes.ts +21 -5
- package/src/runtime/routes/guardian-action-routes.ts +9 -0
- package/src/runtime/routes/guardian-approval-interception.ts +0 -31
- package/src/runtime/routes/heartbeat-routes.ts +25 -9
- package/src/runtime/routes/home-feed-routes.ts +23 -19
- package/src/runtime/routes/home-state-routes.ts +8 -40
- package/src/runtime/routes/host-app-control-routes.ts +5 -0
- package/src/runtime/routes/host-bash-routes.ts +5 -0
- package/src/runtime/routes/host-browser-routes.ts +13 -0
- package/src/runtime/routes/host-cu-routes.ts +5 -0
- package/src/runtime/routes/host-file-routes.ts +26 -6
- package/src/runtime/routes/host-transfer-routes.ts +13 -2
- package/src/runtime/routes/http-adapter.ts +1 -2
- package/src/runtime/routes/identity-intro-cache.ts +17 -6
- package/src/runtime/routes/identity-routes.ts +12 -2
- package/src/runtime/routes/image-generation-routes.ts +5 -0
- package/src/runtime/routes/inbound-message-handler.ts +15 -11
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +0 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +15 -19
- package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
- package/src/runtime/routes/inference-provider-connection-routes.ts +21 -5
- package/src/runtime/routes/inference-send-routes.ts +11 -11
- package/src/runtime/routes/integrations/a2a.ts +30 -7
- package/src/runtime/routes/integrations/slack/channel.ts +19 -3
- package/src/runtime/routes/integrations/slack/share.ts +9 -2
- package/src/runtime/routes/integrations/telegram.ts +28 -9
- package/src/runtime/routes/integrations/twilio.ts +35 -7
- package/src/runtime/routes/integrations/vercel.ts +3 -3
- package/src/runtime/routes/internal-oauth-routes.ts +5 -0
- package/src/runtime/routes/internal-twilio-routes.ts +13 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
- package/src/runtime/routes/log-export-routes.ts +28 -10
- package/src/runtime/routes/mcp-auth-routes.ts +25 -0
- package/src/runtime/routes/memory-item-routes.ts +21 -10
- package/src/runtime/routes/memory-v2-routes.ts +90 -36
- package/src/runtime/routes/memory-v3-routes.ts +273 -407
- package/src/runtime/routes/migration-rollback-routes.ts +5 -1
- package/src/runtime/routes/migration-routes.ts +29 -0
- package/src/runtime/routes/notification-routes.ts +17 -1
- package/src/runtime/routes/oauth-apps.ts +33 -11
- package/src/runtime/routes/oauth-commands-routes.ts +37 -14
- package/src/runtime/routes/oauth-connect-routes.ts +9 -0
- package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
- package/src/runtime/routes/oauth-providers.ts +35 -10
- package/src/runtime/routes/platform-routes.ts +21 -0
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +3 -2
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
- package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +0 -1
- package/src/runtime/routes/playground/inject-failures.ts +13 -8
- package/src/runtime/routes/playground/reset-circuit.ts +14 -9
- package/src/runtime/routes/playground/seed-conversation.ts +1 -1
- package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
- package/src/runtime/routes/playground/state.ts +4 -3
- package/src/runtime/routes/plugins-routes.ts +22 -19
- package/src/runtime/routes/profiler-routes.ts +17 -4
- package/src/runtime/routes/ps-routes.ts +5 -0
- package/src/runtime/routes/publish-routes.ts +13 -3
- package/src/runtime/routes/question-routes.ts +5 -0
- package/src/runtime/routes/recording-routes.ts +25 -12
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/sanity-routes.ts +9 -2
- package/src/runtime/routes/schedule-routes.ts +137 -47
- package/src/runtime/routes/secret-routes.ts +17 -4
- package/src/runtime/routes/sequence-routes.ts +33 -0
- package/src/runtime/routes/settings-routes.ts +65 -19
- package/src/runtime/routes/skills-routes.ts +133 -69
- package/src/runtime/routes/slack-channel-routes.ts +5 -0
- package/src/runtime/routes/stt-routes.ts +13 -6
- package/src/runtime/routes/subagents-routes.ts +24 -18
- package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
- package/src/runtime/routes/surface-action-routes.ts +9 -0
- package/src/runtime/routes/surface-content-routes.ts +10 -2
- package/src/runtime/routes/task-routes.ts +37 -0
- package/src/runtime/routes/telemetry-routes.ts +9 -0
- package/src/runtime/routes/trace-event-routes.ts +42 -1
- package/src/runtime/routes/trust-rules-routes.ts +5 -0
- package/src/runtime/routes/tts-routes.ts +13 -6
- package/src/runtime/routes/types.ts +17 -8
- package/src/runtime/routes/ui-request-routes.ts +5 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
- package/src/runtime/routes/usage-routes.ts +71 -3
- package/src/runtime/routes/user-routes-cli.ts +9 -0
- package/src/runtime/routes/user-routes.ts +5 -1
- package/src/runtime/routes/wake-conversation-routes.ts +5 -0
- package/src/runtime/routes/watcher-routes.ts +21 -0
- package/src/runtime/routes/webhook-routes.ts +9 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +5 -0
- package/src/runtime/routes/work-items-routes.ts +47 -19
- package/src/runtime/routes/workspace-commit-routes.ts +5 -0
- package/src/runtime/routes/workspace-routes.test.ts +42 -0
- package/src/runtime/routes/workspace-routes.ts +120 -9
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -4
- package/src/runtime/services/analyze-conversation.ts +3 -6
- package/src/runtime/services/conversation-serializer.ts +24 -2
- package/src/runtime/sync/resource-sync-events.ts +16 -2
- package/src/runtime/sync/sync-publisher.ts +2 -2
- package/src/schedule/run-script.ts +28 -3
- package/src/schedule/schedule-store.ts +8 -0
- package/src/schedule/scheduler.ts +3 -1
- package/src/signals/user-message.ts +5 -8
- package/src/skills/catalog-files.ts +4 -1
- package/src/skills/clawhub-files.ts +2 -0
- package/src/skills/skillssh-files.ts +2 -0
- package/src/subagent/manager.ts +3 -6
- package/src/telemetry/types.ts +26 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +138 -1
- package/src/telemetry/usage-telemetry-reporter.ts +31 -0
- package/src/tools/acp/spawn.test.ts +88 -38
- package/src/tools/apps/definitions.ts +8 -4
- package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
- package/src/tools/ask-question/ask-question-tool.ts +85 -90
- package/src/tools/computer-use/definitions.ts +28 -24
- package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
- package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
- package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
- package/src/tools/credentials/vault.ts +112 -111
- package/src/tools/execution-target.ts +1 -1
- package/src/tools/execution-timeout.ts +3 -4
- package/src/tools/filesystem/edit.ts +45 -42
- package/src/tools/filesystem/list.ts +33 -30
- package/src/tools/filesystem/read.ts +54 -35
- package/src/tools/filesystem/write.ts +34 -31
- package/src/tools/host-filesystem/edit.ts +44 -42
- package/src/tools/host-filesystem/read.ts +49 -35
- package/src/tools/host-filesystem/transfer.ts +121 -108
- package/src/tools/host-filesystem/write.ts +33 -31
- package/src/tools/host-terminal/host-shell.ts +50 -48
- package/src/tools/memory/register.ts +23 -24
- package/src/tools/network/web-fetch.ts +49 -46
- package/src/tools/network/web-search.ts +16 -13
- package/src/tools/registry.ts +39 -16
- package/src/tools/schedule/create.ts +11 -0
- package/src/tools/schedule/update.ts +16 -0
- package/src/tools/shared/filesystem/audio-read.ts +122 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/execute.ts +34 -31
- package/src/tools/skills/load.ts +29 -23
- package/src/tools/subagent/notify-parent.ts +35 -32
- package/src/tools/system/avatar-generator.ts +13 -22
- package/src/tools/system/request-permission.ts +30 -27
- package/src/tools/terminal/shell.ts +190 -61
- package/src/tools/tool-defaults.ts +20 -9
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +74 -23
- package/src/tools/ui-surface/definitions.ts +69 -9
- package/src/usage/types.ts +10 -0
- package/src/util/errors.ts +2 -2
- package/src/util/map-limit.ts +27 -0
- package/src/util/platform.ts +15 -12
- package/src/work-items/work-item-runner.ts +7 -2
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
- package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
- package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
- package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
- package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
- package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/provider-commit-message-generator.ts +15 -17
- package/tsconfig.json +4 -1
- package/src/__tests__/history-repair-pipeline.test.ts +0 -396
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
- package/src/cli/commands/memory-v3-render.ts +0 -491
- package/src/daemon/message-types/disk-pressure.ts +0 -9
- package/src/email/feature-gate.ts +0 -23
- package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
- package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -466
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +0 -270
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
- package/src/memory/v3/__tests__/edges.test.ts +0 -706
- package/src/memory/v3/__tests__/filter.test.ts +0 -560
- package/src/memory/v3/__tests__/gate.test.ts +0 -637
- package/src/memory/v3/__tests__/index-composition.test.ts +0 -291
- package/src/memory/v3/__tests__/loop.test.ts +0 -775
- package/src/memory/v3/__tests__/retriever.test.ts +0 -226
- package/src/memory/v3/__tests__/scouts.test.ts +0 -489
- package/src/memory/v3/__tests__/shadow-diff.test.ts +0 -225
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -398
- package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
- package/src/memory/v3/__tests__/traversal.test.ts +0 -508
- package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
- package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
- package/src/memory/v3/__tests__/tree-walk.test.ts +0 -784
- package/src/memory/v3/__tests__/validate.test.ts +0 -277
- package/src/memory/v3/auto-edges.ts +0 -223
- package/src/memory/v3/coactivation-store.ts +0 -124
- package/src/memory/v3/consolidation-job.ts +0 -323
- package/src/memory/v3/coretrieval-seed.ts +0 -240
- package/src/memory/v3/edge-learning-job.ts +0 -160
- package/src/memory/v3/edges.ts +0 -286
- package/src/memory/v3/filter.ts +0 -286
- package/src/memory/v3/gate.ts +0 -349
- package/src/memory/v3/index-composition.ts +0 -126
- package/src/memory/v3/llm-capture.ts +0 -46
- package/src/memory/v3/loop.ts +0 -430
- package/src/memory/v3/maintenance.ts +0 -144
- package/src/memory/v3/prompt-context.ts +0 -33
- package/src/memory/v3/prompts/consolidation.ts +0 -458
- package/src/memory/v3/prompts/system-prompts.ts +0 -196
- package/src/memory/v3/retriever.ts +0 -33
- package/src/memory/v3/scouts.ts +0 -431
- package/src/memory/v3/shadow-diff.ts +0 -287
- package/src/memory/v3/shadow-middleware.ts +0 -347
- package/src/memory/v3/traversal.ts +0 -211
- package/src/memory/v3/tree-index.ts +0 -237
- package/src/memory/v3/tree-store.ts +0 -394
- package/src/memory/v3/tree-walk.ts +0 -356
- package/src/memory/v3/validate.ts +0 -323
- package/src/plugins/defaults/circuit-breaker.ts +0 -141
- package/src/plugins/defaults/compaction.ts +0 -141
- package/src/plugins/defaults/empty-response.ts +0 -124
- package/src/plugins/defaults/history-repair.ts +0 -83
- package/src/plugins/defaults/persistence.ts +0 -146
- package/src/plugins/defaults/title-generate.ts +0 -90
- package/src/plugins/defaults/token-estimate.ts +0 -101
- package/src/plugins/defaults/tool-error.ts +0 -119
- package/src/plugins/defaults/tool-result-truncate.ts +0 -84
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +0 -35
|
@@ -17,7 +17,7 @@ import type {
|
|
|
17
17
|
AgentLoop,
|
|
18
18
|
AgentLoopExitReason,
|
|
19
19
|
CheckpointDecision,
|
|
20
|
-
|
|
20
|
+
MidLoopCompaction,
|
|
21
21
|
} from "../agent/loop.js";
|
|
22
22
|
import { createAssistantMessage } from "../agent/message-types.js";
|
|
23
23
|
import type {
|
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
TurnChannelContext,
|
|
27
27
|
TurnInterfaceContext,
|
|
28
28
|
} from "../channels/types.js";
|
|
29
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
29
30
|
import {
|
|
30
31
|
contextWindowConfigFromEffective,
|
|
31
32
|
type EffectiveContextWindow,
|
|
@@ -95,28 +96,24 @@ import {
|
|
|
95
96
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
96
97
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
97
98
|
import type { UserPromptSubmitContext } from "../plugin-api/types.js";
|
|
98
|
-
import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
|
|
99
|
-
import {
|
|
99
|
+
import { defaultCompactionTerminal } from "../plugins/defaults/compaction/terminal.js";
|
|
100
|
+
import { deepRepairHistory } from "../plugins/defaults/history-repair/terminal.js";
|
|
100
101
|
import {
|
|
101
102
|
asDefaultGraphPayload,
|
|
102
103
|
type DefaultMemoryRetrievalDeps,
|
|
103
104
|
type GraphMemoryPayload,
|
|
104
105
|
runDefaultMemoryRetrieval,
|
|
105
|
-
} from "../plugins/defaults/memory-retrieval.js";
|
|
106
|
-
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
107
|
-
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate.js";
|
|
108
|
-
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate.js";
|
|
106
|
+
} from "../plugins/defaults/memory-retrieval/register.js";
|
|
107
|
+
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence/terminal.js";
|
|
108
|
+
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate/terminal.js";
|
|
109
|
+
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate/terminal.js";
|
|
109
110
|
import { DEFAULT_TIMEOUTS, runHook, runPipeline } from "../plugins/pipeline.js";
|
|
110
111
|
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
111
112
|
import type {
|
|
112
|
-
CircuitBreakerArgs,
|
|
113
|
-
CircuitBreakerResult,
|
|
114
113
|
CompactionArgs,
|
|
115
114
|
CompactionResult,
|
|
116
115
|
EstimateArgs,
|
|
117
116
|
EstimateResult,
|
|
118
|
-
HistoryRepairArgs,
|
|
119
|
-
HistoryRepairResult,
|
|
120
117
|
MemoryArgs,
|
|
121
118
|
MemoryResult,
|
|
122
119
|
OverflowReduceArgs,
|
|
@@ -127,11 +124,6 @@ import type {
|
|
|
127
124
|
TurnContext as PluginTurnContext,
|
|
128
125
|
} from "../plugins/types.js";
|
|
129
126
|
import { PluginExecutionError, PluginTimeoutError } from "../plugins/types.js";
|
|
130
|
-
import {
|
|
131
|
-
hasProactiveArtifactCompleted,
|
|
132
|
-
runProactiveArtifactJob,
|
|
133
|
-
tryClaimProactiveArtifactTrigger,
|
|
134
|
-
} from "../proactive-artifact/index.js";
|
|
135
127
|
import type {
|
|
136
128
|
ContentBlock,
|
|
137
129
|
Message,
|
|
@@ -210,7 +202,6 @@ import {
|
|
|
210
202
|
} from "./date-context.js";
|
|
211
203
|
import { getDiskPressureStatus } from "./disk-pressure-guard.js";
|
|
212
204
|
import { classifyDiskPressureTurnPolicy } from "./disk-pressure-policy.js";
|
|
213
|
-
import { deepRepairHistory } from "./history-repair.js";
|
|
214
205
|
import type {
|
|
215
206
|
DynamicPageSurfaceData,
|
|
216
207
|
ServerMessage,
|
|
@@ -276,154 +267,6 @@ function formatDiskPressureBlockedMessage(): string {
|
|
|
276
267
|
return "Storage is critically low, so background processes are paused and remote messages are ignored until the guardian frees enough space. Remote senders should try again later.";
|
|
277
268
|
}
|
|
278
269
|
|
|
279
|
-
// ── Compaction circuit-breaker pipeline helpers ─────────────────────
|
|
280
|
-
//
|
|
281
|
-
// The circuit-breaker behavior (3 consecutive summary-LLM failures trips a
|
|
282
|
-
// 1-hour cooldown) is now implemented by the `circuitBreaker` plugin
|
|
283
|
-
// pipeline. The default plugin (`plugins/defaults/circuit-breaker.ts`)
|
|
284
|
-
// replicates the legacy threshold/cooldown constants and event-emission
|
|
285
|
-
// semantics exactly — it operates on the `consecutiveCompactionFailures` /
|
|
286
|
-
// `compactionCircuitOpenUntil` fields the conversation still owns so the
|
|
287
|
-
// dev-only playground routes (`POST /playground/reset-compaction-circuit`,
|
|
288
|
-
// `POST /playground/inject-compaction-failures`) continue to read and
|
|
289
|
-
// mutate those fields directly.
|
|
290
|
-
//
|
|
291
|
-
// The helpers below build the pipeline inputs and invoke the runner. They
|
|
292
|
-
// are the sole entry points the rest of the daemon uses to query or update
|
|
293
|
-
// the compaction circuit.
|
|
294
|
-
|
|
295
|
-
/** Circuit-breaker key for a specific conversation's compaction pipeline. */
|
|
296
|
-
function compactionCircuitKey(conversationId: string): string {
|
|
297
|
-
return `compaction:${conversationId}`;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Build the minimal {@link TurnContext} the pipeline runner requires. Called
|
|
302
|
-
* both from inside the agent loop (where turn identifiers are available) and
|
|
303
|
-
* from non-turn invocations like `Conversation.forceCompact` (which falls
|
|
304
|
-
* back to stable placeholders so the runner's log records still carry the
|
|
305
|
-
* conversation identifier).
|
|
306
|
-
*/
|
|
307
|
-
function buildCircuitTurnContext(ctx: {
|
|
308
|
-
readonly conversationId: string;
|
|
309
|
-
currentRequestId?: string;
|
|
310
|
-
currentTurnTrustContext?: TrustContext;
|
|
311
|
-
trustContext?: TrustContext;
|
|
312
|
-
turnCount: number;
|
|
313
|
-
}): PluginTurnContext {
|
|
314
|
-
const trust: TrustContext =
|
|
315
|
-
ctx.currentTurnTrustContext ?? ctx.trustContext ?? FALLBACK_TURN_TRUST;
|
|
316
|
-
return {
|
|
317
|
-
requestId: ctx.currentRequestId ?? "circuit-breaker",
|
|
318
|
-
conversationId: ctx.conversationId,
|
|
319
|
-
turnIndex: ctx.turnCount,
|
|
320
|
-
trust,
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Run the `circuitBreaker` pipeline for the compaction circuit on this
|
|
326
|
-
* conversation. When `outcome` is provided, state is updated (and transition
|
|
327
|
-
* events emit via `onEvent`); when omitted the call is query-only.
|
|
328
|
-
*
|
|
329
|
-
* Returns the post-call decision from the pipeline. Callers gate auto-paths
|
|
330
|
-
* on `!result.open` and admit forced paths regardless of the decision.
|
|
331
|
-
*/
|
|
332
|
-
async function runCompactionCircuitPipeline(
|
|
333
|
-
ctx: {
|
|
334
|
-
readonly conversationId: string;
|
|
335
|
-
consecutiveCompactionFailures: number;
|
|
336
|
-
compactionCircuitOpenUntil: number | null;
|
|
337
|
-
currentRequestId?: string;
|
|
338
|
-
currentTurnTrustContext?: TrustContext;
|
|
339
|
-
trustContext?: TrustContext;
|
|
340
|
-
turnCount: number;
|
|
341
|
-
},
|
|
342
|
-
args: {
|
|
343
|
-
outcome?: "success" | "failure";
|
|
344
|
-
onEvent?: (msg: ServerMessage) => void;
|
|
345
|
-
},
|
|
346
|
-
): Promise<CircuitBreakerResult> {
|
|
347
|
-
const turnContext = buildCircuitTurnContext(ctx);
|
|
348
|
-
return runPipeline<CircuitBreakerArgs, CircuitBreakerResult>(
|
|
349
|
-
"circuitBreaker",
|
|
350
|
-
getMiddlewaresFor("circuitBreaker"),
|
|
351
|
-
async (terminalArgs) => {
|
|
352
|
-
// No plugin in the chain produced a decision. This should be
|
|
353
|
-
// unreachable in production because the default plugin registers a
|
|
354
|
-
// `circuitBreaker` middleware that always returns a decision, but we
|
|
355
|
-
// defensively derive the state here so test setups that intentionally
|
|
356
|
-
// omit the default plugin still get a sensible response.
|
|
357
|
-
const openUntil = terminalArgs.state.compactionCircuitOpenUntil;
|
|
358
|
-
const now = Date.now();
|
|
359
|
-
if (openUntil !== null && now < openUntil) {
|
|
360
|
-
return { open: true, cooldownRemainingMs: openUntil - now };
|
|
361
|
-
}
|
|
362
|
-
return { open: false };
|
|
363
|
-
},
|
|
364
|
-
{
|
|
365
|
-
key: compactionCircuitKey(ctx.conversationId),
|
|
366
|
-
// Pass the ctx directly as the mutable state container. The
|
|
367
|
-
// `CircuitBreakerArgs.state` shape deliberately matches the subset of
|
|
368
|
-
// fields the conversation owns so plugins mutate the same object the
|
|
369
|
-
// playground routes read and write.
|
|
370
|
-
state: ctx,
|
|
371
|
-
...(args.outcome !== undefined ? { outcome: args.outcome } : {}),
|
|
372
|
-
...(args.onEvent ? { onEvent: args.onEvent } : {}),
|
|
373
|
-
},
|
|
374
|
-
turnContext,
|
|
375
|
-
DEFAULT_TIMEOUTS.circuitBreaker,
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Query-only: is the compaction circuit breaker currently open for this
|
|
381
|
-
* conversation? Thin wrapper around {@link runCompactionCircuitPipeline}
|
|
382
|
-
* with no outcome. Async because the pipeline runner is async, but the
|
|
383
|
-
* default plugin resolves synchronously on its microtask.
|
|
384
|
-
*/
|
|
385
|
-
async function isCompactionCircuitOpen(ctx: {
|
|
386
|
-
readonly conversationId: string;
|
|
387
|
-
consecutiveCompactionFailures: number;
|
|
388
|
-
compactionCircuitOpenUntil: number | null;
|
|
389
|
-
currentRequestId?: string;
|
|
390
|
-
currentTurnTrustContext?: TrustContext;
|
|
391
|
-
trustContext?: TrustContext;
|
|
392
|
-
turnCount: number;
|
|
393
|
-
}): Promise<boolean> {
|
|
394
|
-
const decision = await runCompactionCircuitPipeline(ctx, {});
|
|
395
|
-
return decision.open;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Update the compaction circuit breaker with the outcome of a `maybeCompact`
|
|
400
|
-
* call and emit any transition event. A `summaryFailed` value of `undefined`
|
|
401
|
-
* means the summary LLM never ran (early return) — callers must guard with
|
|
402
|
-
* `summaryFailed !== undefined` before invoking this helper so early-return
|
|
403
|
-
* paths don't silently reset the 3-strike counter.
|
|
404
|
-
*
|
|
405
|
-
* The default plugin handles threshold-based tripping and cooldown reset;
|
|
406
|
-
* see `plugins/defaults/circuit-breaker.ts` for the canonical semantics.
|
|
407
|
-
*/
|
|
408
|
-
export async function trackCompactionOutcome(
|
|
409
|
-
ctx: {
|
|
410
|
-
readonly conversationId: string;
|
|
411
|
-
consecutiveCompactionFailures: number;
|
|
412
|
-
compactionCircuitOpenUntil: number | null;
|
|
413
|
-
currentRequestId?: string;
|
|
414
|
-
currentTurnTrustContext?: TrustContext;
|
|
415
|
-
trustContext?: TrustContext;
|
|
416
|
-
turnCount: number;
|
|
417
|
-
},
|
|
418
|
-
summaryFailed: boolean,
|
|
419
|
-
onEvent: (msg: ServerMessage) => void,
|
|
420
|
-
): Promise<void> {
|
|
421
|
-
await runCompactionCircuitPipeline(ctx, {
|
|
422
|
-
outcome: summaryFailed ? "failure" : "success",
|
|
423
|
-
onEvent,
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
|
|
427
270
|
// ── Plugin pipeline helpers ──────────────────────────────────────────
|
|
428
271
|
//
|
|
429
272
|
// Canonical {@link PluginTurnContext} builder threaded into every
|
|
@@ -484,6 +327,28 @@ function buildPluginTurnContext(
|
|
|
484
327
|
|
|
485
328
|
// ── Context Interface ────────────────────────────────────────────────
|
|
486
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Per-surface entry tracked on the current turn. Inline shape kept stable so
|
|
332
|
+
* routes and persistence helpers can consume it via a named import instead of
|
|
333
|
+
* `infer`-extracting from {@link AgentLoopConversationContext}.
|
|
334
|
+
*/
|
|
335
|
+
export interface AssistantSurface {
|
|
336
|
+
surfaceId: string;
|
|
337
|
+
surfaceType: SurfaceType;
|
|
338
|
+
title?: string;
|
|
339
|
+
data: SurfaceData;
|
|
340
|
+
actions?: Array<{
|
|
341
|
+
id: string;
|
|
342
|
+
label: string;
|
|
343
|
+
style?: string;
|
|
344
|
+
data?: Record<string, unknown>;
|
|
345
|
+
}>;
|
|
346
|
+
display?: string;
|
|
347
|
+
persistent?: boolean;
|
|
348
|
+
/** Id of the tool call that produced this surface (the `ui_show` proxy tool). Persisted so app previews can gate on the tool result's arrival rather than whole-turn streaming state. */
|
|
349
|
+
toolCallId?: string;
|
|
350
|
+
}
|
|
351
|
+
|
|
487
352
|
export interface AgentLoopConversationContext {
|
|
488
353
|
readonly conversationId: string;
|
|
489
354
|
messages: Message[];
|
|
@@ -507,10 +372,6 @@ export interface AgentLoopConversationContext {
|
|
|
507
372
|
* happened just before this turn).
|
|
508
373
|
*/
|
|
509
374
|
pendingPostCompactReinject: boolean;
|
|
510
|
-
/** Tracks consecutive compaction failures (summary LLM call threw). */
|
|
511
|
-
consecutiveCompactionFailures: number;
|
|
512
|
-
/** Timestamp (ms since epoch) until which the circuit breaker is open. */
|
|
513
|
-
compactionCircuitOpenUntil: number | null;
|
|
514
375
|
|
|
515
376
|
readonly graphMemory: ConversationGraphMemory;
|
|
516
377
|
|
|
@@ -533,20 +394,7 @@ export interface AgentLoopConversationContext {
|
|
|
533
394
|
pendingSurfaceActions: Map<string, { surfaceType: SurfaceType }>;
|
|
534
395
|
surfaceActionRequestIds: Set<string>;
|
|
535
396
|
approvedViaPromptThisTurn?: boolean;
|
|
536
|
-
currentTurnSurfaces:
|
|
537
|
-
surfaceId: string;
|
|
538
|
-
surfaceType: SurfaceType;
|
|
539
|
-
title?: string;
|
|
540
|
-
data: SurfaceData;
|
|
541
|
-
actions?: Array<{
|
|
542
|
-
id: string;
|
|
543
|
-
label: string;
|
|
544
|
-
style?: string;
|
|
545
|
-
data?: Record<string, unknown>;
|
|
546
|
-
}>;
|
|
547
|
-
display?: string;
|
|
548
|
-
persistent?: boolean;
|
|
549
|
-
}>;
|
|
397
|
+
currentTurnSurfaces: AssistantSurface[];
|
|
550
398
|
|
|
551
399
|
workingDir: string;
|
|
552
400
|
workspaceTopLevelContext: string | null;
|
|
@@ -624,9 +472,11 @@ export interface AgentLoopConversationContext {
|
|
|
624
472
|
| "message_complete"
|
|
625
473
|
| "generation_cancelled"
|
|
626
474
|
| "error_terminal",
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
475
|
+
options?: {
|
|
476
|
+
anchor?: "assistant_turn" | "user_turn" | "global";
|
|
477
|
+
requestId?: string;
|
|
478
|
+
statusText?: string;
|
|
479
|
+
},
|
|
630
480
|
): void;
|
|
631
481
|
emitConfirmationStateChanged(
|
|
632
482
|
params: ConfirmationStateChanged extends {
|
|
@@ -644,7 +494,6 @@ export interface AgentLoopConversationContext {
|
|
|
644
494
|
onConfirmationOutcome?: (
|
|
645
495
|
requestId: string,
|
|
646
496
|
state: string,
|
|
647
|
-
toolName?: string,
|
|
648
497
|
toolUseId?: string,
|
|
649
498
|
) => void;
|
|
650
499
|
|
|
@@ -859,6 +708,25 @@ export async function runAgentLoopImpl(
|
|
|
859
708
|
preflightBudget: Math.floor(providerMaxTokens * (1 - safetyMargin)),
|
|
860
709
|
};
|
|
861
710
|
};
|
|
711
|
+
/**
|
|
712
|
+
* The agent loop's window into the orchestrator's current effective
|
|
713
|
+
* context window. The loop reads `maxInputTokens` for tool-result
|
|
714
|
+
* truncation and `overflowRecovery` for its mid-loop budget gate, applying
|
|
715
|
+
* the long-history safety-margin bump itself off its own running history.
|
|
716
|
+
* Resolved fresh on each access so a mid-turn profile change is reflected.
|
|
717
|
+
*/
|
|
718
|
+
const resolveContextWindow = (): {
|
|
719
|
+
maxInputTokens: number;
|
|
720
|
+
overflowRecovery: { enabled: boolean; safetyMarginRatio: number };
|
|
721
|
+
} => {
|
|
722
|
+
refreshCurrentProfileState();
|
|
723
|
+
const { enabled, safetyMarginRatio } =
|
|
724
|
+
currentEffectiveContextWindow.overflowRecovery;
|
|
725
|
+
return {
|
|
726
|
+
maxInputTokens: currentEffectiveContextWindow.maxInputTokens,
|
|
727
|
+
overflowRecovery: { enabled, safetyMarginRatio },
|
|
728
|
+
};
|
|
729
|
+
};
|
|
862
730
|
|
|
863
731
|
// Initial value for `createToolExecutor` to read into
|
|
864
732
|
// `ToolContext.overrideProfile`. `resolveCurrentOverrideProfile` refreshes
|
|
@@ -968,7 +836,10 @@ export async function runAgentLoopImpl(
|
|
|
968
836
|
{ reason: diskPressureDecision.reason },
|
|
969
837
|
"Blocked turn during disk pressure cleanup mode",
|
|
970
838
|
);
|
|
971
|
-
ctx.emitActivityState("idle", "error_terminal",
|
|
839
|
+
ctx.emitActivityState("idle", "error_terminal", {
|
|
840
|
+
anchor: "global",
|
|
841
|
+
requestId: reqId,
|
|
842
|
+
});
|
|
972
843
|
ctx.traceEmitter.emit("request_error", message, {
|
|
973
844
|
requestId: reqId,
|
|
974
845
|
status: "error",
|
|
@@ -1220,14 +1091,12 @@ export async function runAgentLoopImpl(
|
|
|
1220
1091
|
);
|
|
1221
1092
|
// Skip auto-compaction while the circuit breaker is open. Force paths
|
|
1222
1093
|
// and user-initiated /compact bypass this check.
|
|
1223
|
-
const autoCompactAllowed =
|
|
1094
|
+
const autoCompactAllowed =
|
|
1095
|
+
!(await ctx.agentLoop.compactionCircuit.isOpen(ctx));
|
|
1224
1096
|
if (compactCheck.needed && autoCompactAllowed) {
|
|
1225
|
-
ctx.emitActivityState(
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
"assistant_turn",
|
|
1229
|
-
reqId,
|
|
1230
|
-
);
|
|
1097
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
1098
|
+
requestId: reqId,
|
|
1099
|
+
});
|
|
1231
1100
|
}
|
|
1232
1101
|
const compactionOptions = {
|
|
1233
1102
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
@@ -1235,6 +1104,7 @@ export async function runAgentLoopImpl(
|
|
|
1235
1104
|
conversationOriginChannel:
|
|
1236
1105
|
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
1237
1106
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1107
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
1238
1108
|
};
|
|
1239
1109
|
let compacted: Awaited<
|
|
1240
1110
|
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
@@ -1267,7 +1137,11 @@ export async function runAgentLoopImpl(
|
|
|
1267
1137
|
{ err, phase: "start-of-turn-compaction" },
|
|
1268
1138
|
"Compaction pipeline timed out — skipping compaction this turn",
|
|
1269
1139
|
);
|
|
1270
|
-
await
|
|
1140
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1141
|
+
ctx,
|
|
1142
|
+
true,
|
|
1143
|
+
onEvent,
|
|
1144
|
+
);
|
|
1271
1145
|
compacted = null;
|
|
1272
1146
|
} else {
|
|
1273
1147
|
throw err;
|
|
@@ -1280,7 +1154,11 @@ export async function runAgentLoopImpl(
|
|
|
1280
1154
|
// path) — treating those as "successful" compactions would silently reset
|
|
1281
1155
|
// the 3-strike counter and break the invariant.
|
|
1282
1156
|
if (compacted && compacted.summaryFailed !== undefined) {
|
|
1283
|
-
await
|
|
1157
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1158
|
+
ctx,
|
|
1159
|
+
compacted.summaryFailed,
|
|
1160
|
+
onEvent,
|
|
1161
|
+
);
|
|
1284
1162
|
}
|
|
1285
1163
|
if (compacted?.compacted) {
|
|
1286
1164
|
await applySuccessfulCompaction(
|
|
@@ -1295,12 +1173,7 @@ export async function runAgentLoopImpl(
|
|
|
1295
1173
|
|
|
1296
1174
|
// Register confirmation outcome tracker so the agent loop can link
|
|
1297
1175
|
// confirmation decisions to tool_use_ids for persistence.
|
|
1298
|
-
ctx.onConfirmationOutcome = (
|
|
1299
|
-
requestId,
|
|
1300
|
-
confirmationState,
|
|
1301
|
-
toolName,
|
|
1302
|
-
toolUseId,
|
|
1303
|
-
) => {
|
|
1176
|
+
ctx.onConfirmationOutcome = (requestId, confirmationState, toolUseId) => {
|
|
1304
1177
|
if (confirmationState === "pending") {
|
|
1305
1178
|
// Use the toolUseId passed from the prompter (which knows which tool
|
|
1306
1179
|
// requested confirmation) instead of the ambient state.currentToolUseId,
|
|
@@ -1317,7 +1190,7 @@ export async function runAgentLoopImpl(
|
|
|
1317
1190
|
const resolvedId =
|
|
1318
1191
|
state.requestIdToToolUseId.get(requestId) ?? toolUseId;
|
|
1319
1192
|
if (resolvedId) {
|
|
1320
|
-
const name = state.toolUseIdToName.get(resolvedId) ??
|
|
1193
|
+
const name = state.toolUseIdToName.get(resolvedId) ?? "";
|
|
1321
1194
|
// Build a friendly label from the tool name
|
|
1322
1195
|
const label =
|
|
1323
1196
|
TOOL_FRIENDLY_LABEL[name] ??
|
|
@@ -1760,8 +1633,21 @@ export async function runAgentLoopImpl(
|
|
|
1760
1633
|
// to the reduced `ctx.messages`.
|
|
1761
1634
|
let reducerCompacted = compactedThisTurn;
|
|
1762
1635
|
|
|
1636
|
+
// memory-v3-live: route the turn's `<memory>` block to the v3 injector.
|
|
1637
|
+
// When on, runtime assembly suppresses v2's `<memory>` injection (only
|
|
1638
|
+
// when the v3 injector actually produced a block — otherwise v2 stays as a
|
|
1639
|
+
// fallback) and the provider anchors its long-TTL cache breakpoint on the
|
|
1640
|
+
// most recent STABLE user message, since the latest user message now
|
|
1641
|
+
// carries the volatile per-turn memory block. Flag off → bit-for-bit
|
|
1642
|
+
// identical to today's v2 path.
|
|
1643
|
+
const memoryV3Live = isAssistantFeatureFlagEnabled(
|
|
1644
|
+
"memory-v3-live",
|
|
1645
|
+
getConfig(),
|
|
1646
|
+
);
|
|
1647
|
+
|
|
1763
1648
|
// Shared injection options — reused whenever we need to re-inject after reduction.
|
|
1764
1649
|
const injectionOpts = {
|
|
1650
|
+
suppressV2MemoryForV3: memoryV3Live,
|
|
1765
1651
|
diskPressureContext,
|
|
1766
1652
|
activeSurface,
|
|
1767
1653
|
activeDocuments,
|
|
@@ -1983,6 +1869,7 @@ export async function runAgentLoopImpl(
|
|
|
1983
1869
|
options: {
|
|
1984
1870
|
...(opts ?? {}),
|
|
1985
1871
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
1872
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
1986
1873
|
},
|
|
1987
1874
|
},
|
|
1988
1875
|
buildPluginTurnContext(ctx, reqId),
|
|
@@ -1996,7 +1883,11 @@ export async function runAgentLoopImpl(
|
|
|
1996
1883
|
{ err, phase: "overflow-reducer-forced-compaction" },
|
|
1997
1884
|
"Compaction pipeline timed out — falling through to next reducer tier",
|
|
1998
1885
|
);
|
|
1999
|
-
await
|
|
1886
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1887
|
+
ctx,
|
|
1888
|
+
true,
|
|
1889
|
+
onEvent,
|
|
1890
|
+
);
|
|
2000
1891
|
return {
|
|
2001
1892
|
messages: msgs,
|
|
2002
1893
|
compacted: false,
|
|
@@ -2018,12 +1909,9 @@ export async function runAgentLoopImpl(
|
|
|
2018
1909
|
}
|
|
2019
1910
|
},
|
|
2020
1911
|
emitActivityState: () => {
|
|
2021
|
-
ctx.emitActivityState(
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
"assistant_turn",
|
|
2025
|
-
reqId,
|
|
2026
|
-
);
|
|
1912
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
1913
|
+
requestId: reqId,
|
|
1914
|
+
});
|
|
2027
1915
|
},
|
|
2028
1916
|
onCompactionResult: async (result, compactedBasis) => {
|
|
2029
1917
|
// Track circuit-breaker state whenever the reducer invoked
|
|
@@ -2036,7 +1924,11 @@ export async function runAgentLoopImpl(
|
|
|
2036
1924
|
// truncation-only path, etc.) that shouldn't influence the
|
|
2037
1925
|
// breaker.
|
|
2038
1926
|
if (result.summaryFailed !== undefined) {
|
|
2039
|
-
await
|
|
1927
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
1928
|
+
ctx,
|
|
1929
|
+
result.summaryFailed,
|
|
1930
|
+
onEvent,
|
|
1931
|
+
);
|
|
2040
1932
|
}
|
|
2041
1933
|
if (result.compacted) {
|
|
2042
1934
|
await applySuccessfulCompaction(result, compactedBasis);
|
|
@@ -2130,55 +2022,7 @@ export async function runAgentLoopImpl(
|
|
|
2130
2022
|
}
|
|
2131
2023
|
}
|
|
2132
2024
|
|
|
2133
|
-
// Pre-run repair — routed through the `historyRepair` plugin pipeline so
|
|
2134
|
-
// plugins can observe or override repair behavior. The default plugin's
|
|
2135
|
-
// middleware is a passthrough; the actual repair runs in the terminal
|
|
2136
|
-
// (`defaultHistoryRepairTerminal`).
|
|
2137
2025
|
let preRepairMessages = runMessages;
|
|
2138
|
-
let preRunRepair: HistoryRepairResult | null = null;
|
|
2139
|
-
try {
|
|
2140
|
-
preRunRepair = await runPipeline<HistoryRepairArgs, HistoryRepairResult>(
|
|
2141
|
-
"historyRepair",
|
|
2142
|
-
getMiddlewaresFor("historyRepair"),
|
|
2143
|
-
async (args) => defaultHistoryRepairTerminal(args),
|
|
2144
|
-
{ history: runMessages, provider: ctx.provider.name },
|
|
2145
|
-
buildPluginTurnContext(ctx, reqId),
|
|
2146
|
-
DEFAULT_TIMEOUTS.historyRepair,
|
|
2147
|
-
);
|
|
2148
|
-
} catch (err) {
|
|
2149
|
-
if (err instanceof PluginTimeoutError) {
|
|
2150
|
-
// Pipeline exceeded its budget — likely a misbehaving third-party
|
|
2151
|
-
// middleware. Degrade gracefully by proceeding with the un-repaired
|
|
2152
|
-
// history rather than turn-fatal-erroring; un-repaired history is
|
|
2153
|
-
// strictly better than no turn at all, and the provider call itself
|
|
2154
|
-
// will still error visibly if the drift is unrecoverable.
|
|
2155
|
-
rlog.warn(
|
|
2156
|
-
{ err, phase: "pre_run" },
|
|
2157
|
-
"historyRepair pipeline timed out — proceeding with un-repaired history",
|
|
2158
|
-
);
|
|
2159
|
-
} else {
|
|
2160
|
-
throw err;
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
if (preRunRepair !== null) {
|
|
2164
|
-
// Always adopt the pipeline's output history — a user `historyRepair`
|
|
2165
|
-
// middleware may rewrite `messages` (e.g. provider-specific
|
|
2166
|
-
// normalization) without incrementing any of the built-in repair
|
|
2167
|
-
// counters. Gating the assignment on `stats` would silently discard
|
|
2168
|
-
// those edits and send the un-rewritten history to the provider.
|
|
2169
|
-
runMessages = preRunRepair.messages;
|
|
2170
|
-
if (
|
|
2171
|
-
preRunRepair.stats.assistantToolResultsMigrated > 0 ||
|
|
2172
|
-
preRunRepair.stats.missingToolResultsInserted > 0 ||
|
|
2173
|
-
preRunRepair.stats.orphanToolResultsDowngraded > 0 ||
|
|
2174
|
-
preRunRepair.stats.consecutiveSameRoleMerged > 0
|
|
2175
|
-
) {
|
|
2176
|
-
rlog.warn(
|
|
2177
|
-
{ phase: "pre_run", ...preRunRepair.stats },
|
|
2178
|
-
"Repaired runtime history before provider call",
|
|
2179
|
-
);
|
|
2180
|
-
}
|
|
2181
|
-
}
|
|
2182
2026
|
|
|
2183
2027
|
// Replace historical web_search_tool_result blocks with text summaries.
|
|
2184
2028
|
// The opaque `encrypted_content` tokens Anthropic attaches to each result
|
|
@@ -2195,12 +2039,12 @@ export async function runAgentLoopImpl(
|
|
|
2195
2039
|
}
|
|
2196
2040
|
|
|
2197
2041
|
// user-prompt-submit hook: plugins may transform `runMessages` right
|
|
2198
|
-
// before the agent loop receives them. Fires once per user turn at
|
|
2199
|
-
//
|
|
2200
|
-
//
|
|
2201
|
-
//
|
|
2202
|
-
//
|
|
2203
|
-
//
|
|
2042
|
+
// before the agent loop receives them. Fires once per user turn at the
|
|
2043
|
+
// primary `agentLoop.run` only — the re-entry / retry calls further down
|
|
2044
|
+
// in this function do not refire it (they're not new user submissions).
|
|
2045
|
+
// Plugins may mutate `ctx.latestMessages` in place OR return a new
|
|
2046
|
+
// context with a fresh array; `runHook` forwards whichever the chain
|
|
2047
|
+
// settles on. Order is plugin registration order.
|
|
2204
2048
|
//
|
|
2205
2049
|
// Fires BEFORE `preRunHistoryLength` is captured so the boundary
|
|
2206
2050
|
// between pre-existing and hook-emitted messages — consumed by the
|
|
@@ -2211,6 +2055,7 @@ export async function runAgentLoopImpl(
|
|
|
2211
2055
|
conversationId: ctx.conversationId,
|
|
2212
2056
|
originalMessages: ctx.messages,
|
|
2213
2057
|
latestMessages: runMessages,
|
|
2058
|
+
logger: rlog,
|
|
2214
2059
|
};
|
|
2215
2060
|
const finalUserPromptCtx = await runHook(
|
|
2216
2061
|
HOOKS.USER_PROMPT_SUBMIT,
|
|
@@ -2234,41 +2079,16 @@ export async function runAgentLoopImpl(
|
|
|
2234
2079
|
turnChannelContext: capturedTurnChannelContext,
|
|
2235
2080
|
turnInterfaceContext: capturedTurnInterfaceContext,
|
|
2236
2081
|
};
|
|
2237
|
-
const eventHandler = (event: AgentEvent) =>
|
|
2082
|
+
const eventHandler = (event: AgentEvent): Promise<void> =>
|
|
2238
2083
|
dispatchAgentEvent(state, deps, event);
|
|
2239
2084
|
emitTerminalExit = async (reason: AgentLoopExitReason): Promise<void> => {
|
|
2240
2085
|
await eventHandler({ type: "agent_loop_exit", reason });
|
|
2241
2086
|
};
|
|
2242
2087
|
|
|
2243
|
-
const onCheckpoint = async (
|
|
2244
|
-
checkpoint: CheckpointInfo,
|
|
2245
|
-
): Promise<CheckpointDecision> => {
|
|
2246
|
-
state.currentTurnToolNames = [];
|
|
2247
|
-
|
|
2088
|
+
const onCheckpoint = async (): Promise<CheckpointDecision> => {
|
|
2248
2089
|
if (ctx.canHandoffAtCheckpoint()) {
|
|
2249
|
-
|
|
2250
|
-
pendingCheckpointYield = "handoff";
|
|
2251
|
-
return "yield";
|
|
2090
|
+
return "handoff";
|
|
2252
2091
|
}
|
|
2253
|
-
|
|
2254
|
-
// Mid-loop token budget check: estimate current context size and
|
|
2255
|
-
// yield if we're approaching the preflight budget. This lets the
|
|
2256
|
-
// conversation-agent-loop run compaction before the provider rejects.
|
|
2257
|
-
if (overflowRecovery.enabled) {
|
|
2258
|
-
const midLoopThreshold =
|
|
2259
|
-
resolveCurrentContextBudget().preflightBudget * 0.85;
|
|
2260
|
-
const estimated = await runTokenEstimatePipeline(checkpoint.history);
|
|
2261
|
-
if (estimated > midLoopThreshold) {
|
|
2262
|
-
rlog.warn(
|
|
2263
|
-
{ phase: "mid-loop", estimated, threshold: midLoopThreshold },
|
|
2264
|
-
"Token estimate approaching budget — yielding for compaction",
|
|
2265
|
-
);
|
|
2266
|
-
yieldedForBudget = true;
|
|
2267
|
-
pendingCheckpointYield = "budget";
|
|
2268
|
-
return "yield";
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
2092
|
return "continue";
|
|
2273
2093
|
};
|
|
2274
2094
|
|
|
@@ -2284,19 +2104,120 @@ export async function runAgentLoopImpl(
|
|
|
2284
2104
|
// and overwrites `turnIndex` with its own tool-use iteration counter.
|
|
2285
2105
|
const loopTurnCtx = buildPluginTurnContext(ctx, reqId);
|
|
2286
2106
|
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2107
|
+
// Hooks for the loop-owned mid-loop compaction. The agent loop owns the
|
|
2108
|
+
// trigger (its budget gate), the `compaction` pipeline call, the result
|
|
2109
|
+
// interpretation (circuit-breaker bookkeeping + the exhaustion decision),
|
|
2110
|
+
// and the inline continue; these callbacks bridge the durable / injection
|
|
2111
|
+
// state the loop is intentionally blind to. Durable persistence and
|
|
2112
|
+
// re-injection stay orchestrator-supplied for now.
|
|
2113
|
+
const midLoopCompaction: MidLoopCompaction = {
|
|
2114
|
+
prepare: (history) => {
|
|
2115
|
+
// Strip injected context so the compactor summarizes the raw
|
|
2116
|
+
// persistent messages, and commit the stripped set to durable state.
|
|
2117
|
+
const rawHistory = stripInjectionsForCompaction(history);
|
|
2118
|
+
ctx.messages = rawHistory;
|
|
2119
|
+
markHistoryStrippedBestEffort(ctx.conversationId, Date.now(), rlog);
|
|
2120
|
+
return {
|
|
2121
|
+
rawHistory,
|
|
2122
|
+
options: {
|
|
2123
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
2124
|
+
force: true,
|
|
2125
|
+
targetInputTokensOverride:
|
|
2126
|
+
resolveCurrentContextBudget().preflightBudget,
|
|
2127
|
+
conversationOriginChannel:
|
|
2128
|
+
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
2129
|
+
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2130
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
2131
|
+
},
|
|
2132
|
+
};
|
|
2133
|
+
},
|
|
2134
|
+
applyResult: async (result, rawHistory) => {
|
|
2135
|
+
await applySuccessfulCompaction(result, rawHistory);
|
|
2136
|
+
reducerCompacted = true;
|
|
2137
|
+
shouldInjectWorkspace = true;
|
|
2138
|
+
},
|
|
2139
|
+
reinject: async () => {
|
|
2140
|
+
// stripInjectionsForCompaction() unconditionally removed the existing
|
|
2141
|
+
// NOW.md block, so re-inject the current content regardless of whether
|
|
2142
|
+
// compaction actually ran.
|
|
2143
|
+
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
2144
|
+
...injectionOpts,
|
|
2145
|
+
pkbContext: currentPkbContent,
|
|
2146
|
+
memoryV2Static: currentMemoryV2Static,
|
|
2147
|
+
nowScratchpad: currentNowContent,
|
|
2148
|
+
workspaceTopLevelContext: shouldInjectWorkspace
|
|
2149
|
+
? ctx.workspaceTopLevelContext
|
|
2150
|
+
: null,
|
|
2151
|
+
// Suppress the chronological-transcript snapshot once the reducer
|
|
2152
|
+
// has collapsed `ctx.messages`; the captured snapshot reflects the
|
|
2153
|
+
// full persisted transcript and would overwrite compaction.
|
|
2154
|
+
slackChronologicalMessages: reducerCompacted
|
|
2155
|
+
? null
|
|
2156
|
+
: injectionOpts.slackChronologicalMessages,
|
|
2157
|
+
mode: currentInjectionMode,
|
|
2158
|
+
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
2159
|
+
});
|
|
2160
|
+
runMessages = injection.messages;
|
|
2161
|
+
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
2162
|
+
ctx.graphMemory.retrackCachedNodes();
|
|
2163
|
+
}
|
|
2164
|
+
const midLoopCompactStrip =
|
|
2165
|
+
stripHistoricalWebSearchResults(runMessages);
|
|
2166
|
+
if (midLoopCompactStrip.stats.blocksStripped > 0) {
|
|
2167
|
+
rlog.info(
|
|
2168
|
+
{ phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
|
|
2169
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
2170
|
+
);
|
|
2171
|
+
runMessages = midLoopCompactStrip.messages;
|
|
2172
|
+
}
|
|
2173
|
+
preRepairMessages = runMessages;
|
|
2174
|
+
preRunHistoryLength = runMessages.length;
|
|
2175
|
+
return runMessages;
|
|
2176
|
+
},
|
|
2177
|
+
};
|
|
2178
|
+
|
|
2179
|
+
/**
|
|
2180
|
+
* Shared closure: runs the agent loop with the orchestrator's turn
|
|
2181
|
+
* context and maps the loop's returned checkpoint pause-reason into the
|
|
2182
|
+
* orchestrator's yield bookkeeping. Returns the updated history so call
|
|
2183
|
+
* sites consume it exactly as before. Pass `compaction` only for the
|
|
2184
|
+
* primary run, where the loop compacts in place when its budget gate
|
|
2185
|
+
* trips; reruns omit it and keep yielding for budget.
|
|
2186
|
+
*/
|
|
2187
|
+
const runAgentLoop = async (
|
|
2188
|
+
msgs: Message[],
|
|
2189
|
+
compaction?: MidLoopCompaction,
|
|
2190
|
+
): Promise<Message[]> => {
|
|
2191
|
+
const { history, exitReason } = await ctx.agentLoop.run(
|
|
2192
|
+
msgs,
|
|
2193
|
+
eventHandler,
|
|
2194
|
+
{
|
|
2195
|
+
signal: abortController.signal,
|
|
2196
|
+
requestId: reqId,
|
|
2197
|
+
onCheckpoint,
|
|
2198
|
+
callSite: turnCallSite,
|
|
2199
|
+
turnContext: loopTurnCtx,
|
|
2200
|
+
overrideProfile: turnOverrideProfile,
|
|
2201
|
+
resolveOverrideProfile: resolveCurrentOverrideProfile,
|
|
2202
|
+
resolveContextWindow,
|
|
2203
|
+
compaction,
|
|
2204
|
+
// memory-v3-live: the latest user message carries the volatile v3
|
|
2205
|
+
// `<memory>` block, so anchor the provider's long-TTL cache breakpoint
|
|
2206
|
+
// on the most recent stable message instead.
|
|
2207
|
+
mutableLatestUserMessage: memoryV3Live,
|
|
2208
|
+
},
|
|
2209
|
+
);
|
|
2210
|
+
if (exitReason === "handoff") {
|
|
2211
|
+
yieldedForHandoff = true;
|
|
2212
|
+
pendingCheckpointYield = "handoff";
|
|
2213
|
+
} else if (exitReason === "budget") {
|
|
2214
|
+
yieldedForBudget = true;
|
|
2215
|
+
pendingCheckpointYield = "budget";
|
|
2216
|
+
}
|
|
2217
|
+
return history;
|
|
2218
|
+
};
|
|
2219
|
+
|
|
2220
|
+
let updatedHistory = await runAgentLoop(runMessages, midLoopCompaction);
|
|
2300
2221
|
|
|
2301
2222
|
rlog.info(
|
|
2302
2223
|
{ resultMessageCount: updatedHistory.length },
|
|
@@ -2308,167 +2229,16 @@ export async function runAgentLoopImpl(
|
|
|
2308
2229
|
pendingCheckpointYield = null;
|
|
2309
2230
|
}
|
|
2310
2231
|
|
|
2311
|
-
//
|
|
2312
|
-
//
|
|
2313
|
-
//
|
|
2314
|
-
//
|
|
2315
|
-
//
|
|
2316
|
-
//
|
|
2317
|
-
let midLoopCompactAttempts = 0;
|
|
2318
|
-
while (
|
|
2319
|
-
yieldedForBudget &&
|
|
2320
|
-
midLoopCompactAttempts <
|
|
2321
|
-
resolveCurrentContextBudget().overflowRecovery.maxAttempts &&
|
|
2322
|
-
!state.contextTooLargeDetected &&
|
|
2323
|
-
!abortController.signal.aborted
|
|
2324
|
-
) {
|
|
2325
|
-
midLoopCompactAttempts++;
|
|
2326
|
-
yieldedForBudget = false;
|
|
2327
|
-
pendingCheckpointYield = null;
|
|
2328
|
-
|
|
2329
|
-
rlog.info(
|
|
2330
|
-
{ phase: "mid-loop-compact" },
|
|
2331
|
-
"Running compaction after checkpoint yield",
|
|
2332
|
-
);
|
|
2333
|
-
|
|
2334
|
-
// Strip injected context from updated history before compacting,
|
|
2335
|
-
// so we compact the "raw" persistent messages.
|
|
2336
|
-
const rawHistory = stripInjectionsForCompaction(updatedHistory);
|
|
2337
|
-
ctx.messages = rawHistory;
|
|
2338
|
-
markHistoryStrippedBestEffort(ctx.conversationId, Date.now(), rlog);
|
|
2339
|
-
|
|
2340
|
-
ctx.emitActivityState(
|
|
2341
|
-
"thinking",
|
|
2342
|
-
"context_compacting",
|
|
2343
|
-
"assistant_turn",
|
|
2344
|
-
reqId,
|
|
2345
|
-
"Compacting context",
|
|
2346
|
-
);
|
|
2347
|
-
let midLoopCompact: Awaited<
|
|
2348
|
-
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2349
|
-
>;
|
|
2350
|
-
try {
|
|
2351
|
-
midLoopCompact = (await runPipeline<CompactionArgs, CompactionResult>(
|
|
2352
|
-
"compaction",
|
|
2353
|
-
getMiddlewaresFor("compaction"),
|
|
2354
|
-
(args) =>
|
|
2355
|
-
defaultCompactionTerminal(args, buildPluginTurnContext(ctx, reqId)),
|
|
2356
|
-
{
|
|
2357
|
-
messages: ctx.messages,
|
|
2358
|
-
signal: abortController.signal,
|
|
2359
|
-
options: {
|
|
2360
|
-
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
2361
|
-
force: true,
|
|
2362
|
-
targetInputTokensOverride:
|
|
2363
|
-
resolveCurrentContextBudget().preflightBudget,
|
|
2364
|
-
conversationOriginChannel:
|
|
2365
|
-
getConversationOriginChannel(ctx.conversationId) ?? undefined,
|
|
2366
|
-
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2367
|
-
},
|
|
2368
|
-
},
|
|
2369
|
-
buildPluginTurnContext(ctx, reqId),
|
|
2370
|
-
DEFAULT_TIMEOUTS.compaction,
|
|
2371
|
-
)) as Awaited<ReturnType<typeof ctx.contextWindowManager.maybeCompact>>;
|
|
2372
|
-
} catch (err) {
|
|
2373
|
-
if (err instanceof PluginTimeoutError) {
|
|
2374
|
-
// Mid-loop compaction timed out. Record the failure for the
|
|
2375
|
-
// circuit breaker and escalate to the convergence loop's more
|
|
2376
|
-
// aggressive reducer tiers (tool-result truncation, media
|
|
2377
|
-
// stubbing, injection downgrade) by flipping the overflow flag
|
|
2378
|
-
// and breaking out of the mid-loop retry. The existing
|
|
2379
|
-
// "exhausted all attempts" block further down handles the
|
|
2380
|
-
// escalation.
|
|
2381
|
-
rlog.warn(
|
|
2382
|
-
{ err, phase: "mid-loop-compact" },
|
|
2383
|
-
"Compaction pipeline timed out — escalating to convergence loop",
|
|
2384
|
-
);
|
|
2385
|
-
await trackCompactionOutcome(ctx, true, onEvent);
|
|
2386
|
-
state.contextTooLargeDetected = true;
|
|
2387
|
-
break;
|
|
2388
|
-
}
|
|
2389
|
-
throw err;
|
|
2390
|
-
}
|
|
2391
|
-
// `force: true` bypasses the cooldown/threshold gates but early returns
|
|
2392
|
-
// for "no eligible messages" / "insufficient messages" still leave
|
|
2393
|
-
// `summaryFailed` undefined. Only track when the summary LLM actually ran.
|
|
2394
|
-
if (midLoopCompact.summaryFailed !== undefined) {
|
|
2395
|
-
await trackCompactionOutcome(
|
|
2396
|
-
ctx,
|
|
2397
|
-
midLoopCompact.summaryFailed,
|
|
2398
|
-
onEvent,
|
|
2399
|
-
);
|
|
2400
|
-
}
|
|
2401
|
-
if (midLoopCompact.compacted) {
|
|
2402
|
-
await applySuccessfulCompaction(midLoopCompact, rawHistory);
|
|
2403
|
-
reducerCompacted = true;
|
|
2404
|
-
shouldInjectWorkspace = true;
|
|
2405
|
-
}
|
|
2406
|
-
|
|
2407
|
-
// Re-inject runtime context and re-enter the agent loop.
|
|
2408
|
-
// stripInjectionsForCompaction() unconditionally removed the existing
|
|
2409
|
-
// NOW.md block from ctx.messages above, so we must always re-inject
|
|
2410
|
-
// the current content regardless of whether compaction actually ran.
|
|
2411
|
-
const injection = await applyRuntimeInjections(ctx.messages, {
|
|
2412
|
-
...injectionOpts,
|
|
2413
|
-
pkbContext: currentPkbContent,
|
|
2414
|
-
memoryV2Static: currentMemoryV2Static,
|
|
2415
|
-
nowScratchpad: currentNowContent,
|
|
2416
|
-
workspaceTopLevelContext: shouldInjectWorkspace
|
|
2417
|
-
? ctx.workspaceTopLevelContext
|
|
2418
|
-
: null,
|
|
2419
|
-
// Suppress the chronological-transcript snapshot once the reducer
|
|
2420
|
-
// has collapsed `ctx.messages`; the captured snapshot reflects the
|
|
2421
|
-
// full persisted transcript and would overwrite compaction.
|
|
2422
|
-
slackChronologicalMessages: reducerCompacted
|
|
2423
|
-
? null
|
|
2424
|
-
: injectionOpts.slackChronologicalMessages,
|
|
2425
|
-
mode: currentInjectionMode,
|
|
2426
|
-
turnContext: buildPluginTurnContext(ctx, reqId),
|
|
2427
|
-
});
|
|
2428
|
-
runMessages = injection.messages;
|
|
2429
|
-
if (isTrustedActor && currentInjectionMode !== "minimal") {
|
|
2430
|
-
ctx.graphMemory.retrackCachedNodes();
|
|
2431
|
-
}
|
|
2432
|
-
const midLoopCompactStrip = stripHistoricalWebSearchResults(runMessages);
|
|
2433
|
-
if (midLoopCompactStrip.stats.blocksStripped > 0) {
|
|
2434
|
-
rlog.info(
|
|
2435
|
-
{ phase: "mid-loop-compact", ...midLoopCompactStrip.stats },
|
|
2436
|
-
"Converted historical web_search_tool_result blocks to text summaries",
|
|
2437
|
-
);
|
|
2438
|
-
runMessages = midLoopCompactStrip.messages;
|
|
2439
|
-
}
|
|
2440
|
-
preRepairMessages = runMessages;
|
|
2441
|
-
preRunHistoryLength = runMessages.length;
|
|
2442
|
-
|
|
2443
|
-
updatedHistory = await ctx.agentLoop.run(
|
|
2444
|
-
runMessages,
|
|
2445
|
-
eventHandler,
|
|
2446
|
-
abortController.signal,
|
|
2447
|
-
reqId,
|
|
2448
|
-
onCheckpoint,
|
|
2449
|
-
turnCallSite,
|
|
2450
|
-
loopTurnCtx,
|
|
2451
|
-
turnOverrideProfile,
|
|
2452
|
-
resolveCurrentMaxInputTokens(),
|
|
2453
|
-
resolveCurrentOverrideProfile,
|
|
2454
|
-
resolveCurrentMaxInputTokens,
|
|
2455
|
-
);
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
|
-
// If mid-loop compaction exhausted all attempts but the agent loop
|
|
2459
|
-
// still yielded (yieldedForBudget is true), the turn is incomplete.
|
|
2460
|
-
// Escalate to the convergence loop's more aggressive reducer tiers
|
|
2461
|
-
// (tool-result truncation, media stubbing, injection downgrade)
|
|
2462
|
-
// instead of silently treating an incomplete turn as done.
|
|
2232
|
+
// The loop compacts in place when its budget gate trips and only yields
|
|
2233
|
+
// `exitReason = "budget"` when that inline compaction timed out or
|
|
2234
|
+
// exhausted its retry budget (the `reinject` hook has already restored
|
|
2235
|
+
// runtime context for the productive case). Escalate to the convergence
|
|
2236
|
+
// loop's more aggressive reducer tiers so a half-finished turn doesn't
|
|
2237
|
+
// reach the user.
|
|
2463
2238
|
if (yieldedForBudget && !abortController.signal.aborted) {
|
|
2464
2239
|
rlog.warn(
|
|
2465
|
-
{
|
|
2466
|
-
|
|
2467
|
-
midLoopCompactAttempts,
|
|
2468
|
-
maxAttempts:
|
|
2469
|
-
resolveCurrentContextBudget().overflowRecovery.maxAttempts,
|
|
2470
|
-
},
|
|
2471
|
-
"Mid-loop compaction exhausted all attempts — escalating to convergence loop",
|
|
2240
|
+
{ phase: "mid-loop-compact" },
|
|
2241
|
+
"Inline compaction could not get under budget — escalating to convergence loop",
|
|
2472
2242
|
);
|
|
2473
2243
|
state.contextTooLargeDetected = true;
|
|
2474
2244
|
}
|
|
@@ -2482,15 +2252,15 @@ export async function runAgentLoopImpl(
|
|
|
2482
2252
|
{ phase: "retry" },
|
|
2483
2253
|
"Provider ordering error detected, attempting one-shot deep-repair retry",
|
|
2484
2254
|
);
|
|
2485
|
-
// Design note: deep-repair intentionally
|
|
2486
|
-
//
|
|
2487
|
-
//
|
|
2488
|
-
//
|
|
2489
|
-
// the original drift. Plugins can
|
|
2490
|
-
// pre-run repair via the
|
|
2491
|
-
//
|
|
2492
|
-
//
|
|
2493
|
-
//
|
|
2255
|
+
// Design note: deep-repair intentionally stays a direct call rather
|
|
2256
|
+
// than running through the `user-prompt-submit` hook chain. Deep-repair
|
|
2257
|
+
// is a recovery-only path triggered by a provider ordering error — it
|
|
2258
|
+
// must be deterministic and unaffected by user hooks that might have
|
|
2259
|
+
// caused (or be unable to recover from) the original drift. Plugins can
|
|
2260
|
+
// already observe / transform the pre-run repair via the
|
|
2261
|
+
// `user-prompt-submit` hook (the default history-repair plugin runs
|
|
2262
|
+
// `repairHistory` there); widening that surface to deep-repair is
|
|
2263
|
+
// intentionally deferred until there's a concrete plugin-level use case.
|
|
2494
2264
|
const retryRepair = deepRepairHistory(runMessages);
|
|
2495
2265
|
runMessages = retryRepair.messages;
|
|
2496
2266
|
const retryStrip = stripHistoricalWebSearchResults(runMessages);
|
|
@@ -2500,19 +2270,7 @@ export async function runAgentLoopImpl(
|
|
|
2500
2270
|
state.orderingErrorDetected = false;
|
|
2501
2271
|
state.deferredOrderingError = null;
|
|
2502
2272
|
|
|
2503
|
-
updatedHistory = await
|
|
2504
|
-
runMessages,
|
|
2505
|
-
eventHandler,
|
|
2506
|
-
abortController.signal,
|
|
2507
|
-
reqId,
|
|
2508
|
-
onCheckpoint,
|
|
2509
|
-
turnCallSite,
|
|
2510
|
-
loopTurnCtx,
|
|
2511
|
-
turnOverrideProfile,
|
|
2512
|
-
resolveCurrentMaxInputTokens(),
|
|
2513
|
-
resolveCurrentOverrideProfile,
|
|
2514
|
-
resolveCurrentMaxInputTokens,
|
|
2515
|
-
);
|
|
2273
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2516
2274
|
|
|
2517
2275
|
if (state.orderingErrorDetected) {
|
|
2518
2276
|
rlog.error(
|
|
@@ -2571,19 +2329,7 @@ export async function runAgentLoopImpl(
|
|
|
2571
2329
|
};
|
|
2572
2330
|
});
|
|
2573
2331
|
runMessages = ctx.messages;
|
|
2574
|
-
updatedHistory = await
|
|
2575
|
-
runMessages,
|
|
2576
|
-
eventHandler,
|
|
2577
|
-
abortController.signal,
|
|
2578
|
-
reqId,
|
|
2579
|
-
onCheckpoint,
|
|
2580
|
-
turnCallSite,
|
|
2581
|
-
loopTurnCtx,
|
|
2582
|
-
turnOverrideProfile,
|
|
2583
|
-
resolveCurrentMaxInputTokens(),
|
|
2584
|
-
resolveCurrentOverrideProfile,
|
|
2585
|
-
resolveCurrentMaxInputTokens,
|
|
2586
|
-
);
|
|
2332
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2587
2333
|
if (state.imageTooLargeDetected) {
|
|
2588
2334
|
rlog.error(
|
|
2589
2335
|
{ phase: "image-recovery" },
|
|
@@ -2703,7 +2449,7 @@ export async function runAgentLoopImpl(
|
|
|
2703
2449
|
"Emergency mid-turn compaction succeeded — bypassing reducer tiers",
|
|
2704
2450
|
);
|
|
2705
2451
|
if (emergencyResult.summaryFailed !== undefined) {
|
|
2706
|
-
await
|
|
2452
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2707
2453
|
ctx,
|
|
2708
2454
|
emergencyResult.summaryFailed,
|
|
2709
2455
|
onEvent,
|
|
@@ -2744,12 +2490,9 @@ export async function runAgentLoopImpl(
|
|
|
2744
2490
|
"Context too large — applying next reducer tier",
|
|
2745
2491
|
);
|
|
2746
2492
|
|
|
2747
|
-
ctx.emitActivityState(
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
"assistant_turn",
|
|
2751
|
-
reqId,
|
|
2752
|
-
);
|
|
2493
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
2494
|
+
requestId: reqId,
|
|
2495
|
+
});
|
|
2753
2496
|
const convergenceCompactionBasis = ctx.messages;
|
|
2754
2497
|
const step = await reduceContextOverflow(
|
|
2755
2498
|
convergenceCompactionBasis,
|
|
@@ -2765,6 +2508,7 @@ export async function runAgentLoopImpl(
|
|
|
2765
2508
|
ctx.contextWindowManager.maybeCompact(msgs, signal!, {
|
|
2766
2509
|
...(opts ?? {}),
|
|
2767
2510
|
overrideProfile: resolveCurrentOverrideProfile() ?? null,
|
|
2511
|
+
actorTrustClass: ctx.trustContext?.trustClass,
|
|
2768
2512
|
}),
|
|
2769
2513
|
abortController.signal,
|
|
2770
2514
|
);
|
|
@@ -2781,7 +2525,7 @@ export async function runAgentLoopImpl(
|
|
|
2781
2525
|
step.compactionResult &&
|
|
2782
2526
|
step.compactionResult.summaryFailed !== undefined
|
|
2783
2527
|
) {
|
|
2784
|
-
await
|
|
2528
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2785
2529
|
ctx,
|
|
2786
2530
|
step.compactionResult.summaryFailed,
|
|
2787
2531
|
onEvent,
|
|
@@ -2831,19 +2575,7 @@ export async function runAgentLoopImpl(
|
|
|
2831
2575
|
state.contextTooLargeDetected = false;
|
|
2832
2576
|
yieldedForBudget = false;
|
|
2833
2577
|
|
|
2834
|
-
updatedHistory = await
|
|
2835
|
-
runMessages,
|
|
2836
|
-
eventHandler,
|
|
2837
|
-
abortController.signal,
|
|
2838
|
-
reqId,
|
|
2839
|
-
onCheckpoint,
|
|
2840
|
-
turnCallSite,
|
|
2841
|
-
loopTurnCtx,
|
|
2842
|
-
turnOverrideProfile,
|
|
2843
|
-
resolveCurrentMaxInputTokens(),
|
|
2844
|
-
resolveCurrentOverrideProfile,
|
|
2845
|
-
resolveCurrentMaxInputTokens,
|
|
2846
|
-
);
|
|
2578
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
2847
2579
|
|
|
2848
2580
|
// If the rerun still yields at checkpoint, the turn is still
|
|
2849
2581
|
// incomplete — continue reducing through the remaining tiers
|
|
@@ -2884,12 +2616,9 @@ export async function runAgentLoopImpl(
|
|
|
2884
2616
|
|
|
2885
2617
|
if (action === "auto_compress_latest_turn") {
|
|
2886
2618
|
// Auto-compress without asking — users opt out via the "drop" policy.
|
|
2887
|
-
ctx.emitActivityState(
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
"assistant_turn",
|
|
2891
|
-
reqId,
|
|
2892
|
-
);
|
|
2619
|
+
ctx.emitActivityState("thinking", "context_compacting", {
|
|
2620
|
+
requestId: reqId,
|
|
2621
|
+
});
|
|
2893
2622
|
let emergencyCompact: Awaited<
|
|
2894
2623
|
ReturnType<typeof ctx.contextWindowManager.maybeCompact>
|
|
2895
2624
|
> | null = null;
|
|
@@ -2931,7 +2660,11 @@ export async function runAgentLoopImpl(
|
|
|
2931
2660
|
{ err, phase: "emergency-compaction" },
|
|
2932
2661
|
"Emergency compaction pipeline timed out — continuing with overflow fallback",
|
|
2933
2662
|
);
|
|
2934
|
-
await
|
|
2663
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2664
|
+
ctx,
|
|
2665
|
+
true,
|
|
2666
|
+
onEvent,
|
|
2667
|
+
);
|
|
2935
2668
|
emergencyCompact = null;
|
|
2936
2669
|
} else {
|
|
2937
2670
|
throw err;
|
|
@@ -2943,7 +2676,7 @@ export async function runAgentLoopImpl(
|
|
|
2943
2676
|
emergencyCompact &&
|
|
2944
2677
|
emergencyCompact.summaryFailed !== undefined
|
|
2945
2678
|
) {
|
|
2946
|
-
await
|
|
2679
|
+
await ctx.agentLoop.compactionCircuit.recordOutcome(
|
|
2947
2680
|
ctx,
|
|
2948
2681
|
emergencyCompact.summaryFailed,
|
|
2949
2682
|
onEvent,
|
|
@@ -2987,19 +2720,7 @@ export async function runAgentLoopImpl(
|
|
|
2987
2720
|
preRunHistoryLength = runMessages.length;
|
|
2988
2721
|
state.contextTooLargeDetected = false;
|
|
2989
2722
|
|
|
2990
|
-
updatedHistory = await
|
|
2991
|
-
runMessages,
|
|
2992
|
-
eventHandler,
|
|
2993
|
-
abortController.signal,
|
|
2994
|
-
reqId,
|
|
2995
|
-
onCheckpoint,
|
|
2996
|
-
turnCallSite,
|
|
2997
|
-
loopTurnCtx,
|
|
2998
|
-
turnOverrideProfile,
|
|
2999
|
-
resolveCurrentMaxInputTokens(),
|
|
3000
|
-
resolveCurrentOverrideProfile,
|
|
3001
|
-
resolveCurrentMaxInputTokens,
|
|
3002
|
-
);
|
|
2723
|
+
updatedHistory = await runAgentLoop(runMessages);
|
|
3003
2724
|
}
|
|
3004
2725
|
// action === "fail_gracefully" falls through to the final error below
|
|
3005
2726
|
}
|
|
@@ -3389,7 +3110,10 @@ export async function runAgentLoopImpl(
|
|
|
3389
3110
|
// so the client can re-enable the UI without delay.
|
|
3390
3111
|
if (abortController.signal.aborted) {
|
|
3391
3112
|
syncLastAssistantMessageToDisk();
|
|
3392
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3113
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3114
|
+
anchor: "global",
|
|
3115
|
+
requestId: reqId,
|
|
3116
|
+
});
|
|
3393
3117
|
ctx.traceEmitter.emit(
|
|
3394
3118
|
"generation_cancelled",
|
|
3395
3119
|
"Generation cancelled by user",
|
|
@@ -3433,7 +3157,10 @@ export async function runAgentLoopImpl(
|
|
|
3433
3157
|
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3434
3158
|
pendingCheckpointYield = null;
|
|
3435
3159
|
}
|
|
3436
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3160
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3161
|
+
anchor: "global",
|
|
3162
|
+
requestId: reqId,
|
|
3163
|
+
});
|
|
3437
3164
|
ctx.traceEmitter.emit(
|
|
3438
3165
|
"generation_cancelled",
|
|
3439
3166
|
"Generation cancelled by user",
|
|
@@ -3474,7 +3201,10 @@ export async function runAgentLoopImpl(
|
|
|
3474
3201
|
});
|
|
3475
3202
|
publishLoopMessagesChanged();
|
|
3476
3203
|
} else {
|
|
3477
|
-
ctx.emitActivityState("idle", "message_complete",
|
|
3204
|
+
ctx.emitActivityState("idle", "message_complete", {
|
|
3205
|
+
anchor: "global",
|
|
3206
|
+
requestId: reqId,
|
|
3207
|
+
});
|
|
3478
3208
|
ctx.traceEmitter.emit(
|
|
3479
3209
|
"message_complete",
|
|
3480
3210
|
"Message processing complete",
|
|
@@ -3497,42 +3227,6 @@ export async function runAgentLoopImpl(
|
|
|
3497
3227
|
: {}),
|
|
3498
3228
|
});
|
|
3499
3229
|
publishLoopMessagesChanged();
|
|
3500
|
-
|
|
3501
|
-
// Proactive artifact: fire once when the processed turn was the 4th user message.
|
|
3502
|
-
// Only trigger for real user-authored turns (not subagent/system messages).
|
|
3503
|
-
{
|
|
3504
|
-
const paConv = getConversation(ctx.conversationId);
|
|
3505
|
-
if (
|
|
3506
|
-
paConv &&
|
|
3507
|
-
paConv.conversationType === "standard" &&
|
|
3508
|
-
options?.isUserMessage
|
|
3509
|
-
) {
|
|
3510
|
-
void (async () => {
|
|
3511
|
-
try {
|
|
3512
|
-
if (hasProactiveArtifactCompleted()) return;
|
|
3513
|
-
const userMsg = getMessageById(
|
|
3514
|
-
userMessageId,
|
|
3515
|
-
ctx.conversationId,
|
|
3516
|
-
);
|
|
3517
|
-
if (!userMsg) return;
|
|
3518
|
-
if (!tryClaimProactiveArtifactTrigger(userMsg.createdAt))
|
|
3519
|
-
return;
|
|
3520
|
-
await runProactiveArtifactJob({
|
|
3521
|
-
conversationId: ctx.conversationId,
|
|
3522
|
-
userMessageCutoff: userMsg.createdAt,
|
|
3523
|
-
assistantMessageId: state.lastAssistantMessageId,
|
|
3524
|
-
suppressAppBuild: state.appBuildToolUsedThisRun,
|
|
3525
|
-
broadcastMessage,
|
|
3526
|
-
});
|
|
3527
|
-
} catch (err) {
|
|
3528
|
-
log.warn(
|
|
3529
|
-
{ err, conversationId: ctx.conversationId },
|
|
3530
|
-
"Proactive artifact trigger failed",
|
|
3531
|
-
);
|
|
3532
|
-
}
|
|
3533
|
-
})();
|
|
3534
|
-
}
|
|
3535
|
-
}
|
|
3536
3230
|
}
|
|
3537
3231
|
}
|
|
3538
3232
|
|
|
@@ -3569,7 +3263,10 @@ export async function runAgentLoopImpl(
|
|
|
3569
3263
|
await emitTerminalExit?.("aborted_after_checkpoint");
|
|
3570
3264
|
pendingCheckpointYield = null;
|
|
3571
3265
|
}
|
|
3572
|
-
ctx.emitActivityState("idle", "generation_cancelled",
|
|
3266
|
+
ctx.emitActivityState("idle", "generation_cancelled", {
|
|
3267
|
+
anchor: "global",
|
|
3268
|
+
requestId: reqId,
|
|
3269
|
+
});
|
|
3573
3270
|
rlog.info("Generation cancelled by user");
|
|
3574
3271
|
ctx.traceEmitter.emit(
|
|
3575
3272
|
"generation_cancelled",
|
|
@@ -3585,7 +3282,10 @@ export async function runAgentLoopImpl(
|
|
|
3585
3282
|
});
|
|
3586
3283
|
publishLoopMessagesChanged();
|
|
3587
3284
|
} else {
|
|
3588
|
-
ctx.emitActivityState("idle", "error_terminal",
|
|
3285
|
+
ctx.emitActivityState("idle", "error_terminal", {
|
|
3286
|
+
anchor: "global",
|
|
3287
|
+
requestId: reqId,
|
|
3288
|
+
});
|
|
3589
3289
|
const message = err instanceof Error ? err.message : String(err);
|
|
3590
3290
|
const errorClass = err instanceof Error ? err.constructor.name : "Error";
|
|
3591
3291
|
rlog.error({ err }, "Conversation processing error");
|