@vellumai/assistant 0.8.0 → 0.8.2
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 +11 -0
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +80 -5
- package/README.md +2 -2
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +21 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +4462 -991
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +135 -14
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +129 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +137 -2
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +35 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +278 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +159 -18
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -4
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +93 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +80 -3
- package/src/__tests__/conversation-fork-crud.test.ts +323 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +54 -18
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +297 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +25 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +80 -13
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -8
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +482 -0
- package/src/__tests__/filing-service.test.ts +163 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +42 -69
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +162 -0
- package/src/__tests__/host-app-control-proxy.test.ts +365 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +156 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +410 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +248 -0
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +157 -39
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +107 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +190 -2
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +222 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +145 -14
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +863 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +48 -19
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +41 -38
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +31 -4
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -18
- package/src/__tests__/plugin-types.test.ts +15 -23
- package/src/__tests__/process-message-background-slack.test.ts +53 -0
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +20 -12
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +151 -0
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +208 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +12 -4
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -12
- package/src/__tests__/skill-load-tool.test.ts +29 -93
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +143 -5
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +108 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +170 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +241 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/image-optimize.ts +13 -5
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +74 -36
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +109 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +578 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +478 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +429 -434
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +342 -304
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +40 -6
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -2
- package/src/config/feature-flag-registry.json +57 -1
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +140 -52
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +8 -7
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +81 -0
- package/src/config/schemas/llm.ts +55 -2
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/config/skills.ts +3 -96
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1334
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +113 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +183 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +26 -30
- package/src/daemon/config-watcher.ts +94 -29
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +293 -103
- package/src/daemon/conversation-error.ts +188 -33
- package/src/daemon/conversation-lifecycle.ts +80 -26
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +85 -31
- package/src/daemon/conversation-runtime-assembly.ts +30 -6
- package/src/daemon/conversation-slash.ts +184 -25
- package/src/daemon/conversation-store.ts +24 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +63 -21
- package/src/daemon/conversation.ts +81 -10
- package/src/daemon/external-plugins-bootstrap.ts +231 -185
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +13 -130
- package/src/daemon/handlers/config-slack-channel.ts +25 -10
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +166 -84
- package/src/daemon/history-repair.ts +61 -7
- package/src/daemon/host-app-control-proxy.ts +129 -29
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +79 -70
- package/src/daemon/meet-host-supervisor.ts +20 -19
- package/src/daemon/memory-v2-startup.ts +58 -2
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +37 -9
- package/src/daemon/message-types/messages.ts +70 -1
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +61 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +77 -26
- package/src/daemon/server.ts +34 -20
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +79 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +444 -0
- package/src/heartbeat/heartbeat-run-store.ts +3 -1
- package/src/heartbeat/heartbeat-service.ts +189 -127
- package/src/home/__tests__/feed-types.test.ts +99 -127
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +41 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +2 -3
- package/src/index.ts +18 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +264 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +318 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +211 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +80 -8
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +17 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +368 -22
- package/src/memory/conversation-queries.ts +116 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +20 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +6 -5
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +92 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +45 -6
- package/src/memory/indexer.ts +51 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +86 -15
- package/src/memory/jobs/embed-concept-page.ts +65 -20
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +57 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +324 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +64 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +175 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +107 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +19 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +13 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +36 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +27 -0
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -12
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +726 -18
- package/src/memory/v2/__tests__/migration.test.ts +94 -3
- package/src/memory/v2/__tests__/page-index.test.ts +360 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +309 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +138 -3
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +531 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +445 -11
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -109
- package/src/memory/v2/migration.ts +147 -20
- package/src/memory/v2/page-index.ts +221 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +195 -0
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +234 -93
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +323 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +204 -30
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +4 -3
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +48 -2
- package/src/notifications/home-feed-side-effect.ts +165 -0
- package/src/notifications/signal.ts +8 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +14 -0
- package/src/permissions/ipc-risk-types.ts +3 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +46 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +144 -0
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +55 -6
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +367 -0
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +74 -53
- package/src/plugins/user-loader.ts +85 -43
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +49 -9
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +117 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +72 -154
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +303 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +123 -54
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +170 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +210 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +401 -0
- package/src/providers/inference/resolve-auth.ts +73 -0
- package/src/providers/model-catalog.ts +386 -6
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +151 -159
- package/src/providers/retry.ts +65 -11
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +64 -7
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +311 -9
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +3 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +21 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +268 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +319 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +280 -4
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +70 -3
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +12 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +156 -0
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +233 -0
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +47 -85
- package/src/runtime/routes/conversation-query-routes.ts +350 -97
- package/src/runtime/routes/conversation-routes.ts +121 -21
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +248 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +118 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +42 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +285 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +84 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +361 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +7 -13
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +3 -1
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1097 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +79 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +93 -1
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +117 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +208 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/sequence/engine.ts +38 -40
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +28 -15
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +29 -14
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +14 -6
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +323 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +94 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +94 -5
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +117 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +95 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +46 -5
- package/src/workspace/migrations/types.ts +17 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/context-window-manager.test.ts +0 -2093
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assistant-driven context compaction.
|
|
3
|
+
*
|
|
4
|
+
* When a conversation grows long, we hand the model the entire conversation
|
|
5
|
+
* plus an appended instruction message and let it write its own summary,
|
|
6
|
+
* choose its own cut point, and decide which images to retain.
|
|
7
|
+
*
|
|
8
|
+
* The instruction message is appended as a `user`-role message at the tail
|
|
9
|
+
* so the full conversation prefix (system prompt + tools + messages) remains
|
|
10
|
+
* cacheable across compaction calls.
|
|
11
|
+
*
|
|
12
|
+
* The model responds with a `<compaction_result>` XML block. We parse it,
|
|
13
|
+
* resolve `tail_start` to a message index, re-attach any retained images,
|
|
14
|
+
* and rebuild the conversation as:
|
|
15
|
+
*
|
|
16
|
+
* [<assistant summary>, <retained-image user message?>, ...tail]
|
|
17
|
+
*
|
|
18
|
+
* On any parse or resolution failure we abort the compaction and return
|
|
19
|
+
* `compacted: false` — never silently lose messages.
|
|
20
|
+
*/
|
|
21
|
+
import { optimizeImageForTransport } from "../agent/image-optimize.js";
|
|
22
|
+
import type { CompactionConfig } from "../config/schemas/compaction.js";
|
|
23
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
24
|
+
import { stripInjectionsForCompaction } from "../daemon/conversation-runtime-assembly.js";
|
|
25
|
+
import {
|
|
26
|
+
getAttachmentContent,
|
|
27
|
+
getAttachmentMetadataForMessage,
|
|
28
|
+
} from "../memory/attachments-store.js";
|
|
29
|
+
import { getMessages } from "../memory/conversation-crud.js";
|
|
30
|
+
import type {
|
|
31
|
+
ContentBlock,
|
|
32
|
+
ImageContent,
|
|
33
|
+
Message,
|
|
34
|
+
Provider,
|
|
35
|
+
ProviderResponse,
|
|
36
|
+
ToolDefinition,
|
|
37
|
+
} from "../providers/types.js";
|
|
38
|
+
import { getLogger } from "../util/logger.js";
|
|
39
|
+
import { estimatePromptTokens } from "./token-estimator.js";
|
|
40
|
+
|
|
41
|
+
const log = getLogger("compactor");
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Stable call-site identifier used when invoking the provider for a
|
|
45
|
+
* compaction pass. Using `mainAgent` (rather than a dedicated
|
|
46
|
+
* `conversationCompaction` site) keeps the resolved provider/model/system
|
|
47
|
+
* prompt/tools identical to the agent's last turn, so the prefix cache hit
|
|
48
|
+
* rate is maximized — the compaction-instruction user message is the only
|
|
49
|
+
* new token sequence.
|
|
50
|
+
*/
|
|
51
|
+
const COMPACTION_CALL_SITE: LLMCallSite = "mainAgent";
|
|
52
|
+
|
|
53
|
+
const RESULT_TAG_OPEN = "<compaction_result>";
|
|
54
|
+
const RESULT_TAG_CLOSE = "</compaction_result>";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generic compaction instruction. Used when `compaction.prompt` is unset.
|
|
58
|
+
*
|
|
59
|
+
* `{image_manifest}` is the only interpolation point. Custom prompts in
|
|
60
|
+
* `config.json` go through the same interpolation, so override authors can
|
|
61
|
+
* place the placeholder wherever they want.
|
|
62
|
+
*/
|
|
63
|
+
export const DEFAULT_COMPACTION_PROMPT = `<compaction_instructions>
|
|
64
|
+
This conversation is getting long. It's time to run a compaction pass.
|
|
65
|
+
|
|
66
|
+
You have the full conversation in your context right now. Your job is to
|
|
67
|
+
compress the older parts into a summary while preserving recent messages
|
|
68
|
+
exactly as they are.
|
|
69
|
+
|
|
70
|
+
Write the summary in YOUR voice — as if you're remembering this conversation,
|
|
71
|
+
not writing meeting notes about it. Prioritize:
|
|
72
|
+
- Decisions made and commitments given
|
|
73
|
+
- Key context that's still relevant going forward
|
|
74
|
+
- Emotional moments that shaped the conversation's direction
|
|
75
|
+
- Exact quotes when the specific wording matters
|
|
76
|
+
- Project/task state changes
|
|
77
|
+
|
|
78
|
+
Compress aggressively:
|
|
79
|
+
- Repeated debugging or troubleshooting attempts → just the outcome
|
|
80
|
+
- Tool call outputs → results only, not raw data
|
|
81
|
+
- Intermediate states superseded by later states
|
|
82
|
+
- Back-and-forth deliberation → just the conclusion
|
|
83
|
+
|
|
84
|
+
For picking where to cut between summary and preserved tail:
|
|
85
|
+
- Find the last major topic shift or energy change
|
|
86
|
+
- Keep the active thread of conversation fully intact
|
|
87
|
+
- When in doubt, preserve more rather than less
|
|
88
|
+
- Never cut in the middle of an ongoing discussion
|
|
89
|
+
|
|
90
|
+
IMAGE MANIFEST (images in this conversation):
|
|
91
|
+
{image_manifest}
|
|
92
|
+
|
|
93
|
+
If any images from the summarized portion are still relevant to the
|
|
94
|
+
ongoing conversation, include them in retained_images by filename.
|
|
95
|
+
|
|
96
|
+
Output your result in this exact format:
|
|
97
|
+
|
|
98
|
+
<compaction_result>
|
|
99
|
+
<summary>
|
|
100
|
+
Your summary in your voice. Aim for 2000-4000 tokens — rich enough
|
|
101
|
+
to preserve what matters, compact enough to free real space.
|
|
102
|
+
</summary>
|
|
103
|
+
|
|
104
|
+
<key_state>
|
|
105
|
+
Short structured list of anything PENDING from this conversation:
|
|
106
|
+
active decisions, open questions, commitments, project states.
|
|
107
|
+
</key_state>
|
|
108
|
+
|
|
109
|
+
<retained_images>
|
|
110
|
+
<image file="filename.ext" />
|
|
111
|
+
(only images from BEFORE the tail that are still contextually important)
|
|
112
|
+
(omit this section entirely if no images need retention)
|
|
113
|
+
</retained_images>
|
|
114
|
+
|
|
115
|
+
<tail_start
|
|
116
|
+
timestamp="[exact timestamp from the turn_context of the first message to preserve verbatim]"
|
|
117
|
+
preview="[first ~60 characters of that message for verification]" />
|
|
118
|
+
</compaction_result>
|
|
119
|
+
</compaction_instructions>`;
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Public types
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
export interface CompactionRunArgs {
|
|
126
|
+
conversationId: string;
|
|
127
|
+
messages: Message[];
|
|
128
|
+
provider: Provider;
|
|
129
|
+
systemPrompt: string;
|
|
130
|
+
tools?: ToolDefinition[];
|
|
131
|
+
compaction: CompactionConfig;
|
|
132
|
+
/** Effective context window for the conversation (in tokens). */
|
|
133
|
+
maxInputTokens: number;
|
|
134
|
+
/** Pre-computed estimated input tokens for the live history. */
|
|
135
|
+
previousEstimatedInputTokens: number;
|
|
136
|
+
/** Skip the autoThreshold check — fire compaction unconditionally. */
|
|
137
|
+
force?: boolean;
|
|
138
|
+
signal?: AbortSignal;
|
|
139
|
+
overrideProfile?: string | null;
|
|
140
|
+
/**
|
|
141
|
+
* Number of leading non-persisted messages (e.g. inherited summary from a
|
|
142
|
+
* parent fork). Compacted-persisted-count subtracts this so the DB
|
|
143
|
+
* `contextCompactedMessageCount` only advances by rows that actually have
|
|
144
|
+
* DB counterparts.
|
|
145
|
+
*/
|
|
146
|
+
nonPersistedPrefixCount?: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface CompactionRunResult {
|
|
150
|
+
messages: Message[];
|
|
151
|
+
compacted: boolean;
|
|
152
|
+
previousEstimatedInputTokens: number;
|
|
153
|
+
estimatedInputTokens: number;
|
|
154
|
+
maxInputTokens: number;
|
|
155
|
+
thresholdTokens: number;
|
|
156
|
+
compactedMessages: number;
|
|
157
|
+
compactedPersistedMessages: number;
|
|
158
|
+
summaryCalls: number;
|
|
159
|
+
summaryInputTokens: number;
|
|
160
|
+
summaryOutputTokens: number;
|
|
161
|
+
summaryModel: string;
|
|
162
|
+
summaryCallSite?: LLMCallSite;
|
|
163
|
+
summaryOverrideProfile?: string | null;
|
|
164
|
+
summaryCacheCreationInputTokens?: number;
|
|
165
|
+
summaryCacheReadInputTokens?: number;
|
|
166
|
+
summaryRawResponses?: unknown[];
|
|
167
|
+
summaryText: string;
|
|
168
|
+
/** Inline structured pending state from the model's `<key_state>` block. */
|
|
169
|
+
keyState?: string;
|
|
170
|
+
reason?: string;
|
|
171
|
+
/** True when the provider call threw and no compaction was applied. */
|
|
172
|
+
summaryFailed?: boolean;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface ParsedCompactionResult {
|
|
176
|
+
summary: string;
|
|
177
|
+
keyState: string;
|
|
178
|
+
retainedImageFilenames: string[];
|
|
179
|
+
tailStartTimestamp: string;
|
|
180
|
+
tailStartPreview: string;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// XML parser
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Extract the `<compaction_result>` block from raw assistant output and
|
|
189
|
+
* pull out `<summary>`, `<key_state>`, `<retained_images>` (filenames),
|
|
190
|
+
* and `<tail_start>` (timestamp + preview).
|
|
191
|
+
*
|
|
192
|
+
* Lenient by design — the model may wrap the block in narration, may omit
|
|
193
|
+
* `<retained_images>`, and may produce slightly malformed inner tags. We
|
|
194
|
+
* accept any of those. Returns `null` only when the required fields
|
|
195
|
+
* (summary + tail_start.timestamp) are missing.
|
|
196
|
+
*/
|
|
197
|
+
export function parseCompactionResult(
|
|
198
|
+
raw: string,
|
|
199
|
+
): ParsedCompactionResult | null {
|
|
200
|
+
const openIdx = raw.indexOf(RESULT_TAG_OPEN);
|
|
201
|
+
if (openIdx < 0) return null;
|
|
202
|
+
const closeIdx = raw.lastIndexOf(RESULT_TAG_CLOSE);
|
|
203
|
+
const inner =
|
|
204
|
+
closeIdx > openIdx
|
|
205
|
+
? raw.slice(openIdx + RESULT_TAG_OPEN.length, closeIdx)
|
|
206
|
+
: raw.slice(openIdx + RESULT_TAG_OPEN.length);
|
|
207
|
+
|
|
208
|
+
const summary = extractTagContent(inner, "summary")?.trim() ?? "";
|
|
209
|
+
if (summary.length === 0) return null;
|
|
210
|
+
|
|
211
|
+
const keyState = extractTagContent(inner, "key_state")?.trim() ?? "";
|
|
212
|
+
|
|
213
|
+
const tail = extractTailStart(inner);
|
|
214
|
+
if (!tail || tail.timestamp.length === 0) return null;
|
|
215
|
+
|
|
216
|
+
const retainedImageFilenames = extractRetainedImages(inner);
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
summary,
|
|
220
|
+
keyState,
|
|
221
|
+
retainedImageFilenames,
|
|
222
|
+
tailStartTimestamp: tail.timestamp,
|
|
223
|
+
tailStartPreview: tail.preview,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function extractTagContent(haystack: string, tag: string): string | null {
|
|
228
|
+
const open = `<${tag}>`;
|
|
229
|
+
const close = `</${tag}>`;
|
|
230
|
+
const openIdx = haystack.indexOf(open);
|
|
231
|
+
if (openIdx < 0) return null;
|
|
232
|
+
const closeIdx = haystack.indexOf(close, openIdx + open.length);
|
|
233
|
+
if (closeIdx < 0) return null;
|
|
234
|
+
return haystack.slice(openIdx + open.length, closeIdx);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function extractTailStart(
|
|
238
|
+
inner: string,
|
|
239
|
+
): { timestamp: string; preview: string } | null {
|
|
240
|
+
// Match `<tail_start ... />` or `<tail_start ...></tail_start>` with
|
|
241
|
+
// attributes in any order. We require at least `timestamp="..."`.
|
|
242
|
+
const tagMatch = inner.match(
|
|
243
|
+
/<tail_start\b([\s\S]*?)(?:\/>|<\/tail_start>)/i,
|
|
244
|
+
);
|
|
245
|
+
if (!tagMatch) return null;
|
|
246
|
+
const attrs = tagMatch[1];
|
|
247
|
+
const timestamp = extractAttr(attrs, "timestamp") ?? "";
|
|
248
|
+
const preview = extractAttr(attrs, "preview") ?? "";
|
|
249
|
+
return { timestamp, preview };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function extractAttr(attrs: string, name: string): string | null {
|
|
253
|
+
const pattern = new RegExp(`${name}\\s*=\\s*"([^"]*)"`, "i");
|
|
254
|
+
const m = attrs.match(pattern);
|
|
255
|
+
return m ? m[1] : null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function extractRetainedImages(inner: string): string[] {
|
|
259
|
+
const block = extractTagContent(inner, "retained_images");
|
|
260
|
+
if (block == null) return [];
|
|
261
|
+
const out: string[] = [];
|
|
262
|
+
const seen = new Set<string>();
|
|
263
|
+
const re = /<image\b[^>]*\bfile\s*=\s*"([^"]+)"[^>]*\/?>/gi;
|
|
264
|
+
let m: RegExpExecArray | null;
|
|
265
|
+
while ((m = re.exec(block)) !== null) {
|
|
266
|
+
const name = m[1].trim();
|
|
267
|
+
if (name.length === 0 || seen.has(name)) continue;
|
|
268
|
+
seen.add(name);
|
|
269
|
+
out.push(name);
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// Image manifest
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
interface ManifestEntry {
|
|
279
|
+
filename: string;
|
|
280
|
+
attachmentId: string;
|
|
281
|
+
role: "user" | "assistant" | string;
|
|
282
|
+
timestamp: number;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Walk the DB rows for the conversation and build an entry per image
|
|
287
|
+
* attachment. Returns entries sorted by message createdAt ascending. The
|
|
288
|
+
* `filename` is the attachment's `originalFilename`; collisions across
|
|
289
|
+
* messages are kept as separate entries (the model can disambiguate via
|
|
290
|
+
* the timestamp it sees in the manifest).
|
|
291
|
+
*/
|
|
292
|
+
export function collectImageManifest(conversationId: string): ManifestEntry[] {
|
|
293
|
+
const rows = getMessages(conversationId);
|
|
294
|
+
const entries: ManifestEntry[] = [];
|
|
295
|
+
for (const row of rows) {
|
|
296
|
+
const atts = getAttachmentMetadataForMessage(row.id);
|
|
297
|
+
for (const att of atts) {
|
|
298
|
+
if (att.kind !== "image") continue;
|
|
299
|
+
entries.push({
|
|
300
|
+
filename: att.originalFilename,
|
|
301
|
+
attachmentId: att.id,
|
|
302
|
+
role: row.role,
|
|
303
|
+
timestamp: row.createdAt,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return entries;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function renderImageManifest(entries: ManifestEntry[]): string {
|
|
311
|
+
if (entries.length === 0) return "(no images in this conversation)";
|
|
312
|
+
return entries
|
|
313
|
+
.map((e) => {
|
|
314
|
+
const ts = new Date(e.timestamp).toISOString();
|
|
315
|
+
return `- ${e.filename} (${e.role} message at ${ts})`;
|
|
316
|
+
})
|
|
317
|
+
.join("\n");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
// Timestamp extraction from live messages
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Extract the `current_time:` value from a user message's `<turn_context>`
|
|
326
|
+
* block, if present. Returns the raw timestamp string (whatever format the
|
|
327
|
+
* runtime emitted — typically
|
|
328
|
+
* `2026-04-02 (Thursday) 01:52:33 -05:00 (America/Chicago)`).
|
|
329
|
+
*/
|
|
330
|
+
function extractTurnContextTimestamp(message: Message): string | null {
|
|
331
|
+
if (message.role !== "user") return null;
|
|
332
|
+
for (const block of message.content) {
|
|
333
|
+
if (block.type !== "text") continue;
|
|
334
|
+
const text = block.text;
|
|
335
|
+
const idx = text.indexOf("<turn_context>");
|
|
336
|
+
if (idx < 0) continue;
|
|
337
|
+
const end = text.indexOf("</turn_context>", idx);
|
|
338
|
+
const slice = end > 0 ? text.slice(idx, end) : text.slice(idx);
|
|
339
|
+
const m = slice.match(/current_time:\s*([^\n]+)/);
|
|
340
|
+
if (m) return m[1].trim();
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Build a parallel array of timestamp strings — one per message — used to
|
|
347
|
+
* resolve the model's `tail_start.timestamp` back to a message index.
|
|
348
|
+
*
|
|
349
|
+
* Assistant and tool-result-only messages get `null` (they have no
|
|
350
|
+
* turn_context); the resolver walks forward from the matched index to
|
|
351
|
+
* include the surrounding user→assistant cluster.
|
|
352
|
+
*/
|
|
353
|
+
function buildTimestampIndex(messages: Message[]): (string | null)[] {
|
|
354
|
+
return messages.map((m) => extractTurnContextTimestamp(m));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function extractFirstTextPreview(message: Message, maxChars = 120): string {
|
|
358
|
+
for (const block of message.content) {
|
|
359
|
+
if (block.type !== "text") continue;
|
|
360
|
+
let text = block.text;
|
|
361
|
+
// Skip injected blocks (`<turn_context>`, `<memory>`, `<workspace>`, ...) —
|
|
362
|
+
// they're not what the model means by "first 60 chars of that message".
|
|
363
|
+
while (text.startsWith("<") && text.includes("</")) {
|
|
364
|
+
const closeMatch = text.match(/<\/[a-zA-Z_][\w-]*>\s*\n?/);
|
|
365
|
+
if (!closeMatch || closeMatch.index === undefined) break;
|
|
366
|
+
text = text.slice(closeMatch.index + closeMatch[0].length).trimStart();
|
|
367
|
+
}
|
|
368
|
+
if (text.length === 0) continue;
|
|
369
|
+
return text.slice(0, maxChars);
|
|
370
|
+
}
|
|
371
|
+
return "";
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Tail resolution
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Reduce a timestamp string to a canonical `YYYY-MM-DDTHH:MM:SS` form by
|
|
380
|
+
* extracting the date and time components and discarding everything else
|
|
381
|
+
* (weekday names, parens, timezone offsets, timezone names, separators).
|
|
382
|
+
*
|
|
383
|
+
* The stored format is e.g. `2026-04-02 (Thursday) 01:52:33 -05:00 (America/Chicago)`.
|
|
384
|
+
* Models routinely paraphrase this — dropping the weekday, dropping the
|
|
385
|
+
* timezone, switching to ISO-8601 with a `T` separator. As long as the
|
|
386
|
+
* model's emission contains a date and a time, both reduce to the same
|
|
387
|
+
* canonical key and we can match.
|
|
388
|
+
*
|
|
389
|
+
* Returns null when no date+time pair is detected.
|
|
390
|
+
*/
|
|
391
|
+
export function canonicalDateTimeKey(ts: string): string | null {
|
|
392
|
+
const m = ts.match(/(\d{4}-\d{2}-\d{2})\D+(\d{2}:\d{2}:\d{2})/);
|
|
393
|
+
if (!m) return null;
|
|
394
|
+
return `${m[1]}T${m[2]}`;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Resolve the model's `tail_start` reference to an index in the live
|
|
399
|
+
* messages array. Match priority:
|
|
400
|
+
* 1. Exact timestamp match against a `<turn_context>` `current_time:` line
|
|
401
|
+
* 2. Substring match (model may emit a shortened or re-formatted ts)
|
|
402
|
+
* 3. Canonical date+time match (tolerant of weekday/timezone paraphrasing)
|
|
403
|
+
* 4. Preview-text fallback — locate the message whose first non-injection
|
|
404
|
+
* text starts with the preview string
|
|
405
|
+
*/
|
|
406
|
+
function resolveTailStartIndex(
|
|
407
|
+
messages: Message[],
|
|
408
|
+
timestamps: (string | null)[],
|
|
409
|
+
parsed: ParsedCompactionResult,
|
|
410
|
+
): number | null {
|
|
411
|
+
const wantedTs = parsed.tailStartTimestamp.trim();
|
|
412
|
+
if (wantedTs.length > 0) {
|
|
413
|
+
for (let i = 0; i < timestamps.length; i++) {
|
|
414
|
+
if (timestamps[i] === wantedTs) return i;
|
|
415
|
+
}
|
|
416
|
+
for (let i = 0; i < timestamps.length; i++) {
|
|
417
|
+
const ts = timestamps[i];
|
|
418
|
+
if (ts && (ts.includes(wantedTs) || wantedTs.includes(ts))) return i;
|
|
419
|
+
}
|
|
420
|
+
const wantedKey = canonicalDateTimeKey(wantedTs);
|
|
421
|
+
if (wantedKey) {
|
|
422
|
+
for (let i = 0; i < timestamps.length; i++) {
|
|
423
|
+
const ts = timestamps[i];
|
|
424
|
+
if (!ts) continue;
|
|
425
|
+
if (canonicalDateTimeKey(ts) === wantedKey) return i;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
const wantedPreview = parsed.tailStartPreview.trim();
|
|
430
|
+
if (wantedPreview.length > 0) {
|
|
431
|
+
const previewHead = wantedPreview.slice(0, 40);
|
|
432
|
+
for (let i = 0; i < messages.length; i++) {
|
|
433
|
+
const m = messages[i];
|
|
434
|
+
if (m.role !== "user") continue;
|
|
435
|
+
const head = extractFirstTextPreview(m);
|
|
436
|
+
if (head.length > 0 && head.startsWith(previewHead)) return i;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ---------------------------------------------------------------------------
|
|
443
|
+
// Retained-image hydration
|
|
444
|
+
// ---------------------------------------------------------------------------
|
|
445
|
+
|
|
446
|
+
function buildRetainedImageBlocks(
|
|
447
|
+
filenames: string[],
|
|
448
|
+
manifest: ManifestEntry[],
|
|
449
|
+
): { blocks: ImageContent[]; resolved: string[]; missing: string[] } {
|
|
450
|
+
const blocks: ImageContent[] = [];
|
|
451
|
+
const resolved: string[] = [];
|
|
452
|
+
const missing: string[] = [];
|
|
453
|
+
for (const name of filenames) {
|
|
454
|
+
const entry = manifest.find((e) => e.filename === name);
|
|
455
|
+
if (!entry) {
|
|
456
|
+
missing.push(name);
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const content = getAttachmentContent(entry.attachmentId);
|
|
460
|
+
if (!content) {
|
|
461
|
+
missing.push(name);
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const sourceMime = guessMimeFromFilename(name);
|
|
465
|
+
// Run the same downscale pass the agent uses when first sending an
|
|
466
|
+
// image. Without this, attachments that exceed the provider's per-image
|
|
467
|
+
// byte limit (Anthropic: 5 MB) crash the next turn after compaction.
|
|
468
|
+
const optimized = optimizeImageForTransport(
|
|
469
|
+
content.toString("base64"),
|
|
470
|
+
sourceMime,
|
|
471
|
+
);
|
|
472
|
+
blocks.push({
|
|
473
|
+
type: "image",
|
|
474
|
+
source: {
|
|
475
|
+
type: "base64",
|
|
476
|
+
media_type: optimized.mediaType,
|
|
477
|
+
data: optimized.data,
|
|
478
|
+
},
|
|
479
|
+
});
|
|
480
|
+
resolved.push(name);
|
|
481
|
+
}
|
|
482
|
+
return { blocks, resolved, missing };
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function guessMimeFromFilename(filename: string): string {
|
|
486
|
+
const ext = filename.toLowerCase().split(".").pop() ?? "";
|
|
487
|
+
switch (ext) {
|
|
488
|
+
case "jpg":
|
|
489
|
+
case "jpeg":
|
|
490
|
+
return "image/jpeg";
|
|
491
|
+
case "png":
|
|
492
|
+
return "image/png";
|
|
493
|
+
case "gif":
|
|
494
|
+
return "image/gif";
|
|
495
|
+
case "webp":
|
|
496
|
+
return "image/webp";
|
|
497
|
+
default:
|
|
498
|
+
return "image/png";
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ---------------------------------------------------------------------------
|
|
503
|
+
// Instruction message
|
|
504
|
+
// ---------------------------------------------------------------------------
|
|
505
|
+
|
|
506
|
+
export function buildInstructionMessage(
|
|
507
|
+
customPrompt: string | null | undefined,
|
|
508
|
+
imageManifest: string,
|
|
509
|
+
): Message {
|
|
510
|
+
const template =
|
|
511
|
+
customPrompt && customPrompt.trim().length > 0
|
|
512
|
+
? customPrompt
|
|
513
|
+
: DEFAULT_COMPACTION_PROMPT;
|
|
514
|
+
const text = template.replace("{image_manifest}", imageManifest);
|
|
515
|
+
return {
|
|
516
|
+
role: "user",
|
|
517
|
+
content: [{ type: "text", text }],
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// ---------------------------------------------------------------------------
|
|
522
|
+
// Summary message construction
|
|
523
|
+
// ---------------------------------------------------------------------------
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Stitch summary + key_state into the assistant-role memory message that
|
|
527
|
+
* heads the compacted context. Kept as a single block so downstream
|
|
528
|
+
* lifecycle code can rehydrate it with the existing `contextSummary` text
|
|
529
|
+
* column without needing a parallel `keyState` column.
|
|
530
|
+
*/
|
|
531
|
+
export function buildSummaryMemoryText(
|
|
532
|
+
summary: string,
|
|
533
|
+
keyState: string,
|
|
534
|
+
): string {
|
|
535
|
+
const trimmedSummary = summary.trim();
|
|
536
|
+
const trimmedKey = keyState.trim();
|
|
537
|
+
if (trimmedKey.length === 0) return trimmedSummary;
|
|
538
|
+
return `${trimmedSummary}\n\n## Pending State\n${trimmedKey}`;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ---------------------------------------------------------------------------
|
|
542
|
+
// Orchestrator
|
|
543
|
+
// ---------------------------------------------------------------------------
|
|
544
|
+
|
|
545
|
+
function emptyResult(
|
|
546
|
+
args: CompactionRunArgs,
|
|
547
|
+
thresholdTokens: number,
|
|
548
|
+
reason: string,
|
|
549
|
+
): CompactionRunResult {
|
|
550
|
+
return {
|
|
551
|
+
messages: args.messages,
|
|
552
|
+
compacted: false,
|
|
553
|
+
previousEstimatedInputTokens: args.previousEstimatedInputTokens,
|
|
554
|
+
estimatedInputTokens: args.previousEstimatedInputTokens,
|
|
555
|
+
maxInputTokens: args.maxInputTokens,
|
|
556
|
+
thresholdTokens,
|
|
557
|
+
compactedMessages: 0,
|
|
558
|
+
compactedPersistedMessages: 0,
|
|
559
|
+
summaryCalls: 0,
|
|
560
|
+
summaryInputTokens: 0,
|
|
561
|
+
summaryOutputTokens: 0,
|
|
562
|
+
summaryModel: "",
|
|
563
|
+
summaryText: "",
|
|
564
|
+
reason,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function extractTextFromResponse(content: ContentBlock[]): string {
|
|
569
|
+
return content
|
|
570
|
+
.filter(
|
|
571
|
+
(b): b is Extract<ContentBlock, { type: "text" }> => b.type === "text",
|
|
572
|
+
)
|
|
573
|
+
.map((b) => b.text)
|
|
574
|
+
.join("\n");
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export async function runAssistantDrivenCompaction(
|
|
578
|
+
args: CompactionRunArgs,
|
|
579
|
+
): Promise<CompactionRunResult> {
|
|
580
|
+
const thresholdTokens = Math.floor(
|
|
581
|
+
args.maxInputTokens * args.compaction.autoThreshold,
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
if (!args.compaction.enabled) {
|
|
585
|
+
return emptyResult(args, thresholdTokens, "compaction disabled");
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (!args.force && args.previousEstimatedInputTokens < thresholdTokens) {
|
|
589
|
+
return emptyResult(args, thresholdTokens, "below auto threshold");
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (args.messages.length === 0) {
|
|
593
|
+
return emptyResult(args, thresholdTokens, "no messages to compact");
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Build image manifest from the DB before invoking the model so the
|
|
597
|
+
// instruction message carries a faithful picture of available images.
|
|
598
|
+
const manifest = collectImageManifest(args.conversationId);
|
|
599
|
+
const manifestText = renderImageManifest(manifest);
|
|
600
|
+
const instruction = buildInstructionMessage(
|
|
601
|
+
args.compaction.prompt ?? null,
|
|
602
|
+
manifestText,
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
// Append instruction at the tail — prefix unchanged, so prefix cache
|
|
606
|
+
// stays warm.
|
|
607
|
+
const requestMessages = [...args.messages, instruction];
|
|
608
|
+
|
|
609
|
+
let response: ProviderResponse;
|
|
610
|
+
try {
|
|
611
|
+
response = await args.provider.sendMessage(
|
|
612
|
+
requestMessages,
|
|
613
|
+
args.tools,
|
|
614
|
+
args.systemPrompt,
|
|
615
|
+
{
|
|
616
|
+
signal: args.signal,
|
|
617
|
+
config: {
|
|
618
|
+
callSite: COMPACTION_CALL_SITE,
|
|
619
|
+
usageTracking: "manual",
|
|
620
|
+
...(args.overrideProfile
|
|
621
|
+
? { overrideProfile: args.overrideProfile }
|
|
622
|
+
: {}),
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
);
|
|
626
|
+
} catch (err) {
|
|
627
|
+
log.warn({ err }, "Compaction provider call failed");
|
|
628
|
+
return {
|
|
629
|
+
...emptyResult(args, thresholdTokens, "provider error"),
|
|
630
|
+
summaryFailed: true,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const rawText = extractTextFromResponse(response.content);
|
|
635
|
+
const parsed = parseCompactionResult(rawText);
|
|
636
|
+
if (!parsed) {
|
|
637
|
+
log.warn(
|
|
638
|
+
{ rawPreview: rawText.slice(0, 200) },
|
|
639
|
+
"Compaction response did not contain a valid <compaction_result> block",
|
|
640
|
+
);
|
|
641
|
+
return {
|
|
642
|
+
...emptyResult(args, thresholdTokens, "unparseable response"),
|
|
643
|
+
summaryFailed: false,
|
|
644
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
645
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
646
|
+
summaryModel: response.model,
|
|
647
|
+
summaryCacheCreationInputTokens:
|
|
648
|
+
response.usage.cacheCreationInputTokens ?? 0,
|
|
649
|
+
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
650
|
+
summaryCallSite: COMPACTION_CALL_SITE,
|
|
651
|
+
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
652
|
+
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
653
|
+
summaryCalls: 1,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const timestamps = buildTimestampIndex(args.messages);
|
|
658
|
+
const tailIndex = resolveTailStartIndex(args.messages, timestamps, parsed);
|
|
659
|
+
if (tailIndex == null) {
|
|
660
|
+
log.warn(
|
|
661
|
+
{
|
|
662
|
+
timestamp: parsed.tailStartTimestamp,
|
|
663
|
+
preview: parsed.tailStartPreview.slice(0, 60),
|
|
664
|
+
},
|
|
665
|
+
"Compaction tail_start did not match any message — aborting compaction",
|
|
666
|
+
);
|
|
667
|
+
return {
|
|
668
|
+
...emptyResult(args, thresholdTokens, "tail_start unresolved"),
|
|
669
|
+
summaryFailed: false,
|
|
670
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
671
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
672
|
+
summaryModel: response.model,
|
|
673
|
+
summaryCacheCreationInputTokens:
|
|
674
|
+
response.usage.cacheCreationInputTokens ?? 0,
|
|
675
|
+
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
676
|
+
summaryCallSite: COMPACTION_CALL_SITE,
|
|
677
|
+
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
678
|
+
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
679
|
+
summaryCalls: 1,
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (tailIndex === 0) {
|
|
684
|
+
return {
|
|
685
|
+
...emptyResult(
|
|
686
|
+
args,
|
|
687
|
+
thresholdTokens,
|
|
688
|
+
"tail_start at head — nothing to compact",
|
|
689
|
+
),
|
|
690
|
+
summaryFailed: false,
|
|
691
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
692
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
693
|
+
summaryModel: response.model,
|
|
694
|
+
summaryCacheCreationInputTokens:
|
|
695
|
+
response.usage.cacheCreationInputTokens ?? 0,
|
|
696
|
+
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
697
|
+
summaryCallSite: COMPACTION_CALL_SITE,
|
|
698
|
+
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
699
|
+
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
700
|
+
summaryCalls: 1,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const compactableMessages = args.messages.slice(0, tailIndex);
|
|
705
|
+
// Strip runtime injections from preserved tail messages before they land in
|
|
706
|
+
// the compacted history. The static blocks (NOW.md, PKB, v2 essentials/
|
|
707
|
+
// threads/recent/buffer, system reminders) on the tail are stale snapshots
|
|
708
|
+
// from the moment of capture — keeping them would (a) waste tokens on
|
|
709
|
+
// outdated content, (b) duplicate against the freshly re-injected blocks
|
|
710
|
+
// the next turn produces, and (c) leak `<system_reminder>` text the model
|
|
711
|
+
// is not supposed to see in history. `<turn_context>` and `<workspace>`
|
|
712
|
+
// are intentionally preserved by `RUNTIME_INJECTION_PREFIXES`.
|
|
713
|
+
const tailMessages = stripInjectionsForCompaction(
|
|
714
|
+
args.messages.slice(tailIndex),
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
const summaryText = buildSummaryMemoryText(parsed.summary, parsed.keyState);
|
|
718
|
+
const summaryMessage: Message = {
|
|
719
|
+
role: "assistant",
|
|
720
|
+
content: [{ type: "text", text: summaryText }],
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
const {
|
|
724
|
+
blocks: retainedImageBlocks,
|
|
725
|
+
resolved,
|
|
726
|
+
missing,
|
|
727
|
+
} = buildRetainedImageBlocks(parsed.retainedImageFilenames, manifest);
|
|
728
|
+
if (missing.length > 0) {
|
|
729
|
+
log.warn(
|
|
730
|
+
{ missing },
|
|
731
|
+
"Compaction referenced images that could not be resolved against attachments — dropping",
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const compactedMessages: Message[] = [summaryMessage];
|
|
736
|
+
if (retainedImageBlocks.length > 0) {
|
|
737
|
+
compactedMessages.push({
|
|
738
|
+
role: "user",
|
|
739
|
+
content: [
|
|
740
|
+
{
|
|
741
|
+
type: "text" as const,
|
|
742
|
+
text: "Images retained from the compacted portion of the conversation:",
|
|
743
|
+
},
|
|
744
|
+
...retainedImageBlocks,
|
|
745
|
+
],
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
compactedMessages.push(...tailMessages);
|
|
749
|
+
|
|
750
|
+
const nonPersistedCompactedAway = Math.min(
|
|
751
|
+
args.nonPersistedPrefixCount ?? 0,
|
|
752
|
+
compactableMessages.length,
|
|
753
|
+
);
|
|
754
|
+
const compactedPersistedMessages = Math.max(
|
|
755
|
+
0,
|
|
756
|
+
compactableMessages.length - nonPersistedCompactedAway,
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
log.info(
|
|
760
|
+
{
|
|
761
|
+
conversationId: args.conversationId,
|
|
762
|
+
compactedMessages: compactableMessages.length,
|
|
763
|
+
compactedPersistedMessages,
|
|
764
|
+
tailIndex,
|
|
765
|
+
retainedImages: resolved.length,
|
|
766
|
+
summaryChars: summaryText.length,
|
|
767
|
+
},
|
|
768
|
+
"Applied assistant-driven compaction",
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
return {
|
|
772
|
+
messages: compactedMessages,
|
|
773
|
+
compacted: true,
|
|
774
|
+
previousEstimatedInputTokens: args.previousEstimatedInputTokens,
|
|
775
|
+
// We don't re-estimate here — the caller (window manager) will recompute
|
|
776
|
+
// when it returns to the agent loop. Returning the previous estimate is
|
|
777
|
+
// a conservative placeholder.
|
|
778
|
+
estimatedInputTokens: args.previousEstimatedInputTokens,
|
|
779
|
+
maxInputTokens: args.maxInputTokens,
|
|
780
|
+
thresholdTokens,
|
|
781
|
+
compactedMessages: compactableMessages.length,
|
|
782
|
+
compactedPersistedMessages,
|
|
783
|
+
summaryCalls: 1,
|
|
784
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
785
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
786
|
+
summaryModel: response.model,
|
|
787
|
+
summaryCallSite: COMPACTION_CALL_SITE,
|
|
788
|
+
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
789
|
+
summaryCacheCreationInputTokens:
|
|
790
|
+
response.usage.cacheCreationInputTokens ?? 0,
|
|
791
|
+
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
792
|
+
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
793
|
+
summaryText,
|
|
794
|
+
keyState: parsed.keyState,
|
|
795
|
+
summaryFailed: false,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// ---------------------------------------------------------------------------
|
|
800
|
+
// Emergency mid-turn compaction
|
|
801
|
+
// ---------------------------------------------------------------------------
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Simplified instruction for emergency compaction. No `tail_start` or
|
|
805
|
+
* `retained_images` — the caller already knows the split point. The model
|
|
806
|
+
* just needs to produce a summary + key_state.
|
|
807
|
+
*/
|
|
808
|
+
const EMERGENCY_COMPACTION_PROMPT = `<emergency_compaction>
|
|
809
|
+
The conversation has exceeded the context window during an active task.
|
|
810
|
+
This is an emergency compaction — summarize EVERYTHING you see into a
|
|
811
|
+
fresh-start summary so the assistant can continue its work.
|
|
812
|
+
|
|
813
|
+
Write the summary in YOUR voice. Prioritize:
|
|
814
|
+
- What task is currently in progress and what stage it is at
|
|
815
|
+
- Decisions already made during this task
|
|
816
|
+
- Key results from tool calls that are still relevant
|
|
817
|
+
- Any commitments or state changes from earlier in the conversation
|
|
818
|
+
- What the next step should be
|
|
819
|
+
|
|
820
|
+
Be thorough on task state — this summary plus the most recent tool call
|
|
821
|
+
and its result are the ONLY context the assistant will have to continue.
|
|
822
|
+
|
|
823
|
+
Output your result in this exact format:
|
|
824
|
+
|
|
825
|
+
<compaction_result>
|
|
826
|
+
<summary>
|
|
827
|
+
Your complete summary of everything that happened.
|
|
828
|
+
</summary>
|
|
829
|
+
|
|
830
|
+
<key_state>
|
|
831
|
+
Structured list of:
|
|
832
|
+
- Current task and its status
|
|
833
|
+
- Important intermediate results
|
|
834
|
+
- What to do next
|
|
835
|
+
</key_state>
|
|
836
|
+
</compaction_result>
|
|
837
|
+
</emergency_compaction>`;
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Find the start index of the last tool_use + tool_result cluster in the
|
|
841
|
+
* message array. Walks backwards to find the last assistant message
|
|
842
|
+
* containing a `tool_use` content block, then returns that index. The
|
|
843
|
+
* caller keeps everything from this index onwards as the preserved tail.
|
|
844
|
+
*
|
|
845
|
+
* Returns `null` if no tool_use message is found.
|
|
846
|
+
*/
|
|
847
|
+
function findLastToolPairStart(messages: Message[]): number | null {
|
|
848
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
849
|
+
const msg = messages[i];
|
|
850
|
+
if (msg.role !== "assistant") continue;
|
|
851
|
+
const hasToolUse = msg.content.some((b) => b.type === "tool_use");
|
|
852
|
+
if (hasToolUse) return i;
|
|
853
|
+
}
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Emergency compaction for the mid-turn context overflow case.
|
|
859
|
+
*
|
|
860
|
+
* When a `context_too_large` error fires during an active agent turn,
|
|
861
|
+
* the normal compactor may itself exceed the context window (the
|
|
862
|
+
* conversation that needs compacting is, by definition, too large to
|
|
863
|
+
* send to the model as-is).
|
|
864
|
+
*
|
|
865
|
+
* This function:
|
|
866
|
+
* 1. Finds the last tool_use message + its trailing tool_result(s)
|
|
867
|
+
* 2. Splits the history there
|
|
868
|
+
* 3. Truncates the prefix from the front if it exceeds the model's
|
|
869
|
+
* context window
|
|
870
|
+
* 4. Sends the (possibly truncated) prefix to the model with a
|
|
871
|
+
* simplified emergency instruction
|
|
872
|
+
* 5. Returns `[summary_message, ...last_tool_pair]` so the agent
|
|
873
|
+
* can continue with knowledge of what it just did
|
|
874
|
+
*
|
|
875
|
+
* If the provider call fails or no tool pair is found, returns
|
|
876
|
+
* `compacted: false` so the caller can fall through to other
|
|
877
|
+
* recovery strategies (tool-result truncation, media stubbing, etc.).
|
|
878
|
+
*/
|
|
879
|
+
export async function runEmergencyCompaction(
|
|
880
|
+
args: CompactionRunArgs,
|
|
881
|
+
): Promise<CompactionRunResult> {
|
|
882
|
+
const thresholdTokens = Math.floor(
|
|
883
|
+
args.maxInputTokens * args.compaction.autoThreshold,
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
const splitIndex = findLastToolPairStart(args.messages);
|
|
887
|
+
if (splitIndex == null || splitIndex === 0) {
|
|
888
|
+
log.info(
|
|
889
|
+
"Emergency compaction: no tool pair found — falling through",
|
|
890
|
+
);
|
|
891
|
+
return emptyResult(args, thresholdTokens, "no tool pair for emergency split");
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const keptTail = stripInjectionsForCompaction(
|
|
895
|
+
args.messages.slice(splitIndex),
|
|
896
|
+
);
|
|
897
|
+
let prefix = args.messages.slice(0, splitIndex);
|
|
898
|
+
|
|
899
|
+
// If the prefix itself exceeds the context window, truncate messages
|
|
900
|
+
// from the front so the model can at least see the recent portion.
|
|
901
|
+
// Reserve budget for the instruction message + output.
|
|
902
|
+
const instructionBudget = 800; // ~tokens for the emergency prompt
|
|
903
|
+
const outputBudget = Math.floor(args.maxInputTokens * 0.15);
|
|
904
|
+
const prefixBudget = args.maxInputTokens - instructionBudget - outputBudget;
|
|
905
|
+
|
|
906
|
+
let prefixEstimate = estimatePromptTokens(prefix, args.systemPrompt, {
|
|
907
|
+
providerName:
|
|
908
|
+
args.provider.tokenEstimationProvider ?? args.provider.name,
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
if (prefixEstimate > prefixBudget && prefix.length > 1) {
|
|
912
|
+
log.info(
|
|
913
|
+
{
|
|
914
|
+
prefixEstimate,
|
|
915
|
+
prefixBudget,
|
|
916
|
+
prefixMessages: prefix.length,
|
|
917
|
+
},
|
|
918
|
+
"Emergency compaction: prefix exceeds context window — truncating from front",
|
|
919
|
+
);
|
|
920
|
+
// Drop messages from the front until we fit. Keep at least the first
|
|
921
|
+
// message (may be an existing summary) and try to preserve recent context.
|
|
922
|
+
let dropCount = 0;
|
|
923
|
+
while (
|
|
924
|
+
prefixEstimate > prefixBudget &&
|
|
925
|
+
dropCount < prefix.length - 1
|
|
926
|
+
) {
|
|
927
|
+
dropCount++;
|
|
928
|
+
const truncated = prefix.slice(dropCount);
|
|
929
|
+
prefixEstimate = estimatePromptTokens(truncated, args.systemPrompt, {
|
|
930
|
+
providerName:
|
|
931
|
+
args.provider.tokenEstimationProvider ?? args.provider.name,
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
if (dropCount > 0) {
|
|
935
|
+
prefix = [
|
|
936
|
+
{
|
|
937
|
+
role: "user" as const,
|
|
938
|
+
content: [
|
|
939
|
+
{
|
|
940
|
+
type: "text" as const,
|
|
941
|
+
text: `[${dropCount} earlier messages truncated — summary covers only the visible portion]`,
|
|
942
|
+
},
|
|
943
|
+
],
|
|
944
|
+
},
|
|
945
|
+
...prefix.slice(dropCount),
|
|
946
|
+
];
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
const instruction: Message = {
|
|
951
|
+
role: "user",
|
|
952
|
+
content: [{ type: "text", text: EMERGENCY_COMPACTION_PROMPT }],
|
|
953
|
+
};
|
|
954
|
+
const requestMessages = [...prefix, instruction];
|
|
955
|
+
|
|
956
|
+
let response: ProviderResponse;
|
|
957
|
+
try {
|
|
958
|
+
response = await args.provider.sendMessage(
|
|
959
|
+
requestMessages,
|
|
960
|
+
args.tools,
|
|
961
|
+
args.systemPrompt,
|
|
962
|
+
{
|
|
963
|
+
signal: args.signal,
|
|
964
|
+
config: {
|
|
965
|
+
callSite: COMPACTION_CALL_SITE,
|
|
966
|
+
usageTracking: "manual",
|
|
967
|
+
...(args.overrideProfile
|
|
968
|
+
? { overrideProfile: args.overrideProfile }
|
|
969
|
+
: {}),
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
);
|
|
973
|
+
} catch (err) {
|
|
974
|
+
log.warn({ err }, "Emergency compaction provider call failed");
|
|
975
|
+
return {
|
|
976
|
+
...emptyResult(args, thresholdTokens, "emergency provider error"),
|
|
977
|
+
summaryFailed: true,
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
const rawText = extractTextFromResponse(response.content);
|
|
982
|
+
const parsed = parseCompactionResult(rawText);
|
|
983
|
+
if (!parsed) {
|
|
984
|
+
log.warn(
|
|
985
|
+
{ rawPreview: rawText.slice(0, 200) },
|
|
986
|
+
"Emergency compaction response did not contain a valid <compaction_result>",
|
|
987
|
+
);
|
|
988
|
+
return {
|
|
989
|
+
...emptyResult(args, thresholdTokens, "emergency unparseable response"),
|
|
990
|
+
summaryFailed: false,
|
|
991
|
+
summaryCalls: 1,
|
|
992
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
993
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
994
|
+
summaryModel: response.model,
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
const summaryText = buildSummaryMemoryText(parsed.summary, parsed.keyState);
|
|
999
|
+
const summaryMessage: Message = {
|
|
1000
|
+
role: "assistant",
|
|
1001
|
+
content: [{ type: "text", text: summaryText }],
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
const compactedMessages: Message[] = [summaryMessage, ...keptTail];
|
|
1005
|
+
|
|
1006
|
+
const compactedCount = splitIndex;
|
|
1007
|
+
const nonPersistedAway = Math.min(
|
|
1008
|
+
args.nonPersistedPrefixCount ?? 0,
|
|
1009
|
+
compactedCount,
|
|
1010
|
+
);
|
|
1011
|
+
|
|
1012
|
+
log.info(
|
|
1013
|
+
{
|
|
1014
|
+
conversationId: args.conversationId,
|
|
1015
|
+
compactedMessages: compactedCount,
|
|
1016
|
+
keptTailMessages: keptTail.length,
|
|
1017
|
+
summaryChars: summaryText.length,
|
|
1018
|
+
prefixTruncated: prefix[0]?.content?.[0]?.type === "text" &&
|
|
1019
|
+
(prefix[0].content[0] as { text: string }).text.includes("truncated"),
|
|
1020
|
+
},
|
|
1021
|
+
"Applied emergency mid-turn compaction",
|
|
1022
|
+
);
|
|
1023
|
+
|
|
1024
|
+
return {
|
|
1025
|
+
messages: compactedMessages,
|
|
1026
|
+
compacted: true,
|
|
1027
|
+
previousEstimatedInputTokens: args.previousEstimatedInputTokens,
|
|
1028
|
+
estimatedInputTokens: args.previousEstimatedInputTokens,
|
|
1029
|
+
maxInputTokens: args.maxInputTokens,
|
|
1030
|
+
thresholdTokens,
|
|
1031
|
+
compactedMessages: compactedCount,
|
|
1032
|
+
compactedPersistedMessages: Math.max(0, compactedCount - nonPersistedAway),
|
|
1033
|
+
summaryCalls: 1,
|
|
1034
|
+
summaryInputTokens: response.usage.inputTokens,
|
|
1035
|
+
summaryOutputTokens: response.usage.outputTokens,
|
|
1036
|
+
summaryModel: response.model,
|
|
1037
|
+
summaryCallSite: COMPACTION_CALL_SITE,
|
|
1038
|
+
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
1039
|
+
summaryCacheCreationInputTokens:
|
|
1040
|
+
response.usage.cacheCreationInputTokens ?? 0,
|
|
1041
|
+
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
1042
|
+
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
1043
|
+
summaryText,
|
|
1044
|
+
keyState: parsed.keyState,
|
|
1045
|
+
summaryFailed: false,
|
|
1046
|
+
};
|
|
1047
|
+
}
|