@vellumai/assistant 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +5 -0
- package/AGENTS.md +9 -1
- package/ARCHITECTURE.md +43 -49
- package/Dockerfile +17 -3
- package/README.md +3 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +33 -59
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +19 -18
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/error-handling.md +111 -0
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +334 -78
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +36 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +96 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +870 -655
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +440 -114
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +883 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -15
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +86 -46
- package/src/__tests__/conversation-agent-loop.test.ts +435 -216
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +36 -10
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +34 -12
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -15
- package/src/__tests__/conversation-process-callsite.test.ts +309 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +44 -21
- package/src/__tests__/conversation-queue.test.ts +68 -38
- package/src/__tests__/conversation-routes-disk-view.test.ts +36 -7
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2877 -152
- package/src/__tests__/conversation-runtime-workspace.test.ts +35 -50
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +39 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +53 -16
- package/src/__tests__/conversation-speed-override.test.ts +36 -12
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +118 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +4 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +33 -9
- package/src/__tests__/conversation-workspace-injection.test.ts +46 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -15
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +5 -2
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +29 -10
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +1 -66
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +621 -0
- package/src/__tests__/model-intents.test.ts +11 -83
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +46 -78
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -25
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +93 -14
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +69 -9
- package/src/__tests__/reaction-persistence.test.ts +561 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +259 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -8
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +201 -94
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +22 -16
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +545 -115
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +886 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +463 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +606 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -12
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +69 -8
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +299 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +39 -24
- package/src/cli.ts +0 -37
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +20 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +69 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -190
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +42 -10
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +49 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +317 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +64 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +96 -7
- package/src/context/__tests__/compact-prompt.test.ts +63 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +26 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +417 -39
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -3
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +162 -34
- package/src/daemon/conversation-agent-loop.ts +1282 -599
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +59 -17
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +1063 -211
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +51 -9
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +197 -64
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +65 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +7 -3
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +109 -82
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +63 -0
- package/src/daemon/message-types/messages.ts +21 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +122 -12
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -65
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +99 -28
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +11 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +97 -4
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +34 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +6 -3
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +63 -0
- package/src/ipc/routes/browser.ts +97 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +31 -1
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +76 -0
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +133 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +32 -4
- package/src/memory/db-init.ts +10 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +183 -53
- package/src/memory/graph/graph-search.test.ts +93 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +237 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/pkb/pkb-index.test.ts +369 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +252 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +499 -0
- package/src/memory/pkb/pkb-search.ts +159 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +147 -1
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1421 -0
- package/src/messaging/providers/slack/render-transcript.ts +501 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +31 -14
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -106
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +1223 -0
- package/src/permissions/approval-policy.ts +309 -0
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +1620 -0
- package/src/permissions/bash-risk-classifier.ts +950 -0
- package/src/permissions/checker.ts +348 -711
- package/src/permissions/command-registry.test.ts +774 -0
- package/src/permissions/command-registry.ts +1005 -0
- package/src/permissions/defaults.ts +28 -79
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +262 -0
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +25 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +9 -19
- package/src/platform/client.ts +19 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +524 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +80 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +646 -0
- package/src/providers/speech-to-text/xai-realtime.ts +821 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +27 -18
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +129 -9
- package/src/runtime/http-types.ts +23 -3
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +78 -0
- package/src/runtime/routes/approval-routes.ts +29 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +351 -138
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +987 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +720 -127
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +97 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +56 -8
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +35 -9
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +234 -2
- package/src/tools/browser/browser-execution.ts +150 -54
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +129 -73
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +116 -46
- package/src/tools/policy-context.ts +29 -8
- package/src/tools/registry.ts +195 -6
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +40 -5
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +9 -4
- package/src/util/pricing.ts +41 -8
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +56 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +28 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -66
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
package/src/agent/loop.ts
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import * as Sentry from "@sentry/node";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
4
|
+
import {
|
|
5
|
+
estimatePromptTokensRaw,
|
|
6
|
+
estimateToolsTokens,
|
|
7
|
+
getCalibrationProviderKey,
|
|
8
|
+
} from "../context/token-estimator.js";
|
|
9
|
+
import { calculateMaxToolResultChars } from "../context/tool-result-truncation.js";
|
|
10
|
+
import { defaultEmptyResponseTerminal } from "../plugins/defaults/empty-response.js";
|
|
11
|
+
import { defaultToolErrorTerminal } from "../plugins/defaults/tool-error.js";
|
|
12
|
+
import { defaultToolResultTruncateTerminal } from "../plugins/defaults/tool-result-truncate.js";
|
|
13
|
+
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
14
|
+
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
15
|
+
import type {
|
|
16
|
+
EmptyResponseArgs,
|
|
17
|
+
EmptyResponseDecision,
|
|
18
|
+
LLMCallArgs,
|
|
19
|
+
LLMCallResult,
|
|
20
|
+
ToolErrorArgs,
|
|
21
|
+
ToolErrorDecision,
|
|
22
|
+
ToolResultTruncateArgs,
|
|
23
|
+
ToolResultTruncateResult,
|
|
24
|
+
TurnContext,
|
|
25
|
+
} from "../plugins/types.js";
|
|
6
26
|
import type {
|
|
7
27
|
ContentBlock,
|
|
8
28
|
Message,
|
|
@@ -15,7 +35,9 @@ import {
|
|
|
15
35
|
applyStreamingSubstitution,
|
|
16
36
|
applySubstitutions,
|
|
17
37
|
} from "../tools/sensitive-output-placeholders.js";
|
|
38
|
+
import { AssistantError, ErrorCode, ProviderError } from "../util/errors.js";
|
|
18
39
|
import { getLogger } from "../util/logger.js";
|
|
40
|
+
import { isRetryableNetworkError } from "../util/retry.js";
|
|
19
41
|
|
|
20
42
|
const log = getLogger("agent-loop");
|
|
21
43
|
|
|
@@ -23,7 +45,7 @@ export interface AgentLoopConfig {
|
|
|
23
45
|
maxTokens: number;
|
|
24
46
|
maxInputTokens?: number; // context window size for tool result truncation
|
|
25
47
|
thinking?: { enabled: boolean };
|
|
26
|
-
effort: "low" | "medium" | "high" | "max";
|
|
48
|
+
effort: "low" | "medium" | "high" | "xhigh" | "max";
|
|
27
49
|
speed?: "standard" | "fast";
|
|
28
50
|
toolChoice?:
|
|
29
51
|
| { type: "auto" }
|
|
@@ -68,6 +90,10 @@ export type AgentEvent =
|
|
|
68
90
|
};
|
|
69
91
|
status?: string;
|
|
70
92
|
contentBlocks?: ContentBlock[];
|
|
93
|
+
riskLevel?: string;
|
|
94
|
+
riskReason?: string;
|
|
95
|
+
isContainerized?: boolean;
|
|
96
|
+
riskScopeOptions?: Array<{ pattern: string; label: string }>;
|
|
71
97
|
}
|
|
72
98
|
| { type: "tool_use_preview_start"; toolUseId: string; toolName: string }
|
|
73
99
|
| {
|
|
@@ -100,6 +126,13 @@ export type AgentEvent =
|
|
|
100
126
|
providerDurationMs: number;
|
|
101
127
|
rawRequest?: unknown;
|
|
102
128
|
rawResponse?: unknown;
|
|
129
|
+
/**
|
|
130
|
+
* Pre-send token estimate for the same call. Used by the estimator
|
|
131
|
+
* calibrator to learn how off the heuristic is versus provider
|
|
132
|
+
* ground truth. Omitted only when estimation genuinely was not run
|
|
133
|
+
* for this call (e.g. legacy/stubbed code paths).
|
|
134
|
+
*/
|
|
135
|
+
estimatedInputTokens?: number;
|
|
103
136
|
};
|
|
104
137
|
|
|
105
138
|
const DEFAULT_CONFIG: AgentLoopConfig = {
|
|
@@ -111,12 +144,139 @@ const DEFAULT_CONFIG: AgentLoopConfig = {
|
|
|
111
144
|
const MAX_CONSECUTIVE_ERROR_NUDGES = 3;
|
|
112
145
|
const MAX_EMPTY_RESPONSE_RETRIES = 1;
|
|
113
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Build a minimal {@link TurnContext} for pipeline invocations inside the
|
|
149
|
+
* agent loop. Real production call sites thread a full `TurnContext` into
|
|
150
|
+
* `AgentLoop.run()` (see the `turnContext` parameter on
|
|
151
|
+
* {@link AgentLoop.run}); this helper is the fallback used only by unit
|
|
152
|
+
* tests that construct `AgentLoop` directly without an orchestrator.
|
|
153
|
+
*
|
|
154
|
+
* When the orchestrator-supplied context is present, {@link resolveLoopTurnContext}
|
|
155
|
+
* is used instead of this helper so the pipeline sees the real
|
|
156
|
+
* `conversationId`, trust, and `contextWindowManager`. In the fallback path
|
|
157
|
+
* the returned context is still useful for pipeline logging: `requestId`
|
|
158
|
+
* surfaces in every structured record, and `turnIndex` reflects the
|
|
159
|
+
* current tool-use iteration.
|
|
160
|
+
*/
|
|
161
|
+
function buildLoopTurnContext(
|
|
162
|
+
requestId: string | undefined,
|
|
163
|
+
turnIndex: number,
|
|
164
|
+
): TurnContext {
|
|
165
|
+
return {
|
|
166
|
+
requestId: requestId ?? "agent-loop",
|
|
167
|
+
// Loop-scoped pipelines do not currently carry a conversation ID; the
|
|
168
|
+
// outer orchestrator owns that dimension. Use a fixed sentinel so log
|
|
169
|
+
// consumers can filter loop-origin records out of conversation queries.
|
|
170
|
+
conversationId: "agent-loop",
|
|
171
|
+
turnIndex,
|
|
172
|
+
trust: {
|
|
173
|
+
sourceChannel: "vellum",
|
|
174
|
+
trustClass: "unknown",
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Produce a `TurnContext` for a pipeline call inside {@link AgentLoop.run}.
|
|
181
|
+
*
|
|
182
|
+
* When the orchestrator supplied a `turnContext`, clone it and overwrite
|
|
183
|
+
* `requestId` + `turnIndex` with the loop-scoped values so plugin log
|
|
184
|
+
* records correctly attribute the call to the current tool-use iteration
|
|
185
|
+
* while preserving the real `conversationId`, trust context, and
|
|
186
|
+
* `contextWindowManager` the orchestrator assembled for the turn. Without
|
|
187
|
+
* an orchestrator context (unit tests that instantiate `AgentLoop` with no
|
|
188
|
+
* `turnContext`), fall back to {@link buildLoopTurnContext}'s synthesized
|
|
189
|
+
* placeholder.
|
|
190
|
+
*/
|
|
191
|
+
function resolveLoopTurnContext(
|
|
192
|
+
base: TurnContext | undefined,
|
|
193
|
+
requestId: string | undefined,
|
|
194
|
+
turnIndex: number,
|
|
195
|
+
): TurnContext {
|
|
196
|
+
if (base) {
|
|
197
|
+
return { ...base, requestId: requestId ?? base.requestId, turnIndex };
|
|
198
|
+
}
|
|
199
|
+
return buildLoopTurnContext(requestId, turnIndex);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* User-config HTTP status codes that should never page the on-call: billing
|
|
204
|
+
* exhaustion (402), invalid credentials (401), and forbidden/plan-gated (403).
|
|
205
|
+
* The user-facing error path already surfaces an actionable message (e.g.
|
|
206
|
+
* credits_exhausted); a Sentry issue adds noise without engineering signal.
|
|
207
|
+
*/
|
|
208
|
+
const USER_CONFIG_STATUS_CODES = new Set([401, 402, 403]);
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Whether an agent-loop error should be reported to Sentry. Suppresses:
|
|
212
|
+
*
|
|
213
|
+
* - `ProviderError` carrying a user-config status code (401/402/403) — these
|
|
214
|
+
* are bad API keys, exhausted billing, or plan gates, not engineering bugs.
|
|
215
|
+
* - Retry-exhausted transient network errors (`retriesExhausted === true` +
|
|
216
|
+
* still categorized as retryable network) — the retry loop already tried
|
|
217
|
+
* its best; the user's network was flaky, not our code.
|
|
218
|
+
*
|
|
219
|
+
* Everything else (5xx with no retry-exhaustion tag, surprise errors, tool
|
|
220
|
+
* failures, etc.) still pages.
|
|
221
|
+
*/
|
|
222
|
+
export function shouldCaptureAgentLoopError(err: Error): boolean {
|
|
223
|
+
if (
|
|
224
|
+
err instanceof ProviderError &&
|
|
225
|
+
err.statusCode !== undefined &&
|
|
226
|
+
USER_CONFIG_STATUS_CODES.has(err.statusCode)
|
|
227
|
+
) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
const exhausted = (err as Error & { retriesExhausted?: boolean })
|
|
231
|
+
.retriesExhausted;
|
|
232
|
+
if (exhausted === true && isRetryableNetworkError(err)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
114
238
|
export interface ResolvedSystemPrompt {
|
|
115
239
|
systemPrompt: string;
|
|
116
240
|
maxTokens?: number;
|
|
117
241
|
model?: string;
|
|
118
242
|
}
|
|
119
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Callback shape the loop uses to execute a tool invocation.
|
|
246
|
+
*
|
|
247
|
+
* The trailing `turnContext` is optional so in-process tests that wire the
|
|
248
|
+
* callback without an orchestrator keep working. Production sites (the
|
|
249
|
+
* `Conversation`'s `createToolExecutor`) forward the supplied context into
|
|
250
|
+
* `ToolExecutor.execute` so the `toolExecute` pipeline sees the orchestrator's
|
|
251
|
+
* real conversation identity/trust/contextWindowManager instead of the
|
|
252
|
+
* synthesized placeholder `ToolExecutor` would otherwise build from the
|
|
253
|
+
* `ToolContext` alone.
|
|
254
|
+
*/
|
|
255
|
+
export type LoopToolExecutor = (
|
|
256
|
+
name: string,
|
|
257
|
+
input: Record<string, unknown>,
|
|
258
|
+
onOutput?: (chunk: string) => void,
|
|
259
|
+
toolUseId?: string,
|
|
260
|
+
turnContext?: TurnContext,
|
|
261
|
+
) => Promise<{
|
|
262
|
+
content: string;
|
|
263
|
+
isError: boolean;
|
|
264
|
+
diff?: {
|
|
265
|
+
filePath: string;
|
|
266
|
+
oldContent: string;
|
|
267
|
+
newContent: string;
|
|
268
|
+
isNewFile: boolean;
|
|
269
|
+
};
|
|
270
|
+
status?: string;
|
|
271
|
+
contentBlocks?: ContentBlock[];
|
|
272
|
+
sensitiveBindings?: SensitiveOutputBinding[];
|
|
273
|
+
yieldToUser?: boolean;
|
|
274
|
+
riskLevel?: string;
|
|
275
|
+
riskReason?: string;
|
|
276
|
+
isContainerized?: boolean;
|
|
277
|
+
riskScopeOptions?: Array<{ pattern: string; label: string }>;
|
|
278
|
+
}>;
|
|
279
|
+
|
|
120
280
|
export class AgentLoop {
|
|
121
281
|
private provider: Provider;
|
|
122
282
|
private systemPrompt: string;
|
|
@@ -126,52 +286,14 @@ export class AgentLoop {
|
|
|
126
286
|
private resolveSystemPrompt:
|
|
127
287
|
| ((history: Message[]) => ResolvedSystemPrompt)
|
|
128
288
|
| null;
|
|
129
|
-
private toolExecutor:
|
|
130
|
-
| ((
|
|
131
|
-
name: string,
|
|
132
|
-
input: Record<string, unknown>,
|
|
133
|
-
onOutput?: (chunk: string) => void,
|
|
134
|
-
toolUseId?: string,
|
|
135
|
-
) => Promise<{
|
|
136
|
-
content: string;
|
|
137
|
-
isError: boolean;
|
|
138
|
-
diff?: {
|
|
139
|
-
filePath: string;
|
|
140
|
-
oldContent: string;
|
|
141
|
-
newContent: string;
|
|
142
|
-
isNewFile: boolean;
|
|
143
|
-
};
|
|
144
|
-
status?: string;
|
|
145
|
-
contentBlocks?: ContentBlock[];
|
|
146
|
-
sensitiveBindings?: SensitiveOutputBinding[];
|
|
147
|
-
yieldToUser?: boolean;
|
|
148
|
-
}>)
|
|
149
|
-
| null;
|
|
289
|
+
private toolExecutor: LoopToolExecutor | null;
|
|
150
290
|
|
|
151
291
|
constructor(
|
|
152
292
|
provider: Provider,
|
|
153
293
|
systemPrompt: string,
|
|
154
294
|
config?: Partial<AgentLoopConfig>,
|
|
155
295
|
tools?: ToolDefinition[],
|
|
156
|
-
toolExecutor?:
|
|
157
|
-
name: string,
|
|
158
|
-
input: Record<string, unknown>,
|
|
159
|
-
onOutput?: (chunk: string) => void,
|
|
160
|
-
toolUseId?: string,
|
|
161
|
-
) => Promise<{
|
|
162
|
-
content: string;
|
|
163
|
-
isError: boolean;
|
|
164
|
-
diff?: {
|
|
165
|
-
filePath: string;
|
|
166
|
-
oldContent: string;
|
|
167
|
-
newContent: string;
|
|
168
|
-
isNewFile: boolean;
|
|
169
|
-
};
|
|
170
|
-
status?: string;
|
|
171
|
-
contentBlocks?: ContentBlock[];
|
|
172
|
-
sensitiveBindings?: SensitiveOutputBinding[];
|
|
173
|
-
yieldToUser?: boolean;
|
|
174
|
-
}>,
|
|
296
|
+
toolExecutor?: LoopToolExecutor,
|
|
175
297
|
resolveTools?: (history: Message[]) => ToolDefinition[],
|
|
176
298
|
resolveSystemPrompt?: (history: Message[]) => ResolvedSystemPrompt,
|
|
177
299
|
) {
|
|
@@ -184,6 +306,21 @@ export class AgentLoop {
|
|
|
184
306
|
this.toolExecutor = toolExecutor ?? null;
|
|
185
307
|
}
|
|
186
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Resolve the tool definitions sent to the provider for the given turn.
|
|
311
|
+
*
|
|
312
|
+
* Mirrors the logic of {@link getToolTokenBudget} but returns the tool
|
|
313
|
+
* array itself — callers that need to thread the tool set into a plugin
|
|
314
|
+
* pipeline (e.g. `tokenEstimate`, where the pipeline's args include
|
|
315
|
+
* `tools`) use this rather than re-implementing the dynamic-vs-static
|
|
316
|
+
* resolver fork.
|
|
317
|
+
*/
|
|
318
|
+
getResolvedTools(history?: Message[]): ToolDefinition[] {
|
|
319
|
+
return history && this.resolveTools
|
|
320
|
+
? this.resolveTools(history)
|
|
321
|
+
: this.tools;
|
|
322
|
+
}
|
|
323
|
+
|
|
187
324
|
/**
|
|
188
325
|
* Estimate token cost of the tool definitions sent to the provider.
|
|
189
326
|
*
|
|
@@ -193,9 +330,7 @@ export class AgentLoop {
|
|
|
193
330
|
* without a resolver), falls back to the static `this.tools`.
|
|
194
331
|
*/
|
|
195
332
|
getToolTokenBudget(history?: Message[]): number {
|
|
196
|
-
|
|
197
|
-
history && this.resolveTools ? this.resolveTools(history) : this.tools;
|
|
198
|
-
return estimateToolsTokens(tools);
|
|
333
|
+
return estimateToolsTokens(this.getResolvedTools(history));
|
|
199
334
|
}
|
|
200
335
|
|
|
201
336
|
async run(
|
|
@@ -203,9 +338,22 @@ export class AgentLoop {
|
|
|
203
338
|
onEvent: (event: AgentEvent) => void | Promise<void>,
|
|
204
339
|
signal?: AbortSignal,
|
|
205
340
|
requestId?: string,
|
|
206
|
-
onCheckpoint?: (
|
|
341
|
+
onCheckpoint?: (
|
|
342
|
+
checkpoint: CheckpointInfo,
|
|
343
|
+
) => CheckpointDecision | Promise<CheckpointDecision>,
|
|
344
|
+
callSite?: LLMCallSite,
|
|
345
|
+
/**
|
|
346
|
+
* Optional per-turn context supplied by the orchestrator. Every pipeline
|
|
347
|
+
* invocation inside the loop clones from this value (overwriting only
|
|
348
|
+
* `turnIndex`/`requestId`) so middleware sees the real conversation
|
|
349
|
+
* identity, trust class, and `contextWindowManager` rather than the
|
|
350
|
+
* `"agent-loop"` sentinel used when the loop is instantiated standalone
|
|
351
|
+
* in unit tests.
|
|
352
|
+
*/
|
|
353
|
+
turnContext?: TurnContext,
|
|
207
354
|
): Promise<Message[]> {
|
|
208
355
|
const history = [...messages];
|
|
356
|
+
const initialHistoryLength = messages.length;
|
|
209
357
|
let toolUseTurns = 0;
|
|
210
358
|
let consecutiveErrorTurns = 0;
|
|
211
359
|
let emptyResponseRetries = 0;
|
|
@@ -221,6 +369,11 @@ export class AgentLoop {
|
|
|
221
369
|
while (true) {
|
|
222
370
|
if (signal?.aborted) break;
|
|
223
371
|
|
|
372
|
+
rlog.info(
|
|
373
|
+
{ turn: toolUseTurns, messageCount: history.length },
|
|
374
|
+
"Agent loop iteration start",
|
|
375
|
+
);
|
|
376
|
+
|
|
224
377
|
let toolUseBlocks: Extract<ContentBlock, { type: "tool_use" }>[] = [];
|
|
225
378
|
|
|
226
379
|
try {
|
|
@@ -235,25 +388,47 @@ export class AgentLoop {
|
|
|
235
388
|
? this.resolveSystemPrompt(history)
|
|
236
389
|
: null;
|
|
237
390
|
const turnSystemPrompt = resolved?.systemPrompt ?? this.systemPrompt;
|
|
238
|
-
const turnMaxTokens = resolved?.maxTokens ?? this.config.maxTokens;
|
|
239
391
|
const turnModel = resolved?.model;
|
|
240
392
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
393
|
+
// Field precedence (highest wins):
|
|
394
|
+
// 1. Per-turn explicit (`resolved.maxTokens` / `resolved.model`)
|
|
395
|
+
// 2. Call-site resolved values (filled by
|
|
396
|
+
// `RetryProvider.normalizeSendMessageOptions` from
|
|
397
|
+
// `resolveCallSiteConfig(callSite, llm)`)
|
|
398
|
+
// 3. Conversation defaults (`this.config.*`, sourced from
|
|
399
|
+
// `llm.default`)
|
|
400
|
+
//
|
|
401
|
+
// When `callSite` is present we deliberately leave
|
|
402
|
+
// `max_tokens`/`thinking`/`effort`/`speed` *unset* in `providerConfig`
|
|
403
|
+
// so the normalizer can fill them from the call-site resolution. The
|
|
404
|
+
// normalizer only writes these fields when they're undefined; if we
|
|
405
|
+
// pre-set them from `this.config` here, every per-call-site override
|
|
406
|
+
// for these knobs is silently ignored.
|
|
407
|
+
//
|
|
408
|
+
// `toolChoice` and `cacheTtl` are not part of the call-site schema, so
|
|
409
|
+
// they always come from `this.config` regardless of `callSite`.
|
|
410
|
+
const providerConfig: Record<string, unknown> = {};
|
|
411
|
+
|
|
412
|
+
if (resolved?.maxTokens !== undefined) {
|
|
413
|
+
providerConfig.max_tokens = resolved.maxTokens;
|
|
414
|
+
} else if (!callSite) {
|
|
415
|
+
providerConfig.max_tokens = this.config.maxTokens;
|
|
249
416
|
}
|
|
250
417
|
|
|
251
|
-
if (
|
|
252
|
-
providerConfig.
|
|
418
|
+
if (turnModel) {
|
|
419
|
+
providerConfig.model = turnModel;
|
|
253
420
|
}
|
|
254
421
|
|
|
255
|
-
if (
|
|
256
|
-
|
|
422
|
+
if (!callSite) {
|
|
423
|
+
if (this.config.thinking?.enabled) {
|
|
424
|
+
providerConfig.thinking = { type: "adaptive" };
|
|
425
|
+
}
|
|
426
|
+
if (this.config.effort) {
|
|
427
|
+
providerConfig.effort = this.config.effort;
|
|
428
|
+
}
|
|
429
|
+
if (this.config.speed && this.config.speed !== "standard") {
|
|
430
|
+
providerConfig.speed = this.config.speed;
|
|
431
|
+
}
|
|
257
432
|
}
|
|
258
433
|
|
|
259
434
|
if (this.config.toolChoice) {
|
|
@@ -264,20 +439,15 @@ export class AgentLoop {
|
|
|
264
439
|
providerConfig.cacheTtl = this.config.cacheTtl;
|
|
265
440
|
}
|
|
266
441
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
error: new Error(
|
|
277
|
-
`LLM call blocked by hook "${preLlmResult.blockedBy}"`,
|
|
278
|
-
),
|
|
279
|
-
});
|
|
280
|
-
break;
|
|
442
|
+
// Per-call LLM call-site identifier. Surfaces on the per-call
|
|
443
|
+
// `config.callSite` so `RetryProvider.normalizeSendMessageOptions`
|
|
444
|
+
// can route through `resolveCallSiteConfig` against
|
|
445
|
+
// `llm.callSites.<id>` (falling back to `llm.default` when absent).
|
|
446
|
+
// User-initiated conversation turns default to `mainAgent` in the
|
|
447
|
+
// agent loop's caller; other invocation contexts (heartbeat, filing,
|
|
448
|
+
// analyze, etc.) pass their own `callSite`.
|
|
449
|
+
if (callSite) {
|
|
450
|
+
providerConfig.callSite = callSite;
|
|
281
451
|
}
|
|
282
452
|
|
|
283
453
|
// Rate-limit consecutive LLM calls to prevent spin when tools return instantly
|
|
@@ -292,6 +462,25 @@ export class AgentLoop {
|
|
|
292
462
|
const providerStart = Date.now();
|
|
293
463
|
lastLlmCallTime = providerStart;
|
|
294
464
|
|
|
465
|
+
// Compute the pre-send estimate against the full in-memory
|
|
466
|
+
// history — matching what upstream callers of
|
|
467
|
+
// `estimatePromptTokens` (preflight, mid-loop checkpoints, the
|
|
468
|
+
// window manager) see. We use the RAW estimate (before applying
|
|
469
|
+
// the existing correction) so the calibrator learns the true
|
|
470
|
+
// bias against provider ground truth instead of ratcheting a
|
|
471
|
+
// feedback loop against its own corrected output.
|
|
472
|
+
const toolTokenBudget =
|
|
473
|
+
currentTools.length > 0 ? estimateToolsTokens(currentTools) : 0;
|
|
474
|
+
const preSendEstimatedTokens = estimatePromptTokensRaw(
|
|
475
|
+
history,
|
|
476
|
+
turnSystemPrompt,
|
|
477
|
+
{
|
|
478
|
+
providerName: getCalibrationProviderKey(this.provider),
|
|
479
|
+
toolTokenBudget,
|
|
480
|
+
},
|
|
481
|
+
);
|
|
482
|
+
rlog.info({ turn: toolUseTurns }, "LLM call start");
|
|
483
|
+
|
|
295
484
|
// Strip image contentBlocks from older tool results to prevent
|
|
296
485
|
// screenshots from accumulating in the context window. The LLM
|
|
297
486
|
// already saw each image on the turn it was captured; keeping
|
|
@@ -302,11 +491,26 @@ export class AgentLoop {
|
|
|
302
491
|
stripOldImageBlocks(history),
|
|
303
492
|
);
|
|
304
493
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
494
|
+
// Wrap the provider call in the `llmCall` pipeline so middleware
|
|
495
|
+
// contributed by plugins may observe, rewrite, short-circuit, or
|
|
496
|
+
// post-process every LLM request. The terminal below is the real
|
|
497
|
+
// `provider.sendMessage(...)` call; middleware that call `next(args)`
|
|
498
|
+
// eventually reach it. The default `defaultLlmCallPlugin` contributes
|
|
499
|
+
// only a passthrough middleware that forwards to `next(args)` —
|
|
500
|
+
// registered at module load, it sits at the outermost layer in the
|
|
501
|
+
// onion, so short-circuiting there would silently disable every
|
|
502
|
+
// user-registered `llmCall` middleware. Timeout is `null`
|
|
503
|
+
// (`DEFAULT_TIMEOUTS.llmCall`) — the provider layer already enforces
|
|
504
|
+
// its own HTTP-level budgets.
|
|
505
|
+
//
|
|
506
|
+
// The `onEvent` wrapping is kept inside `args.options` so substitution
|
|
507
|
+
// and streaming behavior exactly match the pre-pipeline call site.
|
|
508
|
+
const llmCallArgs: LLMCallArgs = {
|
|
509
|
+
provider: this.provider,
|
|
510
|
+
messages: providerHistory,
|
|
511
|
+
tools: currentTools.length > 0 ? currentTools : undefined,
|
|
512
|
+
systemPrompt: turnSystemPrompt,
|
|
513
|
+
options: {
|
|
310
514
|
config: providerConfig,
|
|
311
515
|
onEvent: (event) => {
|
|
312
516
|
if (event.type === "text_delta") {
|
|
@@ -357,6 +561,36 @@ export class AgentLoop {
|
|
|
357
561
|
},
|
|
358
562
|
signal,
|
|
359
563
|
},
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// Per-turn pipeline context. When the orchestrator threaded a full
|
|
567
|
+
// `turnContext` into `run()`, use it (overwriting `turnIndex` with
|
|
568
|
+
// the loop-scoped tool-use iteration) so middleware sees the real
|
|
569
|
+
// conversation identity, trust, and `contextWindowManager`. The
|
|
570
|
+
// synthesized fallback is only reached by standalone unit-test
|
|
571
|
+
// instantiations that never plumb a context through.
|
|
572
|
+
const turnCtx = resolveLoopTurnContext(
|
|
573
|
+
turnContext,
|
|
574
|
+
requestId,
|
|
575
|
+
toolUseTurns,
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
const response: LLMCallResult = await runPipeline<
|
|
579
|
+
LLMCallArgs,
|
|
580
|
+
LLMCallResult
|
|
581
|
+
>(
|
|
582
|
+
"llmCall",
|
|
583
|
+
getMiddlewaresFor("llmCall"),
|
|
584
|
+
(args) =>
|
|
585
|
+
args.provider.sendMessage(
|
|
586
|
+
args.messages,
|
|
587
|
+
args.tools,
|
|
588
|
+
args.systemPrompt,
|
|
589
|
+
args.options,
|
|
590
|
+
),
|
|
591
|
+
llmCallArgs,
|
|
592
|
+
turnCtx,
|
|
593
|
+
DEFAULT_TIMEOUTS.llmCall,
|
|
360
594
|
);
|
|
361
595
|
|
|
362
596
|
const providerDurationMs = Date.now() - providerStart;
|
|
@@ -372,14 +606,7 @@ export class AgentLoop {
|
|
|
372
606
|
providerDurationMs,
|
|
373
607
|
rawRequest: response.rawRequest,
|
|
374
608
|
rawResponse: response.rawResponse,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
void getHookManager().trigger("post-llm-call", {
|
|
378
|
-
model: response.model,
|
|
379
|
-
inputTokens: response.usage.inputTokens,
|
|
380
|
-
outputTokens: response.usage.outputTokens,
|
|
381
|
-
contentBlockCount: response.content.length,
|
|
382
|
-
durationMs: providerDurationMs,
|
|
609
|
+
estimatedInputTokens: preSendEstimatedTokens,
|
|
383
610
|
});
|
|
384
611
|
|
|
385
612
|
// Flush any buffered streaming text from the substitution pipeline
|
|
@@ -407,19 +634,97 @@ export class AgentLoop {
|
|
|
407
634
|
block.type === "tool_use",
|
|
408
635
|
);
|
|
409
636
|
|
|
637
|
+
rlog.info(
|
|
638
|
+
{
|
|
639
|
+
turn: toolUseTurns,
|
|
640
|
+
stopReason: response.stopReason,
|
|
641
|
+
contentBlocks: response.content.length,
|
|
642
|
+
toolUseCount: toolUseBlocks.length,
|
|
643
|
+
durationMs: providerDurationMs,
|
|
644
|
+
},
|
|
645
|
+
"LLM call complete",
|
|
646
|
+
);
|
|
647
|
+
|
|
410
648
|
// Detect empty responses: no user-visible text and no tool calls.
|
|
411
649
|
// This can happen when the model fails to produce output after
|
|
412
650
|
// receiving a large tool result. Retry once with a nudge before
|
|
413
651
|
// the message is persisted.
|
|
652
|
+
//
|
|
653
|
+
// Only nudge when the model hasn't already delivered text to the user
|
|
654
|
+
// earlier in this tool-use chain. If a prior assistant turn in history
|
|
655
|
+
// contained visible text (e.g. the model said its piece before calling
|
|
656
|
+
// a side-effect tool like `remember`), an empty follow-up is the model
|
|
657
|
+
// correctly ending its turn — nudging would mislead it into thinking
|
|
658
|
+
// its earlier text didn't land and cause a verbatim re-send.
|
|
659
|
+
//
|
|
660
|
+
// Note: we check ANY prior assistant turn from this run()
|
|
661
|
+
// invocation, not just the most recent one. In multi-step tool-use
|
|
662
|
+
// chains (say-something → call-tool → call-another-tool → end),
|
|
663
|
+
// the "say-something" text lives on an earlier assistant turn while
|
|
664
|
+
// the most recent assistant turn is a pure tool_use with no text.
|
|
665
|
+
// Restricting the check to the most recent assistant turn would
|
|
666
|
+
// falsely nudge in that case and trigger a duplicate re-send of
|
|
667
|
+
// text the user already saw.
|
|
668
|
+
//
|
|
669
|
+
// Scope the scan to messages appended during this run() call only.
|
|
670
|
+
// Assistant text from prior conversation turns (earlier run()
|
|
671
|
+
// invocations passed in via `messages`) must NOT suppress the
|
|
672
|
+
// nudge — those turns completed long ago and have no bearing on
|
|
673
|
+
// whether the current tool-use chain has delivered text yet.
|
|
674
|
+
//
|
|
675
|
+
// The actual decision (nudge vs. accept vs. error) is delegated to
|
|
676
|
+
// the `emptyResponse` plugin pipeline. The pipeline returns a
|
|
677
|
+
// decision; the loop carries out the side-effect (pushing the nudge
|
|
678
|
+
// or surfacing the error). See `plugins/defaults/empty-response.ts`
|
|
679
|
+
// for the default decision logic.
|
|
414
680
|
const hasVisibleText = response.content.some(
|
|
415
681
|
(block) => block.type === "text" && block.text.trim().length > 0,
|
|
416
682
|
);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
683
|
+
const priorAssistantHadVisibleText = (() => {
|
|
684
|
+
for (let i = history.length - 1; i >= initialHistoryLength; i--) {
|
|
685
|
+
const msg = history[i];
|
|
686
|
+
if (msg.role !== "assistant") continue;
|
|
687
|
+
const hasText = msg.content.some(
|
|
688
|
+
(block) =>
|
|
689
|
+
block.type === "text" &&
|
|
690
|
+
typeof (block as { text?: unknown }).text === "string" &&
|
|
691
|
+
(block as { text: string }).text.trim().length > 0,
|
|
692
|
+
);
|
|
693
|
+
if (hasText) return true;
|
|
694
|
+
}
|
|
695
|
+
return false;
|
|
696
|
+
})();
|
|
697
|
+
|
|
698
|
+
const emptyResponseArgs: EmptyResponseArgs = {
|
|
699
|
+
responseContent: response.content,
|
|
700
|
+
toolUseBlocksLength: toolUseBlocks.length,
|
|
701
|
+
toolUseTurns,
|
|
702
|
+
emptyResponseRetries,
|
|
703
|
+
maxEmptyResponseRetries: MAX_EMPTY_RESPONSE_RETRIES,
|
|
704
|
+
priorAssistantHadVisibleText,
|
|
705
|
+
};
|
|
706
|
+
const emptyResponseCtx = resolveLoopTurnContext(
|
|
707
|
+
turnContext,
|
|
708
|
+
requestId,
|
|
709
|
+
toolUseTurns,
|
|
710
|
+
);
|
|
711
|
+
const emptyResponseDecision: EmptyResponseDecision = await runPipeline(
|
|
712
|
+
"emptyResponse",
|
|
713
|
+
getMiddlewaresFor("emptyResponse"),
|
|
714
|
+
async (args) => defaultEmptyResponseTerminal(args),
|
|
715
|
+
emptyResponseArgs,
|
|
716
|
+
emptyResponseCtx,
|
|
717
|
+
DEFAULT_TIMEOUTS.emptyResponse,
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
if (emptyResponseDecision.action === "nudge") {
|
|
721
|
+
// Fall back to the canonical nudge text if the plugin returned
|
|
722
|
+
// `action: "nudge"` but forgot `nudgeText`. Keeps a misbehaving
|
|
723
|
+
// plugin from silently breaking the loop invariant that the
|
|
724
|
+
// model sees a coherent prompt.
|
|
725
|
+
const nudgeText =
|
|
726
|
+
emptyResponseDecision.nudgeText ??
|
|
727
|
+
"<system_notice>Your previous response was empty. You must respond to the user with a summary of what you found or did. Do not use any tools — just respond with text.</system_notice>";
|
|
423
728
|
emptyResponseRetries++;
|
|
424
729
|
rlog.warn(
|
|
425
730
|
{ turn: toolUseTurns, retry: emptyResponseRetries },
|
|
@@ -427,17 +732,31 @@ export class AgentLoop {
|
|
|
427
732
|
);
|
|
428
733
|
history.push({
|
|
429
734
|
role: "user",
|
|
430
|
-
content: [
|
|
431
|
-
{
|
|
432
|
-
type: "text",
|
|
433
|
-
text: "<system_notice>Your previous response was empty. You must respond to the user with a summary of what you found or did. Do not use any tools — just respond with text.</system_notice>",
|
|
434
|
-
},
|
|
435
|
-
],
|
|
735
|
+
content: [{ type: "text", text: nudgeText }],
|
|
436
736
|
});
|
|
437
737
|
continue;
|
|
438
738
|
}
|
|
439
739
|
|
|
440
|
-
if (
|
|
740
|
+
if (emptyResponseDecision.action === "error") {
|
|
741
|
+
rlog.error(
|
|
742
|
+
{ turn: toolUseTurns, retries: emptyResponseRetries },
|
|
743
|
+
"emptyResponse pipeline requested error surface",
|
|
744
|
+
);
|
|
745
|
+
throw new AssistantError(
|
|
746
|
+
"Model returned empty response after tool results",
|
|
747
|
+
ErrorCode.INTERNAL_ERROR,
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// action === "accept" — fall through. Emit a dedicated log line for
|
|
752
|
+
// the specific "empty turn after tool results, retries exhausted"
|
|
753
|
+
// case so ops dashboards that grep on this line keep working.
|
|
754
|
+
if (
|
|
755
|
+
!hasVisibleText &&
|
|
756
|
+
toolUseBlocks.length === 0 &&
|
|
757
|
+
toolUseTurns > 0 &&
|
|
758
|
+
!priorAssistantHadVisibleText
|
|
759
|
+
) {
|
|
441
760
|
rlog.error(
|
|
442
761
|
{ turn: toolUseTurns, retries: emptyResponseRetries },
|
|
443
762
|
"Model returned empty response after tool results — retries exhausted",
|
|
@@ -479,6 +798,15 @@ export class AgentLoop {
|
|
|
479
798
|
// Execute all tools concurrently for reduced latency.
|
|
480
799
|
// Race against the abort signal so cancellation isn't blocked by
|
|
481
800
|
// stuck tools (e.g. a hung browser navigation).
|
|
801
|
+
const toolExecStart = Date.now();
|
|
802
|
+
rlog.info(
|
|
803
|
+
{
|
|
804
|
+
turn: toolUseTurns,
|
|
805
|
+
toolNames: toolUseBlocks.map((t) => t.name),
|
|
806
|
+
},
|
|
807
|
+
"Tool execution start",
|
|
808
|
+
);
|
|
809
|
+
|
|
482
810
|
const toolExecutionPromise = Promise.all(
|
|
483
811
|
toolUseBlocks.map(async (toolUse) => {
|
|
484
812
|
const result = await this.toolExecutor!(
|
|
@@ -492,6 +820,14 @@ export class AgentLoop {
|
|
|
492
820
|
});
|
|
493
821
|
},
|
|
494
822
|
toolUse.id,
|
|
823
|
+
// Forward the loop's resolved `TurnContext` through the
|
|
824
|
+
// executor callback so `ToolExecutor.execute` can thread the
|
|
825
|
+
// real orchestrator context into the `toolExecute` pipeline.
|
|
826
|
+
// Standalone tests that don't wire a `turnContext` into
|
|
827
|
+
// `AgentLoop.run()` pass `undefined` here and the executor
|
|
828
|
+
// falls back to the synthesized placeholder — preserving the
|
|
829
|
+
// existing unit-test behavior.
|
|
830
|
+
turnCtx,
|
|
495
831
|
);
|
|
496
832
|
|
|
497
833
|
return { toolUse, result };
|
|
@@ -522,6 +858,15 @@ export class AgentLoop {
|
|
|
522
858
|
toolResults = await toolExecutionPromise;
|
|
523
859
|
}
|
|
524
860
|
|
|
861
|
+
rlog.info(
|
|
862
|
+
{
|
|
863
|
+
turn: toolUseTurns,
|
|
864
|
+
toolCount: toolResults.length,
|
|
865
|
+
durationMs: Date.now() - toolExecStart,
|
|
866
|
+
},
|
|
867
|
+
"Tool execution complete",
|
|
868
|
+
);
|
|
869
|
+
|
|
525
870
|
// Merge sensitive output bindings from tool results into the
|
|
526
871
|
// per-run substitution map. Bindings carry placeholder->value pairs
|
|
527
872
|
// that are resolved in streamed text deltas and final message text.
|
|
@@ -546,12 +891,52 @@ export class AgentLoop {
|
|
|
546
891
|
}),
|
|
547
892
|
);
|
|
548
893
|
|
|
549
|
-
// Pre-emptively truncate oversized tool results to prevent context
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
894
|
+
// Pre-emptively truncate oversized tool results to prevent context
|
|
895
|
+
// overflow. The work is delegated to the `toolResultTruncate`
|
|
896
|
+
// plugin pipeline so downstream plugins can swap in a smarter
|
|
897
|
+
// truncation strategy (e.g. a summariser) while the default
|
|
898
|
+
// middleware preserves the historical tail-drop behaviour.
|
|
899
|
+
const contextWindowTokens = this.config.maxInputTokens ?? 180_000;
|
|
900
|
+
const maxChars = calculateMaxToolResultChars(contextWindowTokens);
|
|
901
|
+
const truncateMiddlewares = getMiddlewaresFor("toolResultTruncate");
|
|
902
|
+
|
|
903
|
+
let truncatedCount = 0;
|
|
904
|
+
const truncatedBlocks: ContentBlock[] = [];
|
|
905
|
+
for (const block of rawResultBlocks) {
|
|
906
|
+
if (block.type !== "tool_result") {
|
|
907
|
+
truncatedBlocks.push(block);
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
const toolBlock = block as ToolResultContent;
|
|
911
|
+
if (
|
|
912
|
+
typeof toolBlock.content !== "string" ||
|
|
913
|
+
toolBlock.content.length <= maxChars
|
|
914
|
+
) {
|
|
915
|
+
truncatedBlocks.push(block);
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
const pipelineResult = await runPipeline<
|
|
919
|
+
ToolResultTruncateArgs,
|
|
920
|
+
ToolResultTruncateResult
|
|
921
|
+
>(
|
|
922
|
+
"toolResultTruncate",
|
|
923
|
+
truncateMiddlewares,
|
|
924
|
+
async (args) => defaultToolResultTruncateTerminal(args),
|
|
925
|
+
{ content: toolBlock.content, maxChars },
|
|
926
|
+
turnCtx,
|
|
927
|
+
DEFAULT_TIMEOUTS.toolResultTruncate,
|
|
554
928
|
);
|
|
929
|
+
if (pipelineResult.truncated) {
|
|
930
|
+
truncatedCount++;
|
|
931
|
+
truncatedBlocks.push({
|
|
932
|
+
...toolBlock,
|
|
933
|
+
content: pipelineResult.content,
|
|
934
|
+
});
|
|
935
|
+
} else {
|
|
936
|
+
truncatedBlocks.push(block);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
const resultBlocks = truncatedBlocks;
|
|
555
940
|
if (truncatedCount > 0) {
|
|
556
941
|
log.warn(
|
|
557
942
|
`Truncated ${truncatedCount} oversized tool result(s) to prevent context overflow`,
|
|
@@ -577,6 +962,10 @@ export class AgentLoop {
|
|
|
577
962
|
diff: result.diff,
|
|
578
963
|
status: result.status,
|
|
579
964
|
contentBlocks: result.contentBlocks,
|
|
965
|
+
riskLevel: result.riskLevel,
|
|
966
|
+
riskReason: result.riskReason,
|
|
967
|
+
isContainerized: result.isContainerized,
|
|
968
|
+
riskScopeOptions: result.riskScopeOptions,
|
|
580
969
|
});
|
|
581
970
|
}
|
|
582
971
|
|
|
@@ -598,29 +987,59 @@ export class AgentLoop {
|
|
|
598
987
|
// When any tool returned an error, nudge the LLM to retry with
|
|
599
988
|
// corrected parameters instead of ending its turn. Skip the nudge
|
|
600
989
|
// after MAX_CONSECUTIVE_ERROR_NUDGES consecutive error turns
|
|
601
|
-
// (the error is likely unrecoverable at that point).
|
|
990
|
+
// (the error is likely unrecoverable at that point). The nudge
|
|
991
|
+
// decision is delegated to the `toolError` plugin pipeline so user
|
|
992
|
+
// plugins can change the text, observe the event, or suppress it.
|
|
602
993
|
const hasToolError = toolResults.some(({ result }) => result.isError);
|
|
603
994
|
if (hasToolError) {
|
|
604
995
|
consecutiveErrorTurns++;
|
|
605
996
|
} else {
|
|
606
997
|
consecutiveErrorTurns = 0;
|
|
607
998
|
}
|
|
608
|
-
|
|
609
|
-
hasToolError
|
|
610
|
-
consecutiveErrorTurns
|
|
611
|
-
|
|
999
|
+
const toolErrorArgs: ToolErrorArgs = {
|
|
1000
|
+
hasToolError,
|
|
1001
|
+
consecutiveErrorTurns,
|
|
1002
|
+
maxConsecutiveErrorNudges: MAX_CONSECUTIVE_ERROR_NUDGES,
|
|
1003
|
+
};
|
|
1004
|
+
const toolErrorCtx: TurnContext = resolveLoopTurnContext(
|
|
1005
|
+
turnContext,
|
|
1006
|
+
requestId,
|
|
1007
|
+
toolUseTurns - 1,
|
|
1008
|
+
);
|
|
1009
|
+
const toolErrorDecision = await runPipeline<
|
|
1010
|
+
ToolErrorArgs,
|
|
1011
|
+
ToolErrorDecision
|
|
1012
|
+
>(
|
|
1013
|
+
"toolError",
|
|
1014
|
+
getMiddlewaresFor("toolError"),
|
|
1015
|
+
// Terminal: the canonical nudge decision. The default plugin's
|
|
1016
|
+
// middleware is a passthrough (so later-registered user plugins
|
|
1017
|
+
// aren't shadowed), so this terminal is what actually produces
|
|
1018
|
+
// the decision when no user plugin overrides it. Wiring the
|
|
1019
|
+
// decision here — rather than inside the default plugin's
|
|
1020
|
+
// middleware — also preserves the legacy nudge for direct
|
|
1021
|
+
// AgentLoop callers (tests, benchmarks) that skip
|
|
1022
|
+
// `bootstrapPlugins()` and therefore never register the default.
|
|
1023
|
+
async (args) => defaultToolErrorTerminal(args),
|
|
1024
|
+
toolErrorArgs,
|
|
1025
|
+
toolErrorCtx,
|
|
1026
|
+
DEFAULT_TIMEOUTS.toolError,
|
|
1027
|
+
);
|
|
1028
|
+
if (toolErrorDecision.action === "nudge") {
|
|
612
1029
|
resultBlocks.push({
|
|
613
1030
|
type: "text",
|
|
614
|
-
text:
|
|
1031
|
+
text: toolErrorDecision.nudgeText,
|
|
615
1032
|
});
|
|
616
1033
|
}
|
|
617
1034
|
|
|
618
1035
|
// Add tool results as a user message and continue the loop
|
|
619
1036
|
history.push({ role: "user", content: resultBlocks });
|
|
620
1037
|
|
|
621
|
-
// Invoke checkpoint callback after tool results are in history
|
|
1038
|
+
// Invoke checkpoint callback after tool results are in history.
|
|
1039
|
+
// The callback may be async — the mid-loop budget check delegates
|
|
1040
|
+
// to the `tokenEstimate` plugin pipeline, which is asynchronous.
|
|
622
1041
|
if (onCheckpoint) {
|
|
623
|
-
const decision = onCheckpoint({
|
|
1042
|
+
const decision = await onCheckpoint({
|
|
624
1043
|
turnIndex: toolUseTurns - 1, // 0-based (toolUseTurns was already incremented)
|
|
625
1044
|
toolCount: toolUseBlocks.length,
|
|
626
1045
|
hasToolUse: true,
|
|
@@ -653,12 +1072,23 @@ export class AgentLoop {
|
|
|
653
1072
|
{ err, turn: toolUseTurns, messageCount: history.length },
|
|
654
1073
|
"Agent loop error during turn processing",
|
|
655
1074
|
);
|
|
656
|
-
|
|
1075
|
+
if (shouldCaptureAgentLoopError(err)) {
|
|
1076
|
+
Sentry.captureException(err);
|
|
1077
|
+
}
|
|
657
1078
|
onEvent({ type: "error", error: err });
|
|
658
1079
|
break;
|
|
659
1080
|
}
|
|
660
1081
|
}
|
|
661
1082
|
|
|
1083
|
+
rlog.info(
|
|
1084
|
+
{
|
|
1085
|
+
turns: toolUseTurns,
|
|
1086
|
+
finalMessageCount: history.length,
|
|
1087
|
+
aborted: signal?.aborted ?? false,
|
|
1088
|
+
},
|
|
1089
|
+
"Agent loop exited",
|
|
1090
|
+
);
|
|
1091
|
+
|
|
662
1092
|
return history;
|
|
663
1093
|
}
|
|
664
1094
|
}
|