@vellumai/assistant 0.8.2 → 0.8.4
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/ARCHITECTURE.md +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import type { DrizzleDb } from "../memory/db-connection.js";
|
|
4
|
+
import { getDb } from "../memory/db-connection.js";
|
|
5
|
+
import { rawChanges } from "../memory/raw-query.js";
|
|
6
|
+
import { a2aTasks } from "../memory/schema.js";
|
|
7
|
+
import { TERMINAL_TASK_STATES } from "./protocol-constants.js";
|
|
8
|
+
import type {
|
|
9
|
+
A2AMessage,
|
|
10
|
+
A2ATask,
|
|
11
|
+
Artifact,
|
|
12
|
+
TaskState,
|
|
13
|
+
} from "./protocol-types.js";
|
|
14
|
+
|
|
15
|
+
// ── Internal types ──────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/** Raw database row shape for a2a_tasks. */
|
|
18
|
+
type A2ATaskRow = typeof a2aTasks.$inferSelect;
|
|
19
|
+
|
|
20
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/** Throw if the task doesn't exist or is in a terminal state. */
|
|
23
|
+
function assertNonTerminal(
|
|
24
|
+
db: DrizzleDb,
|
|
25
|
+
taskId: string,
|
|
26
|
+
targetState: TaskState,
|
|
27
|
+
): void {
|
|
28
|
+
const current = db
|
|
29
|
+
.select({ state: a2aTasks.state })
|
|
30
|
+
.from(a2aTasks)
|
|
31
|
+
.where(eq(a2aTasks.id, taskId))
|
|
32
|
+
.get();
|
|
33
|
+
|
|
34
|
+
if (!current) {
|
|
35
|
+
throw new Error(`A2A task not found: ${taskId}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (TERMINAL_TASK_STATES.has(current.state as TaskState)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`Cannot transition task ${taskId} from terminal state "${current.state}" to "${targetState}"`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function rowToTask(row: A2ATaskRow): A2ATask {
|
|
46
|
+
return {
|
|
47
|
+
id: row.id,
|
|
48
|
+
context_id: row.contextId ?? undefined,
|
|
49
|
+
status: {
|
|
50
|
+
state: row.state as TaskState,
|
|
51
|
+
message: row.statusMessage
|
|
52
|
+
? {
|
|
53
|
+
message_id: crypto.randomUUID(),
|
|
54
|
+
role: "agent",
|
|
55
|
+
parts: [{ kind: "text", text: row.statusMessage }],
|
|
56
|
+
}
|
|
57
|
+
: undefined,
|
|
58
|
+
timestamp: new Date(row.updatedAt).toISOString(),
|
|
59
|
+
},
|
|
60
|
+
artifacts: row.artifactsJson
|
|
61
|
+
? (JSON.parse(row.artifactsJson) as Artifact[])
|
|
62
|
+
: undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Store functions ─────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
export function createTask(params: {
|
|
69
|
+
contextId?: string;
|
|
70
|
+
senderAssistantId: string;
|
|
71
|
+
requestMessage: A2AMessage;
|
|
72
|
+
pushUrl?: string;
|
|
73
|
+
}): A2ATask {
|
|
74
|
+
const db = getDb();
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
|
|
77
|
+
const row: A2ATaskRow = {
|
|
78
|
+
id: crypto.randomUUID(),
|
|
79
|
+
contextId: params.contextId ?? null,
|
|
80
|
+
conversationId: null,
|
|
81
|
+
state: "submitted",
|
|
82
|
+
statusMessage: null,
|
|
83
|
+
requestMessageJson: JSON.stringify(params.requestMessage),
|
|
84
|
+
artifactsJson: null,
|
|
85
|
+
pushUrl: params.pushUrl ?? null,
|
|
86
|
+
senderAssistantId: params.senderAssistantId,
|
|
87
|
+
createdAt: now,
|
|
88
|
+
updatedAt: now,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
db.insert(a2aTasks).values(row).run();
|
|
92
|
+
|
|
93
|
+
return rowToTask(row);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function getTask(taskId: string): A2ATask | null {
|
|
97
|
+
const db = getDb();
|
|
98
|
+
const row = db.select().from(a2aTasks).where(eq(a2aTasks.id, taskId)).get();
|
|
99
|
+
return row ? rowToTask(row) : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function updateState(
|
|
103
|
+
taskId: string,
|
|
104
|
+
state: TaskState,
|
|
105
|
+
statusMessage?: string,
|
|
106
|
+
): A2ATask {
|
|
107
|
+
const db = getDb();
|
|
108
|
+
assertNonTerminal(db, taskId, state);
|
|
109
|
+
|
|
110
|
+
db.update(a2aTasks)
|
|
111
|
+
.set({
|
|
112
|
+
state,
|
|
113
|
+
statusMessage: statusMessage ?? null,
|
|
114
|
+
updatedAt: Date.now(),
|
|
115
|
+
})
|
|
116
|
+
.where(eq(a2aTasks.id, taskId))
|
|
117
|
+
.run();
|
|
118
|
+
|
|
119
|
+
return rowToTask(
|
|
120
|
+
db.select().from(a2aTasks).where(eq(a2aTasks.id, taskId)).get()!,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function completeWithArtifacts(
|
|
125
|
+
taskId: string,
|
|
126
|
+
artifacts: Artifact[],
|
|
127
|
+
): A2ATask {
|
|
128
|
+
const db = getDb();
|
|
129
|
+
assertNonTerminal(db, taskId, "completed");
|
|
130
|
+
|
|
131
|
+
db.update(a2aTasks)
|
|
132
|
+
.set({
|
|
133
|
+
state: "completed",
|
|
134
|
+
statusMessage: null,
|
|
135
|
+
artifactsJson: JSON.stringify(artifacts),
|
|
136
|
+
updatedAt: Date.now(),
|
|
137
|
+
})
|
|
138
|
+
.where(eq(a2aTasks.id, taskId))
|
|
139
|
+
.run();
|
|
140
|
+
|
|
141
|
+
return rowToTask(
|
|
142
|
+
db.select().from(a2aTasks).where(eq(a2aTasks.id, taskId)).get()!,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function linkConversation(taskId: string, conversationId: string): void {
|
|
147
|
+
const db = getDb();
|
|
148
|
+
const now = Date.now();
|
|
149
|
+
|
|
150
|
+
db.update(a2aTasks)
|
|
151
|
+
.set({ conversationId, updatedAt: now })
|
|
152
|
+
.where(eq(a2aTasks.id, taskId))
|
|
153
|
+
.run();
|
|
154
|
+
|
|
155
|
+
if (rawChanges() === 0) {
|
|
156
|
+
throw new Error(`A2A task not found: ${taskId}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function getPushUrl(taskId: string): string | null {
|
|
161
|
+
const db = getDb();
|
|
162
|
+
const row = db
|
|
163
|
+
.select({ pushUrl: a2aTasks.pushUrl })
|
|
164
|
+
.from(a2aTasks)
|
|
165
|
+
.where(eq(a2aTasks.id, taskId))
|
|
166
|
+
.get();
|
|
167
|
+
return row?.pushUrl ?? null;
|
|
168
|
+
}
|
package/src/agent/attachments.ts
CHANGED
package/src/agent/loop.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getCalibrationProviderKey,
|
|
8
8
|
} from "../context/token-estimator.js";
|
|
9
9
|
import { calculateMaxToolResultChars } from "../context/tool-result-truncation.js";
|
|
10
|
+
import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
|
|
10
11
|
import { defaultEmptyResponseTerminal } from "../plugins/defaults/empty-response.js";
|
|
11
12
|
import { defaultToolErrorTerminal } from "../plugins/defaults/tool-error.js";
|
|
12
13
|
import { defaultToolResultTruncateTerminal } from "../plugins/defaults/tool-result-truncate.js";
|
|
@@ -67,6 +68,48 @@ export interface CheckpointInfo {
|
|
|
67
68
|
|
|
68
69
|
export type CheckpointDecision = "continue" | "yield";
|
|
69
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Why an agent turn reached a terminal state.
|
|
73
|
+
*
|
|
74
|
+
* Emitted as part of an {@link AgentEvent} of type `agent_loop_exit`, then
|
|
75
|
+
* persisted onto the **final** `llm_request_logs` row of the turn. Rows from
|
|
76
|
+
* intermediate turns keep a NULL `agent_loop_exit_reason`, which is how
|
|
77
|
+
* downstream tooling (and the LLM Context Inspector) distinguishes "loop kept
|
|
78
|
+
* going" from "loop is done".
|
|
79
|
+
*
|
|
80
|
+
* Values are stable wire/DB strings — they are written to SQLite and
|
|
81
|
+
* surfaced over the inspector wire format, so renaming any of them is a
|
|
82
|
+
* breaking change.
|
|
83
|
+
*
|
|
84
|
+
* Keep in sync with `emitExit` call sites in {@link AgentLoop.run} and the
|
|
85
|
+
* outer conversation orchestrator paths that terminate after a checkpoint
|
|
86
|
+
* yield. A checkpoint yield used for budget compaction is intentionally not
|
|
87
|
+
* a terminal reason — it is a control transfer before re-entering the loop.
|
|
88
|
+
*/
|
|
89
|
+
export type AgentLoopExitReason =
|
|
90
|
+
/** `if (signal?.aborted) break;` at the top of the loop. */
|
|
91
|
+
| "aborted_pre_call"
|
|
92
|
+
/** Empty assistant response after the configured retry budget. */
|
|
93
|
+
| "empty_response_exhausted"
|
|
94
|
+
/** Assistant message has no tool-use blocks (or no tool executor). */
|
|
95
|
+
| "no_tool_calls"
|
|
96
|
+
/** Signal aborted while building the user-side tool-results message. */
|
|
97
|
+
| "aborted_post_response"
|
|
98
|
+
/** Signal aborted mid-tool-execution; completed results were pushed. */
|
|
99
|
+
| "aborted_during_tools"
|
|
100
|
+
/** A tool result requested handing back to the user. */
|
|
101
|
+
| "yield_to_user"
|
|
102
|
+
/** The orchestrator yielded at checkpoint to process a queued message. */
|
|
103
|
+
| "checkpoint_handoff"
|
|
104
|
+
/** Context-window recovery exhausted and the turn ended with an error. */
|
|
105
|
+
| "context_too_large"
|
|
106
|
+
/** User cancellation landed after a non-terminal checkpoint yield. */
|
|
107
|
+
| "aborted_after_checkpoint"
|
|
108
|
+
/** Signal aborted while the catch handler was synthesizing an error turn. */
|
|
109
|
+
| "aborted_via_error"
|
|
110
|
+
/** Catch-block fallback: an unhandled error broke the loop. */
|
|
111
|
+
| "error";
|
|
112
|
+
|
|
70
113
|
export type AgentEvent =
|
|
71
114
|
| { type: "text_delta"; text: string }
|
|
72
115
|
| { type: "thinking_delta"; thinking: string }
|
|
@@ -105,6 +148,7 @@ export type AgentEvent =
|
|
|
105
148
|
approvalMode?: string;
|
|
106
149
|
approvalReason?: string;
|
|
107
150
|
riskThreshold?: string;
|
|
151
|
+
activityMetadata?: ToolActivityMetadata;
|
|
108
152
|
}
|
|
109
153
|
| { type: "tool_use_preview_start"; toolUseId: string; toolName: string }
|
|
110
154
|
| {
|
|
@@ -124,8 +168,45 @@ export type AgentEvent =
|
|
|
124
168
|
toolUseId: string;
|
|
125
169
|
isError: boolean;
|
|
126
170
|
content?: unknown[];
|
|
171
|
+
/**
|
|
172
|
+
* Finalized input for the server tool (e.g. the actual web-search
|
|
173
|
+
* query). Carried through so the daemon can populate accurate activity
|
|
174
|
+
* metadata; Anthropic streams server-tool input via deltas that aren't
|
|
175
|
+
* resolved at `server_tool_start` time.
|
|
176
|
+
*/
|
|
177
|
+
resolvedInput?: Record<string, unknown>;
|
|
178
|
+
/** Provider-specific error code (e.g. `max_uses_exceeded`). */
|
|
179
|
+
errorCode?: string;
|
|
180
|
+
/** Optional human-readable error message from the provider. */
|
|
181
|
+
errorMessage?: string;
|
|
127
182
|
}
|
|
128
183
|
| { type: "error"; error: Error }
|
|
184
|
+
| {
|
|
185
|
+
/**
|
|
186
|
+
* Emitted when the `llmCall` pipeline throws — i.e. the provider
|
|
187
|
+
* rejected the request before returning a usable response. Carries
|
|
188
|
+
* the loop-level raw request we attempted to send (messages, tools,
|
|
189
|
+
* system prompt, provider-agnostic config) plus the thrown error.
|
|
190
|
+
* Consumers (`handleProviderError` in the daemon handlers, the
|
|
191
|
+
* `onEvent` in `agent-wake`) persist these as `llm_request_logs`
|
|
192
|
+
* rows so failed calls are queryable in the LLM inspector instead
|
|
193
|
+
* of only surfacing in pino logs.
|
|
194
|
+
*
|
|
195
|
+
* `rawRequest` is the loop-level abstract shape rather than the
|
|
196
|
+
* provider-specific payload (which the provider builds internally
|
|
197
|
+
* and never returns when it throws). `actualProvider` echoes the
|
|
198
|
+
* `ProviderError.provider` tag when available so the persisted row
|
|
199
|
+
* has the same `provider` column value as a successful `usage` row.
|
|
200
|
+
*
|
|
201
|
+
* Re-thrown by the inner LLM-call try/catch after emission so the
|
|
202
|
+
* outer agent-loop catch still handles abort, Sentry capture, the
|
|
203
|
+
* existing `error` event, and the loop break.
|
|
204
|
+
*/
|
|
205
|
+
type: "provider_error";
|
|
206
|
+
rawRequest: unknown;
|
|
207
|
+
error: Error;
|
|
208
|
+
actualProvider?: string;
|
|
209
|
+
}
|
|
129
210
|
| {
|
|
130
211
|
type: "usage";
|
|
131
212
|
inputTokens: number;
|
|
@@ -144,6 +225,19 @@ export type AgentEvent =
|
|
|
144
225
|
* for this call (e.g. legacy/stubbed code paths).
|
|
145
226
|
*/
|
|
146
227
|
estimatedInputTokens?: number;
|
|
228
|
+
}
|
|
229
|
+
| {
|
|
230
|
+
/**
|
|
231
|
+
* Emitted when an agent turn reaches a terminal state. Checkpoint
|
|
232
|
+
* yields used for orchestration (handoff or budget compaction) are not
|
|
233
|
+
* emitted by {@link AgentLoop.run}; the outer orchestrator emits a
|
|
234
|
+
* terminal reason only if that control transfer truly ends the turn.
|
|
235
|
+
* Consumers persist `reason` onto the final `llm_request_logs` row;
|
|
236
|
+
* intermediate rows keep `agent_loop_exit_reason = NULL`, which is the
|
|
237
|
+
* canonical "loop kept going" signal.
|
|
238
|
+
*/
|
|
239
|
+
type: "agent_loop_exit";
|
|
240
|
+
reason: AgentLoopExitReason;
|
|
147
241
|
};
|
|
148
242
|
|
|
149
243
|
const DEFAULT_CONFIG: AgentLoopConfig = {
|
|
@@ -296,6 +390,7 @@ export type LoopToolExecutor = (
|
|
|
296
390
|
approvalMode?: string;
|
|
297
391
|
approvalReason?: string;
|
|
298
392
|
riskThreshold?: string;
|
|
393
|
+
activityMetadata?: ToolActivityMetadata;
|
|
299
394
|
}>;
|
|
300
395
|
|
|
301
396
|
export class AgentLoop {
|
|
@@ -383,6 +478,8 @@ export class AgentLoop {
|
|
|
383
478
|
*/
|
|
384
479
|
overrideProfile?: string,
|
|
385
480
|
effectiveMaxInputTokens?: number,
|
|
481
|
+
resolveOverrideProfile?: () => string | undefined,
|
|
482
|
+
resolveEffectiveMaxInputTokens?: () => number | undefined,
|
|
386
483
|
): Promise<Message[]> {
|
|
387
484
|
const history = [...messages];
|
|
388
485
|
const initialHistoryLength = messages.length;
|
|
@@ -398,8 +495,24 @@ export class AgentLoop {
|
|
|
398
495
|
const substitutionMap = new Map<string, string>();
|
|
399
496
|
let streamingPending = "";
|
|
400
497
|
|
|
498
|
+
// Idempotency guard for `emitExit`. Used so the throw path in the
|
|
499
|
+
// empty-response branch can stamp its reason ("empty_response_exhausted")
|
|
500
|
+
// before throwing — the catch handler that observes the rethrow will
|
|
501
|
+
// then attempt to stamp "error" and harmlessly no-op, preserving the
|
|
502
|
+
// more specific reason. Also defends against accidental future
|
|
503
|
+
// double-emits if a new break site is added without checking this.
|
|
504
|
+
let exitReasonEmitted = false;
|
|
505
|
+
const emitExit = async (reason: AgentLoopExitReason): Promise<void> => {
|
|
506
|
+
if (exitReasonEmitted) return;
|
|
507
|
+
exitReasonEmitted = true;
|
|
508
|
+
await onEvent({ type: "agent_loop_exit", reason });
|
|
509
|
+
};
|
|
510
|
+
|
|
401
511
|
while (true) {
|
|
402
|
-
if (signal?.aborted)
|
|
512
|
+
if (signal?.aborted) {
|
|
513
|
+
await emitExit("aborted_pre_call");
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
403
516
|
|
|
404
517
|
rlog.info(
|
|
405
518
|
{ turn: toolUseTurns, messageCount: history.length },
|
|
@@ -489,9 +602,14 @@ export class AgentLoop {
|
|
|
489
602
|
// `activeProfile` and any call-site named profile. Threading it on
|
|
490
603
|
// every send (rather than once at construction) keeps subagents that
|
|
491
604
|
// share an `AgentLoop` instance but ought to inherit a different
|
|
492
|
-
// profile correct — and matches how `callSite` is plumbed.
|
|
493
|
-
|
|
494
|
-
|
|
605
|
+
// profile correct — and matches how `callSite` is plumbed. The
|
|
606
|
+
// optional resolver lets a turn observe an explicitly confirmed
|
|
607
|
+
// profile-session switch before the next model call.
|
|
608
|
+
const effectiveOverrideProfile = resolveOverrideProfile
|
|
609
|
+
? resolveOverrideProfile()
|
|
610
|
+
: overrideProfile;
|
|
611
|
+
if (effectiveOverrideProfile) {
|
|
612
|
+
providerConfig.overrideProfile = effectiveOverrideProfile;
|
|
495
613
|
}
|
|
496
614
|
|
|
497
615
|
// Rate-limit consecutive LLM calls to prevent spin when tools return instantly
|
|
@@ -599,6 +717,13 @@ export class AgentLoop {
|
|
|
599
717
|
toolUseId: event.toolUseId,
|
|
600
718
|
isError: event.isError,
|
|
601
719
|
...(event.content ? { content: event.content } : {}),
|
|
720
|
+
...(event.resolvedInput
|
|
721
|
+
? { resolvedInput: event.resolvedInput }
|
|
722
|
+
: {}),
|
|
723
|
+
...(event.errorCode ? { errorCode: event.errorCode } : {}),
|
|
724
|
+
...(event.errorMessage
|
|
725
|
+
? { errorMessage: event.errorMessage }
|
|
726
|
+
: {}),
|
|
602
727
|
});
|
|
603
728
|
}
|
|
604
729
|
},
|
|
@@ -618,23 +743,64 @@ export class AgentLoop {
|
|
|
618
743
|
toolUseTurns,
|
|
619
744
|
);
|
|
620
745
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
746
|
+
// Inner try/catch narrows error-recording scope to the provider
|
|
747
|
+
// call itself. The outer agent-loop catch (below) wraps the entire
|
|
748
|
+
// turn body (tool execution, plugin pipelines, checkpoints), so
|
|
749
|
+
// recording there would risk mis-attributing tool/plugin throws as
|
|
750
|
+
// provider rejections. On provider failure we emit `provider_error`
|
|
751
|
+
// with the loop-level raw request so consumers can persist it as an
|
|
752
|
+
// `llm_request_logs` row, then re-throw so the existing outer catch
|
|
753
|
+
// continues to handle abort sync, Sentry capture, the `error` event,
|
|
754
|
+
// and the loop break unchanged.
|
|
755
|
+
let response: LLMCallResult;
|
|
756
|
+
try {
|
|
757
|
+
response = await runPipeline<LLMCallArgs, LLMCallResult>(
|
|
758
|
+
"llmCall",
|
|
759
|
+
getMiddlewaresFor("llmCall"),
|
|
760
|
+
(args) =>
|
|
761
|
+
args.provider.sendMessage(
|
|
762
|
+
args.messages,
|
|
763
|
+
args.tools,
|
|
764
|
+
args.systemPrompt,
|
|
765
|
+
args.options,
|
|
766
|
+
),
|
|
767
|
+
llmCallArgs,
|
|
768
|
+
turnCtx,
|
|
769
|
+
DEFAULT_TIMEOUTS.llmCall,
|
|
770
|
+
);
|
|
771
|
+
} catch (llmCallError) {
|
|
772
|
+
// Skip recording on abort — the user cancelled the request and
|
|
773
|
+
// there's no provider rejection worth a log row. The outer catch
|
|
774
|
+
// still synthesizes cancellation tool_results.
|
|
775
|
+
if (!signal?.aborted) {
|
|
776
|
+
const errInstance =
|
|
777
|
+
llmCallError instanceof Error
|
|
778
|
+
? llmCallError
|
|
779
|
+
: new Error(String(llmCallError));
|
|
780
|
+
// Strip non-serializable / runtime-only fields from `options`
|
|
781
|
+
// before snapshotting. `onEvent` is a closure with side effects
|
|
782
|
+
// and `signal` is an AbortSignal — neither is meaningful in a
|
|
783
|
+
// persisted log row, and `JSON.stringify` would silently drop or
|
|
784
|
+
// misrepresent both.
|
|
785
|
+
const rawRequest = {
|
|
786
|
+
provider: this.provider.name,
|
|
787
|
+
messages: llmCallArgs.messages,
|
|
788
|
+
tools: llmCallArgs.tools,
|
|
789
|
+
systemPrompt: llmCallArgs.systemPrompt,
|
|
790
|
+
config: llmCallArgs.options?.config,
|
|
791
|
+
};
|
|
792
|
+
onEvent({
|
|
793
|
+
type: "provider_error",
|
|
794
|
+
rawRequest,
|
|
795
|
+
error: errInstance,
|
|
796
|
+
actualProvider:
|
|
797
|
+
errInstance instanceof ProviderError
|
|
798
|
+
? errInstance.provider
|
|
799
|
+
: this.provider.name,
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
throw llmCallError;
|
|
803
|
+
}
|
|
638
804
|
|
|
639
805
|
const providerDurationMs = Date.now() - providerStart;
|
|
640
806
|
|
|
@@ -785,6 +951,11 @@ export class AgentLoop {
|
|
|
785
951
|
{ turn: toolUseTurns, retries: emptyResponseRetries },
|
|
786
952
|
"emptyResponse pipeline requested error surface",
|
|
787
953
|
);
|
|
954
|
+
// Stamp the specific exit reason *before* throwing. The catch
|
|
955
|
+
// handler below will see the rethrown error and attempt to stamp
|
|
956
|
+
// "error" — guarded by `exitReasonEmitted`, that becomes a no-op
|
|
957
|
+
// and the more specific reason wins.
|
|
958
|
+
await emitExit("empty_response_exhausted");
|
|
788
959
|
throw new AssistantError(
|
|
789
960
|
"Model returned empty response after tool results",
|
|
790
961
|
ErrorCode.INTERNAL_ERROR,
|
|
@@ -811,6 +982,7 @@ export class AgentLoop {
|
|
|
811
982
|
await onEvent({ type: "message_complete", message: assistantMessage });
|
|
812
983
|
|
|
813
984
|
if (toolUseBlocks.length === 0 || !this.toolExecutor) {
|
|
985
|
+
await emitExit("no_tool_calls");
|
|
814
986
|
break;
|
|
815
987
|
}
|
|
816
988
|
|
|
@@ -835,6 +1007,7 @@ export class AgentLoop {
|
|
|
835
1007
|
}),
|
|
836
1008
|
);
|
|
837
1009
|
history.push({ role: "user", content: cancelledBlocks });
|
|
1010
|
+
await emitExit("aborted_post_response");
|
|
838
1011
|
break;
|
|
839
1012
|
}
|
|
840
1013
|
|
|
@@ -940,7 +1113,10 @@ export class AgentLoop {
|
|
|
940
1113
|
// truncation strategy (e.g. a summariser) while the default
|
|
941
1114
|
// middleware preserves the historical tail-drop behaviour.
|
|
942
1115
|
const contextWindowTokens =
|
|
943
|
-
|
|
1116
|
+
resolveEffectiveMaxInputTokens?.() ??
|
|
1117
|
+
effectiveMaxInputTokens ??
|
|
1118
|
+
this.config.maxInputTokens ??
|
|
1119
|
+
180_000;
|
|
944
1120
|
const maxChars = calculateMaxToolResultChars(contextWindowTokens);
|
|
945
1121
|
const truncateMiddlewares = getMiddlewaresFor("toolResultTruncate");
|
|
946
1122
|
|
|
@@ -1016,12 +1192,14 @@ export class AgentLoop {
|
|
|
1016
1192
|
approvalMode: result.approvalMode,
|
|
1017
1193
|
approvalReason: result.approvalReason,
|
|
1018
1194
|
riskThreshold: result.riskThreshold,
|
|
1195
|
+
activityMetadata: result.activityMetadata,
|
|
1019
1196
|
});
|
|
1020
1197
|
}
|
|
1021
1198
|
|
|
1022
1199
|
// If cancelled during execution, push completed results and stop
|
|
1023
1200
|
if (signal?.aborted) {
|
|
1024
1201
|
history.push({ role: "user", content: resultBlocks });
|
|
1202
|
+
await emitExit("aborted_during_tools");
|
|
1025
1203
|
break;
|
|
1026
1204
|
}
|
|
1027
1205
|
|
|
@@ -1029,6 +1207,7 @@ export class AgentLoop {
|
|
|
1029
1207
|
// surface awaiting a button click), push results and stop the loop.
|
|
1030
1208
|
if (toolResults.some(({ result }) => result.yieldToUser)) {
|
|
1031
1209
|
history.push({ role: "user", content: resultBlocks });
|
|
1210
|
+
await emitExit("yield_to_user");
|
|
1032
1211
|
break;
|
|
1033
1212
|
}
|
|
1034
1213
|
|
|
@@ -1114,6 +1293,7 @@ export class AgentLoop {
|
|
|
1114
1293
|
);
|
|
1115
1294
|
history.push({ role: "user", content: cancelledBlocks });
|
|
1116
1295
|
}
|
|
1296
|
+
await emitExit("aborted_via_error");
|
|
1117
1297
|
break;
|
|
1118
1298
|
}
|
|
1119
1299
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
@@ -1125,6 +1305,12 @@ export class AgentLoop {
|
|
|
1125
1305
|
Sentry.captureException(err);
|
|
1126
1306
|
}
|
|
1127
1307
|
onEvent({ type: "error", error: err });
|
|
1308
|
+
// Catch-block fallback. If the rethrow came from the
|
|
1309
|
+
// empty-response throw path above, `emitExit("error")` no-ops
|
|
1310
|
+
// because `emitExit("empty_response_exhausted")` already ran
|
|
1311
|
+
// before the throw. Otherwise, this is the genuine
|
|
1312
|
+
// unhandled-error exit.
|
|
1313
|
+
await emitExit("error");
|
|
1128
1314
|
break;
|
|
1129
1315
|
}
|
|
1130
1316
|
}
|