@vellumai/assistant 0.8.5 → 0.8.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/AGENTS.md +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type pino from "pino";
|
|
10
|
+
import { v4 as uuid } from "uuid";
|
|
10
11
|
|
|
11
12
|
import type { AgentEvent } from "../agent/loop.js";
|
|
12
13
|
import type {
|
|
@@ -16,12 +17,16 @@ import type {
|
|
|
16
17
|
import { getConfig } from "../config/loader.js";
|
|
17
18
|
import { recordEstimate } from "../context/estimator-calibration.js";
|
|
18
19
|
import { getCalibrationProviderKey } from "../context/token-estimator.js";
|
|
20
|
+
import { projectAssistantMessage } from "../memory/conversation-attention-store.js";
|
|
19
21
|
import {
|
|
22
|
+
deleteMessageById,
|
|
20
23
|
getConversation,
|
|
21
24
|
getMessageById,
|
|
25
|
+
messageMetadataSchema,
|
|
22
26
|
provenanceFromTrustContext,
|
|
23
27
|
updateMessageContent,
|
|
24
28
|
} from "../memory/conversation-crud.js";
|
|
29
|
+
import { indexMessageNow } from "../memory/indexer.js";
|
|
25
30
|
import {
|
|
26
31
|
backfillMessageIdOnLogs,
|
|
27
32
|
buildProviderErrorResponsePayload,
|
|
@@ -40,15 +45,20 @@ import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
|
40
45
|
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
41
46
|
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
42
47
|
import type {
|
|
43
|
-
PersistAddResult,
|
|
44
48
|
PersistArgs,
|
|
49
|
+
PersistReserveResult,
|
|
45
50
|
PersistResult,
|
|
46
51
|
TurnContext,
|
|
47
52
|
} from "../plugins/types.js";
|
|
48
53
|
import type { ContentBlock, ImageContent } from "../providers/types.js";
|
|
49
54
|
import { isContextOverflowError } from "../providers/types.js";
|
|
55
|
+
import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
|
|
50
56
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
51
57
|
import { extractDomain } from "../tools/network/domain-normalize.js";
|
|
58
|
+
import {
|
|
59
|
+
buildPricingUsage,
|
|
60
|
+
resolveStructuredPricing,
|
|
61
|
+
} from "../usage/pricing.js";
|
|
52
62
|
import { ProviderError } from "../util/errors.js";
|
|
53
63
|
import { faviconUrlForDomain } from "../util/favicon.js";
|
|
54
64
|
import { getLogger } from "../util/logger.js";
|
|
@@ -62,10 +72,17 @@ import {
|
|
|
62
72
|
buildConversationErrorMessage,
|
|
63
73
|
classifyConversationError,
|
|
64
74
|
isContextTooLarge,
|
|
75
|
+
maxTokensReachedClassification,
|
|
65
76
|
} from "./conversation-error.js";
|
|
66
77
|
import { isProviderOrderingError } from "./conversation-slash.js";
|
|
67
78
|
import { resolveTurnTimezoneContext } from "./date-context.js";
|
|
68
|
-
import type {
|
|
79
|
+
import type {
|
|
80
|
+
CardSurfaceData,
|
|
81
|
+
ServerMessage,
|
|
82
|
+
SurfaceAction,
|
|
83
|
+
UiSurfaceShow,
|
|
84
|
+
} from "./message-protocol.js";
|
|
85
|
+
import { conversationMetadataSyncTag } from "./message-types/sync.js";
|
|
69
86
|
import type {
|
|
70
87
|
WebSearchMetadata,
|
|
71
88
|
WebSearchResultItem,
|
|
@@ -145,6 +162,21 @@ export interface EventHandlerState {
|
|
|
145
162
|
contextTooLargeError: unknown;
|
|
146
163
|
providerErrorUserMessage: string | null;
|
|
147
164
|
lastAssistantMessageId: string | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* True when `handleLlmCallStarted` has reserved an empty assistant row
|
|
167
|
+
* that has NOT yet been finalized via `handleMessageComplete`
|
|
168
|
+
* (`op:"updateContent"` + indexing + projection). Used by error/retry
|
|
169
|
+
* paths to detect a stranded reservation that must be cleaned up
|
|
170
|
+
* before the next LLM call reserves a fresh row — without it, every
|
|
171
|
+
* retryable failure (overflow, ordering, image overflow) and every
|
|
172
|
+
* terminal provider rejection would leak an empty assistant bubble
|
|
173
|
+
* into the transcript and mispoint downstream sync/projection.
|
|
174
|
+
*
|
|
175
|
+
* Cleared by `handleMessageComplete` on successful finalize, and by
|
|
176
|
+
* the synthetic-error branch in `conversation-agent-loop.ts` after it
|
|
177
|
+
* absorbs the reserved row into the error message.
|
|
178
|
+
*/
|
|
179
|
+
assistantRowAwaitingFinalization: boolean;
|
|
148
180
|
readonly pendingToolResults: Map<string, PendingToolResult>;
|
|
149
181
|
readonly persistedToolUseIds: Set<string>;
|
|
150
182
|
readonly accumulatedDirectives: DirectiveRequest[];
|
|
@@ -245,6 +277,7 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
245
277
|
contextTooLargeError: null,
|
|
246
278
|
providerErrorUserMessage: null,
|
|
247
279
|
lastAssistantMessageId: undefined,
|
|
280
|
+
assistantRowAwaitingFinalization: false,
|
|
248
281
|
pendingToolResults: new Map(),
|
|
249
282
|
persistedToolUseIds: new Set(),
|
|
250
283
|
accumulatedDirectives: [],
|
|
@@ -307,6 +340,9 @@ function emitLlmCallStartedIfNeeded(
|
|
|
307
340
|
// tools the client discards it (extractCodePreview only handles app tools),
|
|
308
341
|
// so we skip forwarding entirely to avoid transport/decode overhead.
|
|
309
342
|
const APP_TOOL_NAMES = new Set(["app_create"]);
|
|
343
|
+
const MAX_TOKENS_CONTINUE_PROMPT =
|
|
344
|
+
"Continue from where you stopped. Do not repeat content you've already sent.";
|
|
345
|
+
const MAX_TOKENS_SURFACE_COMPLETION_SUMMARY = "Continue";
|
|
310
346
|
|
|
311
347
|
// ── Friendly Tool Names ──────────────────────────────────────────────
|
|
312
348
|
|
|
@@ -389,6 +425,133 @@ function resolveAssistantReplyTimestampTimezone(
|
|
|
389
425
|
}).effectiveTimezone;
|
|
390
426
|
}
|
|
391
427
|
|
|
428
|
+
/**
|
|
429
|
+
* Assemble the metadata envelope written to the assistant message row.
|
|
430
|
+
*
|
|
431
|
+
* Stamped at reserve time (before `provider.sendMessage`) so the row carries
|
|
432
|
+
* channel provenance from the moment it lands in SQLite, mirroring the
|
|
433
|
+
* snapshot that handleMessageComplete used to compute at end-of-turn. All
|
|
434
|
+
* inputs (channel context, trust context, turnStartedAt) are stable across
|
|
435
|
+
* the LLM call, so building this once at reserve is equivalent to building
|
|
436
|
+
* it at complete. Slack reply rows further stamp a `slackMeta` sub-object —
|
|
437
|
+
* the `channelTs` field stays absent here and is back-filled by
|
|
438
|
+
* `deliverReplyViaCallback` after the gateway returns the ts.
|
|
439
|
+
*/
|
|
440
|
+
function buildAssistantChannelMetadata(
|
|
441
|
+
state: EventHandlerState,
|
|
442
|
+
deps: EventHandlerDeps,
|
|
443
|
+
): Record<string, unknown> {
|
|
444
|
+
const metadata: Record<string, unknown> = {
|
|
445
|
+
...provenanceFromTrustContext(deps.ctx.trustContext),
|
|
446
|
+
userMessageChannel: deps.turnChannelContext.userMessageChannel,
|
|
447
|
+
assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
|
|
448
|
+
userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
|
|
449
|
+
assistantMessageInterface:
|
|
450
|
+
deps.turnInterfaceContext.assistantMessageInterface,
|
|
451
|
+
sentAt: state.turnStartedAt,
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
if (deps.turnChannelContext.assistantMessageChannel === "slack") {
|
|
455
|
+
const channelId = deps.ctx.trustContext?.requesterChatId;
|
|
456
|
+
if (channelId) {
|
|
457
|
+
const threadTs = getThreadTs(deps.ctx.conversationId);
|
|
458
|
+
const timestampTimezone = resolveAssistantReplyTimestampTimezone(
|
|
459
|
+
deps.ctx,
|
|
460
|
+
);
|
|
461
|
+
const timestampTimezoneLabel = formatSlackTimezoneLabel(
|
|
462
|
+
timestampTimezone,
|
|
463
|
+
{ nowMs: state.turnStartedAt },
|
|
464
|
+
);
|
|
465
|
+
const partialSlackMeta: Partial<SlackMessageMetadata> = {
|
|
466
|
+
source: "slack",
|
|
467
|
+
eventKind: "message",
|
|
468
|
+
channelId,
|
|
469
|
+
...(threadTs ? { threadTs } : {}),
|
|
470
|
+
timestampTimezone,
|
|
471
|
+
...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
|
|
472
|
+
};
|
|
473
|
+
// `channelTs` is filled in by the post-send reconciliation step in
|
|
474
|
+
// `deliverReplyViaCallback`; cast through the Partial to satisfy
|
|
475
|
+
// the writer's type at this pre-send boundary.
|
|
476
|
+
metadata.slackMeta = writeSlackMetadata(
|
|
477
|
+
partialSlackMeta as SlackMessageMetadata,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return metadata;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Reserve an empty assistant row for the LLM call about to begin, stash
|
|
487
|
+
* its id on `state.lastAssistantMessageId`, and announce the boundary on
|
|
488
|
+
* the wire via `assistant_turn_start`.
|
|
489
|
+
*
|
|
490
|
+
* Awaited so the row exists and the client has the anchor id BEFORE any
|
|
491
|
+
* streaming delta arrives — every subsequent `deps.onEvent` in this LLM
|
|
492
|
+
* call stamps `messageId: state.lastAssistantMessageId`, and
|
|
493
|
+
* `handleMessageComplete` flushes the final content to the same row via
|
|
494
|
+
* `op: "updateContent"` instead of inserting a fresh one.
|
|
495
|
+
*
|
|
496
|
+
* Multi-LLM-call agent turns (LLM call → tool execution → LLM call) emit
|
|
497
|
+
* one `llm_call_started` per call, so each LLM call reserves its own row.
|
|
498
|
+
* The read-path `findDisplayTurnEndIndex` collapses consecutive assistant
|
|
499
|
+
* rows for the merged history view, matching today's per-call DB layout.
|
|
500
|
+
*/
|
|
501
|
+
export async function handleLlmCallStarted(
|
|
502
|
+
state: EventHandlerState,
|
|
503
|
+
deps: EventHandlerDeps,
|
|
504
|
+
): Promise<void> {
|
|
505
|
+
// Clean up an orphaned reservation from a previous LLM call in this run
|
|
506
|
+
// that errored before `message_complete` could finalize it. This covers
|
|
507
|
+
// the retryable paths (overflow, ordering, image overflow) where the
|
|
508
|
+
// agent loop re-enters with a fresh `run()` and reserves another row;
|
|
509
|
+
// without this delete the failed-attempt row stays in the transcript as
|
|
510
|
+
// an empty assistant bubble. The finalized-row case is filtered out via
|
|
511
|
+
// the `assistantRowAwaitingFinalization` flag — `handleMessageComplete`
|
|
512
|
+
// clears it after the successful `updateContent`, so the previous call's
|
|
513
|
+
// committed row is never touched here.
|
|
514
|
+
//
|
|
515
|
+
// Direct `deleteMessageById` (not via the `persistence` pipeline) is
|
|
516
|
+
// intentional: a never-finalized reservation has no segments, no
|
|
517
|
+
// attachments, and no observable history — undoing it isn't a real
|
|
518
|
+
// persistence event for plugins to react to, so routing through the
|
|
519
|
+
// pipeline would only widen the mock surface for no observability win.
|
|
520
|
+
if (state.assistantRowAwaitingFinalization && state.lastAssistantMessageId) {
|
|
521
|
+
try {
|
|
522
|
+
deleteMessageById(state.lastAssistantMessageId);
|
|
523
|
+
} catch (err) {
|
|
524
|
+
// Non-fatal: a leaked empty row is preferable to a turn-level throw.
|
|
525
|
+
deps.rlog.warn(
|
|
526
|
+
{ err, messageId: state.lastAssistantMessageId },
|
|
527
|
+
"Failed to clean up stranded reserved assistant row before new reservation",
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const metadata = buildAssistantChannelMetadata(state, deps);
|
|
533
|
+
const reserveResult = (await runPipeline<PersistArgs, PersistResult>(
|
|
534
|
+
"persistence",
|
|
535
|
+
getMiddlewaresFor("persistence"),
|
|
536
|
+
defaultPersistenceTerminal,
|
|
537
|
+
{
|
|
538
|
+
op: "reserve",
|
|
539
|
+
conversationId: deps.ctx.conversationId,
|
|
540
|
+
role: "assistant",
|
|
541
|
+
metadata,
|
|
542
|
+
},
|
|
543
|
+
buildHandlerTurnContext(deps),
|
|
544
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
545
|
+
)) as PersistReserveResult;
|
|
546
|
+
state.lastAssistantMessageId = reserveResult.message.id;
|
|
547
|
+
state.assistantRowAwaitingFinalization = true;
|
|
548
|
+
deps.onEvent({
|
|
549
|
+
type: "assistant_turn_start",
|
|
550
|
+
messageId: reserveResult.message.id,
|
|
551
|
+
conversationId: deps.ctx.conversationId,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
392
555
|
// ── Individual Handlers ──────────────────────────────────────────────
|
|
393
556
|
|
|
394
557
|
function handleTextDelta(
|
|
@@ -417,6 +580,7 @@ function handleTextDelta(
|
|
|
417
580
|
type: "assistant_text_delta",
|
|
418
581
|
text: drained.emitText,
|
|
419
582
|
conversationId: deps.ctx.conversationId,
|
|
583
|
+
messageId: state.lastAssistantMessageId,
|
|
420
584
|
});
|
|
421
585
|
if (deps.shouldGenerateTitle) state.firstAssistantText += drained.emitText;
|
|
422
586
|
}
|
|
@@ -454,6 +618,7 @@ function handleThinkingDelta(
|
|
|
454
618
|
type: "assistant_thinking_delta",
|
|
455
619
|
thinking: event.thinking,
|
|
456
620
|
conversationId: deps.ctx.conversationId,
|
|
621
|
+
messageId: state.lastAssistantMessageId,
|
|
457
622
|
});
|
|
458
623
|
}
|
|
459
624
|
|
|
@@ -484,11 +649,12 @@ export function handleToolUse(
|
|
|
484
649
|
input: event.input,
|
|
485
650
|
conversationId: deps.ctx.conversationId,
|
|
486
651
|
toolUseId: event.id,
|
|
652
|
+
messageId: state.lastAssistantMessageId,
|
|
487
653
|
});
|
|
488
654
|
}
|
|
489
655
|
|
|
490
656
|
export function handleToolUsePreviewStart(
|
|
491
|
-
|
|
657
|
+
state: EventHandlerState,
|
|
492
658
|
deps: EventHandlerDeps,
|
|
493
659
|
event: Extract<AgentEvent, { type: "tool_use_preview_start" }>,
|
|
494
660
|
): void {
|
|
@@ -497,6 +663,7 @@ export function handleToolUsePreviewStart(
|
|
|
497
663
|
toolUseId: event.toolUseId,
|
|
498
664
|
toolName: event.toolName,
|
|
499
665
|
conversationId: deps.ctx.conversationId,
|
|
666
|
+
messageId: state.lastAssistantMessageId,
|
|
500
667
|
});
|
|
501
668
|
const statusText = `Preparing ${friendlyToolName(event.toolName)}...`;
|
|
502
669
|
deps.ctx.emitActivityState(
|
|
@@ -509,7 +676,7 @@ export function handleToolUsePreviewStart(
|
|
|
509
676
|
}
|
|
510
677
|
|
|
511
678
|
function handleToolOutputChunk(
|
|
512
|
-
|
|
679
|
+
state: EventHandlerState,
|
|
513
680
|
deps: EventHandlerDeps,
|
|
514
681
|
event: Extract<AgentEvent, { type: "tool_output_chunk" }>,
|
|
515
682
|
): void {
|
|
@@ -567,6 +734,7 @@ function handleToolOutputChunk(
|
|
|
567
734
|
chunk: event.chunk,
|
|
568
735
|
conversationId: deps.ctx.conversationId,
|
|
569
736
|
toolUseId: event.toolUseId,
|
|
737
|
+
messageId: state.lastAssistantMessageId,
|
|
570
738
|
subType: structured.subType,
|
|
571
739
|
subToolName: structured.subToolName,
|
|
572
740
|
subToolInput: structured.subToolInput,
|
|
@@ -579,12 +747,13 @@ function handleToolOutputChunk(
|
|
|
579
747
|
chunk: event.chunk,
|
|
580
748
|
conversationId: deps.ctx.conversationId,
|
|
581
749
|
toolUseId: event.toolUseId,
|
|
750
|
+
messageId: state.lastAssistantMessageId,
|
|
582
751
|
});
|
|
583
752
|
}
|
|
584
753
|
}
|
|
585
754
|
|
|
586
755
|
export function handleInputJsonDelta(
|
|
587
|
-
|
|
756
|
+
state: EventHandlerState,
|
|
588
757
|
deps: EventHandlerDeps,
|
|
589
758
|
event: Extract<AgentEvent, { type: "input_json_delta" }>,
|
|
590
759
|
): void {
|
|
@@ -598,6 +767,7 @@ export function handleInputJsonDelta(
|
|
|
598
767
|
content: event.accumulatedJson,
|
|
599
768
|
conversationId: deps.ctx.conversationId,
|
|
600
769
|
toolUseId: event.toolUseId,
|
|
770
|
+
messageId: state.lastAssistantMessageId,
|
|
601
771
|
});
|
|
602
772
|
}
|
|
603
773
|
|
|
@@ -724,6 +894,7 @@ export function handleToolResult(
|
|
|
724
894
|
diff: event.diff,
|
|
725
895
|
status: event.status,
|
|
726
896
|
conversationId: deps.ctx.conversationId,
|
|
897
|
+
messageId: state.lastAssistantMessageId,
|
|
727
898
|
imageData: imageDataList?.[0],
|
|
728
899
|
imageDataList,
|
|
729
900
|
toolUseId: event.toolUseId,
|
|
@@ -903,6 +1074,69 @@ function handleError(
|
|
|
903
1074
|
}
|
|
904
1075
|
}
|
|
905
1076
|
|
|
1077
|
+
export function handleMaxTokensReached(
|
|
1078
|
+
_state: EventHandlerState,
|
|
1079
|
+
deps: EventHandlerDeps,
|
|
1080
|
+
event: Extract<AgentEvent, { type: "max_tokens_reached" }>,
|
|
1081
|
+
): void {
|
|
1082
|
+
const classified = maxTokensReachedClassification();
|
|
1083
|
+
const surfaceId = `max_tokens_${uuid()}`;
|
|
1084
|
+
const data: CardSurfaceData = {
|
|
1085
|
+
title: "Response limit reached",
|
|
1086
|
+
subtitle: "The partial response above was saved.",
|
|
1087
|
+
body: classified.userMessage,
|
|
1088
|
+
};
|
|
1089
|
+
const actions: SurfaceAction[] = [
|
|
1090
|
+
{
|
|
1091
|
+
id: "relay_prompt",
|
|
1092
|
+
label: "Continue",
|
|
1093
|
+
style: "primary",
|
|
1094
|
+
data: {
|
|
1095
|
+
prompt: MAX_TOKENS_CONTINUE_PROMPT,
|
|
1096
|
+
_completeSurface: true,
|
|
1097
|
+
_completionSummary: MAX_TOKENS_SURFACE_COMPLETION_SUMMARY,
|
|
1098
|
+
},
|
|
1099
|
+
},
|
|
1100
|
+
];
|
|
1101
|
+
|
|
1102
|
+
deps.ctx.surfaceState.set(surfaceId, {
|
|
1103
|
+
surfaceType: "card",
|
|
1104
|
+
title: data.title,
|
|
1105
|
+
data,
|
|
1106
|
+
actions,
|
|
1107
|
+
});
|
|
1108
|
+
deps.ctx.currentTurnSurfaces.push({
|
|
1109
|
+
surfaceId,
|
|
1110
|
+
surfaceType: "card",
|
|
1111
|
+
title: data.title,
|
|
1112
|
+
data,
|
|
1113
|
+
actions,
|
|
1114
|
+
display: "inline",
|
|
1115
|
+
persistent: true,
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
deps.rlog.warn(
|
|
1119
|
+
{
|
|
1120
|
+
conversationId: deps.ctx.conversationId,
|
|
1121
|
+
stopReason: event.stopReason,
|
|
1122
|
+
surfaceId,
|
|
1123
|
+
},
|
|
1124
|
+
"Surfacing max-tokens continuation card",
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
deps.onEvent({
|
|
1128
|
+
type: "ui_surface_show",
|
|
1129
|
+
conversationId: deps.ctx.conversationId,
|
|
1130
|
+
surfaceId,
|
|
1131
|
+
surfaceType: "card",
|
|
1132
|
+
title: data.title,
|
|
1133
|
+
data,
|
|
1134
|
+
actions,
|
|
1135
|
+
display: "inline",
|
|
1136
|
+
persistent: true,
|
|
1137
|
+
} as UiSurfaceShow);
|
|
1138
|
+
}
|
|
1139
|
+
|
|
906
1140
|
export async function handleMessageComplete(
|
|
907
1141
|
state: EventHandlerState,
|
|
908
1142
|
deps: EventHandlerDeps,
|
|
@@ -917,6 +1151,7 @@ export async function handleMessageComplete(
|
|
|
917
1151
|
type: "assistant_text_delta",
|
|
918
1152
|
text: state.pendingDirectiveDisplayBuffer,
|
|
919
1153
|
conversationId: deps.ctx.conversationId,
|
|
1154
|
+
messageId: state.lastAssistantMessageId,
|
|
920
1155
|
});
|
|
921
1156
|
if (deps.shouldGenerateTitle)
|
|
922
1157
|
state.firstAssistantText += state.pendingDirectiveDisplayBuffer;
|
|
@@ -1023,52 +1258,6 @@ export async function handleMessageComplete(
|
|
|
1023
1258
|
} as unknown as ContentBlock);
|
|
1024
1259
|
}
|
|
1025
1260
|
|
|
1026
|
-
const assistantChannelMetadata: Record<string, unknown> = {
|
|
1027
|
-
...provenanceFromTrustContext(deps.ctx.trustContext),
|
|
1028
|
-
userMessageChannel: deps.turnChannelContext.userMessageChannel,
|
|
1029
|
-
assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
|
|
1030
|
-
userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
|
|
1031
|
-
assistantMessageInterface:
|
|
1032
|
-
deps.turnInterfaceContext.assistantMessageInterface,
|
|
1033
|
-
sentAt: state.turnStartedAt,
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
// When the assistant is replying through Slack, stamp a `slackMeta`
|
|
1037
|
-
// sub-object so the transcript-rendering / thread-aware-context lookup
|
|
1038
|
-
// can identify this row's thread without joining tables.
|
|
1039
|
-
// Persistence happens BEFORE the Slack adapter sends the message, so
|
|
1040
|
-
// Slack's authoritative `ts` (-> `channelTs`) is not yet known and is
|
|
1041
|
-
// intentionally omitted here. The post-send reconciliation step in
|
|
1042
|
-
// `deliverReplyViaCallback` writes `channelTs` back into this row once
|
|
1043
|
-
// the gateway returns the Slack-assigned ts, restoring a fully-formed
|
|
1044
|
-
// metadata envelope before any subsequent turn reads the row.
|
|
1045
|
-
if (deps.turnChannelContext.assistantMessageChannel === "slack") {
|
|
1046
|
-
const channelId = deps.ctx.trustContext?.requesterChatId;
|
|
1047
|
-
if (channelId) {
|
|
1048
|
-
const threadTs = getThreadTs(deps.ctx.conversationId);
|
|
1049
|
-
const timestampTimezone = resolveAssistantReplyTimestampTimezone(
|
|
1050
|
-
deps.ctx,
|
|
1051
|
-
);
|
|
1052
|
-
const timestampTimezoneLabel = formatSlackTimezoneLabel(
|
|
1053
|
-
timestampTimezone,
|
|
1054
|
-
{ nowMs: state.turnStartedAt },
|
|
1055
|
-
);
|
|
1056
|
-
const partialSlackMeta: Partial<SlackMessageMetadata> = {
|
|
1057
|
-
source: "slack",
|
|
1058
|
-
eventKind: "message",
|
|
1059
|
-
channelId,
|
|
1060
|
-
...(threadTs ? { threadTs } : {}),
|
|
1061
|
-
timestampTimezone,
|
|
1062
|
-
...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
|
|
1063
|
-
};
|
|
1064
|
-
assistantChannelMetadata.slackMeta = writeSlackMetadata(
|
|
1065
|
-
// `channelTs` is filled in by the post-send reconciliation step in
|
|
1066
|
-
// `deliverReplyViaCallback`; cast through the Partial to satisfy
|
|
1067
|
-
// the writer's type at this pre-send boundary.
|
|
1068
|
-
partialSlackMeta as SlackMessageMetadata,
|
|
1069
|
-
);
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
1261
|
// Redact known-pattern secrets from assistant text blocks before they are
|
|
1073
1262
|
// written to durable storage. Non-text blocks (images, UI surfaces) pass
|
|
1074
1263
|
// through unchanged. The live model history retains the original values.
|
|
@@ -1080,32 +1269,123 @@ export async function handleMessageComplete(
|
|
|
1080
1269
|
return block;
|
|
1081
1270
|
});
|
|
1082
1271
|
|
|
1083
|
-
//
|
|
1084
|
-
//
|
|
1085
|
-
//
|
|
1086
|
-
//
|
|
1087
|
-
|
|
1272
|
+
// The row was reserved at `llm_call_started` (with channel metadata
|
|
1273
|
+
// stamped at that point) and `state.lastAssistantMessageId` carries its
|
|
1274
|
+
// id. Flush the final content via `updateContent` instead of inserting a
|
|
1275
|
+
// new row. No `syncToDisk` flag here — the orchestrator separately
|
|
1276
|
+
// invokes `syncMessageToDisk` on `state.lastAssistantMessageId` after
|
|
1277
|
+
// the loop completes (see
|
|
1278
|
+
// `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
|
|
1279
|
+
const assistantMessageId = state.lastAssistantMessageId;
|
|
1280
|
+
if (!assistantMessageId) {
|
|
1281
|
+
throw new Error(
|
|
1282
|
+
"handleMessageComplete fired without a prior llm_call_started reserving an assistant row",
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
const contentJson = JSON.stringify(contentForPersistence);
|
|
1286
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
1088
1287
|
"persistence",
|
|
1089
1288
|
getMiddlewaresFor("persistence"),
|
|
1090
1289
|
defaultPersistenceTerminal,
|
|
1091
1290
|
{
|
|
1092
|
-
op: "
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
content: JSON.stringify(contentForPersistence),
|
|
1096
|
-
metadata: assistantChannelMetadata,
|
|
1291
|
+
op: "updateContent",
|
|
1292
|
+
messageId: assistantMessageId,
|
|
1293
|
+
content: contentJson,
|
|
1097
1294
|
},
|
|
1098
1295
|
buildHandlerTurnContext(deps),
|
|
1099
1296
|
DEFAULT_TIMEOUTS.persistence,
|
|
1100
|
-
)
|
|
1101
|
-
|
|
1102
|
-
|
|
1297
|
+
);
|
|
1298
|
+
state.assistantRowAwaitingFinalization = false;
|
|
1299
|
+
|
|
1300
|
+
// ── Indexing + attention projection (restored from the pre-B3 `add` path) ──
|
|
1301
|
+
// `reserveMessage` + `updateMessageContent` are CRUD-only: they don't run
|
|
1302
|
+
// the memory indexer or the attention-cursor projector. The pre-B3 path
|
|
1303
|
+
// wrote the row via `addMessage`, which ran both as side-effects of the
|
|
1304
|
+
// insert. Calling them here keeps the assistant row's external state
|
|
1305
|
+
// (Qdrant segments, conversation attention cursor) in lockstep with the
|
|
1306
|
+
// finalized content. Both are non-fatal — a memory hiccup must not
|
|
1307
|
+
// escalate a successful generation into a turn-level throw. Indexing
|
|
1308
|
+
// intentionally fires AFTER `updateContent` succeeds so we never index
|
|
1309
|
+
// the empty reserved placeholder.
|
|
1310
|
+
const finalizedRow = getMessageById(
|
|
1311
|
+
assistantMessageId,
|
|
1312
|
+
deps.ctx.conversationId,
|
|
1313
|
+
);
|
|
1314
|
+
if (finalizedRow) {
|
|
1315
|
+
let provenanceTrustClass:
|
|
1316
|
+
| "guardian"
|
|
1317
|
+
| "trusted_contact"
|
|
1318
|
+
| "unknown"
|
|
1319
|
+
| undefined;
|
|
1320
|
+
let automated: boolean | undefined;
|
|
1321
|
+
if (finalizedRow.metadata) {
|
|
1322
|
+
try {
|
|
1323
|
+
const parsedMeta = messageMetadataSchema.safeParse(
|
|
1324
|
+
JSON.parse(finalizedRow.metadata),
|
|
1325
|
+
);
|
|
1326
|
+
if (parsedMeta.success) {
|
|
1327
|
+
provenanceTrustClass = parsedMeta.data.provenanceTrustClass;
|
|
1328
|
+
automated = parsedMeta.data.automated;
|
|
1329
|
+
}
|
|
1330
|
+
} catch {
|
|
1331
|
+
// Malformed metadata JSON — fall through with undefined fields,
|
|
1332
|
+
// matching the legacy behavior in `addMessage`.
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
try {
|
|
1336
|
+
await indexMessageNow(
|
|
1337
|
+
{
|
|
1338
|
+
messageId: assistantMessageId,
|
|
1339
|
+
conversationId: deps.ctx.conversationId,
|
|
1340
|
+
role: "assistant",
|
|
1341
|
+
content: contentJson,
|
|
1342
|
+
createdAt: finalizedRow.createdAt,
|
|
1343
|
+
scopeId: "default",
|
|
1344
|
+
provenanceTrustClass,
|
|
1345
|
+
automated,
|
|
1346
|
+
},
|
|
1347
|
+
getConfig().memory,
|
|
1348
|
+
);
|
|
1349
|
+
} catch (err) {
|
|
1350
|
+
deps.rlog.warn(
|
|
1351
|
+
{
|
|
1352
|
+
err,
|
|
1353
|
+
conversationId: deps.ctx.conversationId,
|
|
1354
|
+
messageId: assistantMessageId,
|
|
1355
|
+
},
|
|
1356
|
+
"Failed to index assistant message for memory (non-fatal)",
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
try {
|
|
1360
|
+
const attentionStateChanged = projectAssistantMessage({
|
|
1361
|
+
conversationId: deps.ctx.conversationId,
|
|
1362
|
+
messageId: assistantMessageId,
|
|
1363
|
+
messageAt: finalizedRow.createdAt,
|
|
1364
|
+
});
|
|
1365
|
+
if (attentionStateChanged) {
|
|
1366
|
+
void publishSyncInvalidation([
|
|
1367
|
+
conversationMetadataSyncTag(deps.ctx.conversationId),
|
|
1368
|
+
]);
|
|
1369
|
+
}
|
|
1370
|
+
} catch (err) {
|
|
1371
|
+
deps.rlog.warn(
|
|
1372
|
+
{
|
|
1373
|
+
err,
|
|
1374
|
+
conversationId: deps.ctx.conversationId,
|
|
1375
|
+
messageId: assistantMessageId,
|
|
1376
|
+
},
|
|
1377
|
+
"Failed to project assistant message for attention tracking (non-fatal)",
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1103
1381
|
|
|
1104
1382
|
// Backfill message_id on all LLM request logs from this turn.
|
|
1105
1383
|
// The agent loop is single-threaded per conversation, so all rows with
|
|
1106
|
-
// message_id IS NULL belong to the current turn.
|
|
1384
|
+
// message_id IS NULL belong to the current turn. The reserved id was
|
|
1385
|
+
// available before the LLM call ran but the logs are inserted DURING
|
|
1386
|
+
// the call, so the sweep still runs here.
|
|
1107
1387
|
try {
|
|
1108
|
-
backfillMessageIdOnLogs(deps.ctx.conversationId,
|
|
1388
|
+
backfillMessageIdOnLogs(deps.ctx.conversationId, assistantMessageId);
|
|
1109
1389
|
} catch (err) {
|
|
1110
1390
|
deps.rlog.warn(
|
|
1111
1391
|
{ err },
|
|
@@ -1114,7 +1394,10 @@ export async function handleMessageComplete(
|
|
|
1114
1394
|
}
|
|
1115
1395
|
|
|
1116
1396
|
try {
|
|
1117
|
-
backfillMemoryRecallLogMessageId(
|
|
1397
|
+
backfillMemoryRecallLogMessageId(
|
|
1398
|
+
deps.ctx.conversationId,
|
|
1399
|
+
assistantMessageId,
|
|
1400
|
+
);
|
|
1118
1401
|
} catch (err) {
|
|
1119
1402
|
deps.rlog.warn(
|
|
1120
1403
|
{ err },
|
|
@@ -1125,7 +1408,7 @@ export async function handleMessageComplete(
|
|
|
1125
1408
|
try {
|
|
1126
1409
|
backfillMemoryV2ActivationMessageId(
|
|
1127
1410
|
deps.ctx.conversationId,
|
|
1128
|
-
|
|
1411
|
+
assistantMessageId,
|
|
1129
1412
|
);
|
|
1130
1413
|
} catch (err) {
|
|
1131
1414
|
deps.rlog.warn(
|
|
@@ -1236,6 +1519,36 @@ function handleUsage(
|
|
|
1236
1519
|
},
|
|
1237
1520
|
);
|
|
1238
1521
|
state.llmCallStartedEmitted = false;
|
|
1522
|
+
|
|
1523
|
+
// Emit a lightweight per-call usage progress event so clients can show
|
|
1524
|
+
// live-updating token/cost metrics. This is a UI hint only — no DB writes.
|
|
1525
|
+
const pricingUsage = buildPricingUsage({
|
|
1526
|
+
providerName,
|
|
1527
|
+
model: event.model,
|
|
1528
|
+
inputTokens: event.inputTokens,
|
|
1529
|
+
outputTokens: event.outputTokens,
|
|
1530
|
+
cacheCreationInputTokens: event.cacheCreationInputTokens,
|
|
1531
|
+
cacheReadInputTokens: event.cacheReadInputTokens,
|
|
1532
|
+
rawResponse: event.rawResponse,
|
|
1533
|
+
});
|
|
1534
|
+
const pricing = resolveStructuredPricing(
|
|
1535
|
+
providerName,
|
|
1536
|
+
event.model,
|
|
1537
|
+
pricingUsage,
|
|
1538
|
+
);
|
|
1539
|
+
const estimatedCost =
|
|
1540
|
+
pricing.pricingStatus === "priced" && pricing.estimatedCostUsd != null
|
|
1541
|
+
? pricing.estimatedCostUsd
|
|
1542
|
+
: 0;
|
|
1543
|
+
|
|
1544
|
+
deps.onEvent({
|
|
1545
|
+
type: "usage_progress",
|
|
1546
|
+
conversationId: deps.ctx.conversationId,
|
|
1547
|
+
inputTokens: event.inputTokens,
|
|
1548
|
+
outputTokens: event.outputTokens,
|
|
1549
|
+
estimatedCost,
|
|
1550
|
+
model: event.model,
|
|
1551
|
+
});
|
|
1239
1552
|
}
|
|
1240
1553
|
|
|
1241
1554
|
/**
|
|
@@ -1295,6 +1608,9 @@ export async function dispatchAgentEvent(
|
|
|
1295
1608
|
): Promise<void> {
|
|
1296
1609
|
try {
|
|
1297
1610
|
switch (event.type) {
|
|
1611
|
+
case "llm_call_started":
|
|
1612
|
+
await handleLlmCallStarted(state, deps);
|
|
1613
|
+
break;
|
|
1298
1614
|
case "text_delta":
|
|
1299
1615
|
handleTextDelta(state, deps, event);
|
|
1300
1616
|
break;
|
|
@@ -1335,6 +1651,7 @@ export async function dispatchAgentEvent(
|
|
|
1335
1651
|
input: event.input,
|
|
1336
1652
|
conversationId: deps.ctx.conversationId,
|
|
1337
1653
|
toolUseId: event.toolUseId,
|
|
1654
|
+
messageId: state.lastAssistantMessageId,
|
|
1338
1655
|
});
|
|
1339
1656
|
break;
|
|
1340
1657
|
}
|
|
@@ -1414,6 +1731,7 @@ export async function dispatchAgentEvent(
|
|
|
1414
1731
|
isError: event.isError,
|
|
1415
1732
|
conversationId: deps.ctx.conversationId,
|
|
1416
1733
|
toolUseId: event.toolUseId,
|
|
1734
|
+
messageId: state.lastAssistantMessageId,
|
|
1417
1735
|
...(metadata ? { activityMetadata: { webSearch: metadata } } : {}),
|
|
1418
1736
|
});
|
|
1419
1737
|
break;
|
|
@@ -1421,6 +1739,9 @@ export async function dispatchAgentEvent(
|
|
|
1421
1739
|
case "error":
|
|
1422
1740
|
handleError(state, deps, event);
|
|
1423
1741
|
break;
|
|
1742
|
+
case "max_tokens_reached":
|
|
1743
|
+
handleMaxTokensReached(state, deps, event);
|
|
1744
|
+
break;
|
|
1424
1745
|
case "provider_error":
|
|
1425
1746
|
handleProviderError(deps, event);
|
|
1426
1747
|
break;
|