@vellumai/assistant 0.8.4 → 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 +3 -3
- package/bunfig.toml +6 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/knip.json +2 -1
- 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 +2748 -216
- 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__/anthropic-provider.test.ts +34 -37
- 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-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +12 -28
- package/src/__tests__/audit-log-rotation.test.ts +72 -18
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +8 -11
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +5 -5
- package/src/__tests__/call-controller.test.ts +3 -3
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +6 -5
- 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 +18 -27
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +215 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -16
- package/src/__tests__/computer-use-tools.test.ts +14 -18
- 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__/confirmation-request-guardian-bridge.test.ts +0 -1
- 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 +2 -1
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +231 -2
- package/src/__tests__/conversation-agent-loop.test.ts +581 -54
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +31 -24
- 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-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +61 -0
- package/src/__tests__/conversation-fork-crud.test.ts +239 -15
- 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 +53 -11
- 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-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +14 -13
- 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 +6 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +112 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +68 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +40 -147
- 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-store.test.ts +1 -1
- 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 +218 -35
- 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 +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -1
- 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 +19 -19
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +6 -5
- package/src/__tests__/credential-vault-unit.test.ts +21 -21
- 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-page-surface.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- 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 +236 -0
- package/src/__tests__/gemini-provider.test.ts +104 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +10 -7
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +5 -0
- package/src/__tests__/heartbeat-service.test.ts +5 -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 +6 -5
- 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__/init-feature-flag-overrides.test.ts +5 -6
- 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__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +408 -9
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +16 -2
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- 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 +4 -6
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- 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 +4 -3
- package/src/__tests__/openai-provider.test.ts +54 -9
- package/src/__tests__/openai-responses-provider.test.ts +176 -14
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +11 -13
- package/src/__tests__/plugin-tool-contribution.test.ts +50 -40
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- 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__/prune-jobs-changes-parser.test.ts +61 -0
- 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 +84 -84
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- 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__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +16 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +48 -37
- package/src/__tests__/skill-projection.benchmark.test.ts +7 -13
- package/src/__tests__/skill-tool-factory.test.ts +97 -96
- 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 +6 -5
- 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 +2 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +183 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +35 -12
- package/src/__tests__/tool-executor.test.ts +64 -72
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +3 -2
- 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-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- 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/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +6 -7
- package/src/agent/loop.ts +88 -0
- package/src/api/README.md +127 -0
- 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/api/events/relationship-state-updated.ts +25 -0
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +129 -0
- package/src/api/package.json +10 -0
- 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 +868 -0
- 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 +24 -0
- 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__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +176 -1
- package/src/cli/commands/memory-v3-render.ts +491 -0
- package/src/cli/commands/memory-v3.ts +567 -0
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +4 -0
- package/src/config/assistant-feature-flags.ts +39 -46
- package/src/config/bundled-skills/document-editor/SKILL.md +16 -3
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- 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/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +8 -7
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +33 -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 +228 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +102 -2
- package/src/config/schemas/memory-v2.ts +272 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/compactor.ts +52 -0
- package/src/context/token-estimator.ts +10 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- 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 +2 -3
- 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 +390 -80
- package/src/daemon/conversation-agent-loop.ts +244 -90
- package/src/daemon/conversation-error.ts +64 -6
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +38 -17
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +77 -32
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +40 -75
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +39 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +29 -26
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +11 -24
- package/src/daemon/message-types/conversations.ts +22 -27
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -14
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +25 -48
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/sync.ts +14 -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/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +62 -0
- package/src/daemon/tool-setup-types.ts +7 -0
- 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 +30 -1
- 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/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +27 -154
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/gateway-flag-listener.ts +123 -0
- 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 +35 -40
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +242 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- 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 +8 -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/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +423 -182
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +14 -0
- package/src/memory/db-maintenance.ts +30 -21
- 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/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- 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/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +66 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +122 -2
- package/src/memory/llm-request-log-source-local.ts +31 -0
- package/src/memory/llm-request-log-source.ts +40 -2
- package/src/memory/llm-request-log-store.ts +228 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +110 -7
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- 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 +19 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +10 -2
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +83 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +135 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +128 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +240 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +112 -0
- package/src/memory/v2/harness/trace.ts +64 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +466 -0
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +706 -0
- package/src/memory/v3/__tests__/filter.test.ts +560 -0
- package/src/memory/v3/__tests__/gate.test.ts +637 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +291 -0
- package/src/memory/v3/__tests__/loop.test.ts +775 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +489 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +398 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +508 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +784 -0
- package/src/memory/v3/__tests__/validate.test.ts +277 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +286 -0
- package/src/memory/v3/filter.ts +286 -0
- package/src/memory/v3/gate.ts +349 -0
- package/src/memory/v3/index-composition.ts +126 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +430 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +431 -0
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +347 -0
- package/src/memory/v3/traversal.ts +211 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +356 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +323 -0
- 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/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- 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/decision-engine.ts +1 -4
- 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 +40 -50
- 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/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- 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/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +20 -19
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +68 -29
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +84 -221
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +9 -13
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +233 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +42 -6
- package/src/providers/connection-model-compat.ts +61 -0
- package/src/providers/connection-resolution.ts +47 -14
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +70 -6
- 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/adapter-factory.ts +3 -0
- 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/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +78 -1
- package/src/providers/model-intents.ts +4 -4
- 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 +116 -15
- package/src/providers/openai/codex-models.ts +20 -0
- package/src/providers/openai/responses-provider.ts +87 -30
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +20 -5
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +50 -7
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- 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/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +46 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- 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/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +12 -4
- package/src/runtime/pending-interactions.ts +0 -1
- 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 +204 -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 +76 -9
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -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/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +356 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +4 -10
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +159 -4
- package/src/runtime/routes/conversation-management-routes.ts +108 -26
- package/src/runtime/routes/conversation-query-routes.ts +200 -44
- package/src/runtime/routes/conversation-routes.ts +409 -521
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +35 -8
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- 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/acl-enforcement.ts +96 -3
- 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 +10 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- 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-call-sites-routes.ts +32 -5
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +474 -0
- package/src/runtime/routes/migration-routes.ts +32 -28
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +5 -4
- 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/routes/workspace-routes.ts +25 -10
- 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 +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/runtime/verification-outbound-actions.ts +73 -1
- 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/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +36 -28
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +282 -336
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-tool.ts +189 -7
- package/src/tools/execution-target.ts +18 -23
- package/src/tools/executor.ts +24 -56
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -10
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- 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-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +224 -76
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +150 -123
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +18 -44
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +32 -101
- package/src/tools/ui-surface/definitions.ts +104 -108
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/browser.ts +7 -2
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- 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 +6 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -193,6 +193,8 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
193
193
|
updateConversationTitle: () => {},
|
|
194
194
|
getMessageById: () => null,
|
|
195
195
|
getLastUserTimestampBefore: () => 0,
|
|
196
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
197
|
+
updateMessageContent: mock(() => {}),
|
|
196
198
|
}));
|
|
197
199
|
|
|
198
200
|
mock.module("../memory/conversation-queries.js", () => ({
|
|
@@ -315,7 +317,7 @@ interface PendingRun {
|
|
|
315
317
|
resolve: (history: Message[]) => void;
|
|
316
318
|
reject: (err: Error) => void;
|
|
317
319
|
messages: Message[];
|
|
318
|
-
onEvent: (event: AgentEvent) => void
|
|
320
|
+
onEvent: (event: AgentEvent) => void | Promise<void>;
|
|
319
321
|
onCheckpoint?: (
|
|
320
322
|
checkpoint: CheckpointInfo,
|
|
321
323
|
) => CheckpointDecision | Promise<CheckpointDecision>;
|
|
@@ -337,7 +339,7 @@ mock.module("../agent/loop.js", () => ({
|
|
|
337
339
|
}
|
|
338
340
|
async run(
|
|
339
341
|
messages: Message[],
|
|
340
|
-
onEvent: (event: AgentEvent) => void
|
|
342
|
+
onEvent: (event: AgentEvent) => void | Promise<void>,
|
|
341
343
|
_signal?: AbortSignal,
|
|
342
344
|
_requestId?: string,
|
|
343
345
|
onCheckpoint?: (
|
|
@@ -471,7 +473,7 @@ async function waitForCondition(
|
|
|
471
473
|
* that `runAgentLoop` expects (usage + message_complete) so the conversation
|
|
472
474
|
* cleanly transitions out of its processing state.
|
|
473
475
|
*/
|
|
474
|
-
function resolveRun(index: number) {
|
|
476
|
+
async function resolveRun(index: number) {
|
|
475
477
|
const run = pendingRuns[index];
|
|
476
478
|
if (!run) throw new Error(`No pending run at index ${index}`);
|
|
477
479
|
// Emit the events runAgentLoop expects
|
|
@@ -479,14 +481,17 @@ function resolveRun(index: number) {
|
|
|
479
481
|
role: "assistant",
|
|
480
482
|
content: [{ type: "text", text: `reply-${index}` }],
|
|
481
483
|
};
|
|
482
|
-
|
|
484
|
+
// Prime the assistant row anchor — production code emits this from
|
|
485
|
+
// `AgentLoop.run` just before `provider.sendMessage`.
|
|
486
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
487
|
+
await run.onEvent({
|
|
483
488
|
type: "usage",
|
|
484
489
|
inputTokens: 10,
|
|
485
490
|
outputTokens: 5,
|
|
486
491
|
model: "mock",
|
|
487
492
|
providerDurationMs: 100,
|
|
488
493
|
});
|
|
489
|
-
run.onEvent({ type: "message_complete", message: assistantMsg });
|
|
494
|
+
await run.onEvent({ type: "message_complete", message: assistantMsg });
|
|
490
495
|
// Return updated history with the assistant message appended
|
|
491
496
|
run.resolve([...run.messages, assistantMsg]);
|
|
492
497
|
}
|
|
@@ -533,18 +538,17 @@ describe("Conversation message queue", () => {
|
|
|
533
538
|
expect(conversation.isProcessing()).toBe(true);
|
|
534
539
|
|
|
535
540
|
// Enqueue second message — should NOT throw
|
|
536
|
-
const result = conversation.enqueueMessage(
|
|
537
|
-
"msg-2",
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
);
|
|
541
|
+
const result = conversation.enqueueMessage({
|
|
542
|
+
content: "msg-2",
|
|
543
|
+
onEvent: (e) => events2.push(e),
|
|
544
|
+
requestId: "req-2",
|
|
545
|
+
});
|
|
542
546
|
expect(result.queued).toBe(true);
|
|
543
547
|
expect(result.requestId).toBe("req-2");
|
|
544
548
|
expect(conversation.getQueueDepth()).toBe(1);
|
|
545
549
|
|
|
546
550
|
// Complete the first message
|
|
547
|
-
resolveRun(0);
|
|
551
|
+
await resolveRun(0);
|
|
548
552
|
await p1;
|
|
549
553
|
|
|
550
554
|
// After the first run resolves, the queue drains and triggers a second run.
|
|
@@ -557,7 +561,7 @@ describe("Conversation message queue", () => {
|
|
|
557
561
|
expect(pendingRuns.length).toBe(2);
|
|
558
562
|
|
|
559
563
|
// Complete the second run
|
|
560
|
-
resolveRun(1);
|
|
564
|
+
await resolveRun(1);
|
|
561
565
|
await new Promise((r) => setTimeout(r, 10));
|
|
562
566
|
});
|
|
563
567
|
|
|
@@ -579,12 +583,20 @@ describe("Conversation message queue", () => {
|
|
|
579
583
|
await waitForPendingRun(1);
|
|
580
584
|
|
|
581
585
|
// Enqueue two more sibling passthrough messages
|
|
582
|
-
conversation.enqueueMessage(
|
|
583
|
-
|
|
586
|
+
conversation.enqueueMessage({
|
|
587
|
+
content: "msg-2",
|
|
588
|
+
onEvent: (e) => events2.push(e),
|
|
589
|
+
requestId: "req-2",
|
|
590
|
+
});
|
|
591
|
+
conversation.enqueueMessage({
|
|
592
|
+
content: "msg-3",
|
|
593
|
+
onEvent: (e) => events3.push(e),
|
|
594
|
+
requestId: "req-3",
|
|
595
|
+
});
|
|
584
596
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
585
597
|
|
|
586
598
|
// Complete run 0 → drain pulls msg-2 and msg-3 into ONE batched run.
|
|
587
|
-
resolveRun(0);
|
|
599
|
+
await resolveRun(0);
|
|
588
600
|
await p1;
|
|
589
601
|
await waitForPendingRun(2);
|
|
590
602
|
|
|
@@ -623,7 +635,7 @@ describe("Conversation message queue", () => {
|
|
|
623
635
|
expect(combinedUserText).toContain("msg-3");
|
|
624
636
|
|
|
625
637
|
// Resolve the batched run; message_complete must fan out to both clients.
|
|
626
|
-
resolveRun(1);
|
|
638
|
+
await resolveRun(1);
|
|
627
639
|
await new Promise((r) => setTimeout(r, 10));
|
|
628
640
|
|
|
629
641
|
expect(events2.some((e) => e.type === "message_complete")).toBe(true);
|
|
@@ -641,16 +653,15 @@ describe("Conversation message queue", () => {
|
|
|
641
653
|
await waitForPendingRun(1);
|
|
642
654
|
|
|
643
655
|
// Enqueue second — simulating what handleUserMessage does
|
|
644
|
-
const result = conversation.enqueueMessage(
|
|
645
|
-
"msg-2",
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
);
|
|
656
|
+
const result = conversation.enqueueMessage({
|
|
657
|
+
content: "msg-2",
|
|
658
|
+
onEvent: (e) => events2.push(e),
|
|
659
|
+
requestId: "req-2",
|
|
660
|
+
});
|
|
650
661
|
expect(result.queued).toBe(true);
|
|
651
662
|
|
|
652
663
|
// Complete first
|
|
653
|
-
resolveRun(0);
|
|
664
|
+
await resolveRun(0);
|
|
654
665
|
await p1;
|
|
655
666
|
await waitForPendingRun(2);
|
|
656
667
|
|
|
@@ -664,7 +675,7 @@ describe("Conversation message queue", () => {
|
|
|
664
675
|
});
|
|
665
676
|
|
|
666
677
|
// Complete second run so the conversation finishes cleanly
|
|
667
|
-
resolveRun(1);
|
|
678
|
+
await resolveRun(1);
|
|
668
679
|
await new Promise((r) => setTimeout(r, 10));
|
|
669
680
|
});
|
|
670
681
|
|
|
@@ -680,8 +691,16 @@ describe("Conversation message queue", () => {
|
|
|
680
691
|
await waitForPendingRun(1);
|
|
681
692
|
|
|
682
693
|
// Enqueue two more
|
|
683
|
-
conversation.enqueueMessage(
|
|
684
|
-
|
|
694
|
+
conversation.enqueueMessage({
|
|
695
|
+
content: "msg-2",
|
|
696
|
+
onEvent: (e) => events2.push(e),
|
|
697
|
+
requestId: "req-2",
|
|
698
|
+
});
|
|
699
|
+
conversation.enqueueMessage({
|
|
700
|
+
content: "msg-3",
|
|
701
|
+
onEvent: (e) => events3.push(e),
|
|
702
|
+
requestId: "req-3",
|
|
703
|
+
});
|
|
685
704
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
686
705
|
|
|
687
706
|
// Abort
|
|
@@ -759,18 +778,18 @@ describe("Conversation message queue", () => {
|
|
|
759
778
|
|
|
760
779
|
expect(conversation.getQueueDepth()).toBe(0);
|
|
761
780
|
|
|
762
|
-
conversation.enqueueMessage("msg-2",
|
|
781
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
763
782
|
expect(conversation.getQueueDepth()).toBe(1);
|
|
764
783
|
|
|
765
|
-
conversation.enqueueMessage("msg-3",
|
|
784
|
+
conversation.enqueueMessage({ content: "msg-3", requestId: "req-3" });
|
|
766
785
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
767
786
|
|
|
768
|
-
conversation.enqueueMessage("msg-4",
|
|
787
|
+
conversation.enqueueMessage({ content: "msg-4", requestId: "req-4" });
|
|
769
788
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
770
789
|
|
|
771
790
|
// Complete first → drain pulls all three same-interface passthroughs
|
|
772
791
|
// into a single batched run (depth → 0, runs → 2 total).
|
|
773
|
-
resolveRun(0);
|
|
792
|
+
await resolveRun(0);
|
|
774
793
|
await p1;
|
|
775
794
|
await waitForPendingRun(2);
|
|
776
795
|
|
|
@@ -778,7 +797,7 @@ describe("Conversation message queue", () => {
|
|
|
778
797
|
expect(pendingRuns.length).toBe(2);
|
|
779
798
|
|
|
780
799
|
// Complete the batched run; conversation finishes cleanly.
|
|
781
|
-
resolveRun(1);
|
|
800
|
+
await resolveRun(1);
|
|
782
801
|
await new Promise((r) => setTimeout(r, 10));
|
|
783
802
|
});
|
|
784
803
|
|
|
@@ -800,14 +819,22 @@ describe("Conversation message queue", () => {
|
|
|
800
819
|
await waitForPendingRun(1);
|
|
801
820
|
|
|
802
821
|
// Enqueue a message with empty content (will fail persistUserMessage)
|
|
803
|
-
conversation.enqueueMessage(
|
|
822
|
+
conversation.enqueueMessage({
|
|
823
|
+
content: "",
|
|
824
|
+
onEvent: (e) => events2.push(e),
|
|
825
|
+
requestId: "req-2",
|
|
826
|
+
});
|
|
804
827
|
// Enqueue a valid message after the bad one
|
|
805
|
-
conversation.enqueueMessage(
|
|
828
|
+
conversation.enqueueMessage({
|
|
829
|
+
content: "msg-3",
|
|
830
|
+
onEvent: (e) => events3.push(e),
|
|
831
|
+
requestId: "req-3",
|
|
832
|
+
});
|
|
806
833
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
807
834
|
|
|
808
835
|
// Complete first message — triggers drain. The empty message should fail
|
|
809
836
|
// to persist, but the drain should continue to msg-3.
|
|
810
|
-
resolveRun(0);
|
|
837
|
+
await resolveRun(0);
|
|
811
838
|
await p1;
|
|
812
839
|
|
|
813
840
|
// msg-3 should have been dequeued and started a new AgentLoop.run
|
|
@@ -824,7 +851,7 @@ describe("Conversation message queue", () => {
|
|
|
824
851
|
expect(events3.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
825
852
|
|
|
826
853
|
// Complete the third message's run
|
|
827
|
-
resolveRun(1);
|
|
854
|
+
await resolveRun(1);
|
|
828
855
|
await new Promise((r) => setTimeout(r, 10));
|
|
829
856
|
|
|
830
857
|
// msg-3 should have completed successfully
|
|
@@ -860,46 +887,34 @@ describe("Batched drain", () => {
|
|
|
860
887
|
userMessageInterface: iface,
|
|
861
888
|
assistantMessageInterface: iface,
|
|
862
889
|
});
|
|
863
|
-
conversation.enqueueMessage(
|
|
864
|
-
"msg-2",
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
"
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
"
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
"
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
meta("
|
|
880
|
-
);
|
|
881
|
-
conversation.enqueueMessage(
|
|
882
|
-
"msg-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
"
|
|
886
|
-
|
|
887
|
-
undefined,
|
|
888
|
-
meta("cli"),
|
|
889
|
-
);
|
|
890
|
-
conversation.enqueueMessage(
|
|
891
|
-
"msg-5",
|
|
892
|
-
[],
|
|
893
|
-
(e) => events5.push(e),
|
|
894
|
-
"req-5",
|
|
895
|
-
undefined,
|
|
896
|
-
undefined,
|
|
897
|
-
meta("macos"),
|
|
898
|
-
);
|
|
890
|
+
conversation.enqueueMessage({
|
|
891
|
+
content: "msg-2",
|
|
892
|
+
onEvent: (e) => events2.push(e),
|
|
893
|
+
requestId: "req-2",
|
|
894
|
+
metadata: meta("macos"),
|
|
895
|
+
});
|
|
896
|
+
conversation.enqueueMessage({
|
|
897
|
+
content: "msg-3",
|
|
898
|
+
onEvent: (e) => events3.push(e),
|
|
899
|
+
requestId: "req-3",
|
|
900
|
+
metadata: meta("macos"),
|
|
901
|
+
});
|
|
902
|
+
conversation.enqueueMessage({
|
|
903
|
+
content: "msg-4",
|
|
904
|
+
onEvent: (e) => events4.push(e),
|
|
905
|
+
requestId: "req-4",
|
|
906
|
+
metadata: meta("cli"),
|
|
907
|
+
});
|
|
908
|
+
conversation.enqueueMessage({
|
|
909
|
+
content: "msg-5",
|
|
910
|
+
onEvent: (e) => events5.push(e),
|
|
911
|
+
requestId: "req-5",
|
|
912
|
+
metadata: meta("macos"),
|
|
913
|
+
});
|
|
899
914
|
expect(conversation.getQueueDepth()).toBe(4);
|
|
900
915
|
|
|
901
916
|
// Resolve msg-1 → batched run pulls macos msg-2 + msg-3.
|
|
902
|
-
resolveRun(0);
|
|
917
|
+
await resolveRun(0);
|
|
903
918
|
await p1;
|
|
904
919
|
await waitForPendingRun(2);
|
|
905
920
|
|
|
@@ -927,7 +942,7 @@ describe("Batched drain", () => {
|
|
|
927
942
|
);
|
|
928
943
|
|
|
929
944
|
// Resolve the batched run → drain pulls the cli single-message run.
|
|
930
|
-
resolveRun(1);
|
|
945
|
+
await resolveRun(1);
|
|
931
946
|
await waitForPendingRun(3);
|
|
932
947
|
|
|
933
948
|
// cli run contains msg-4 as a single-message run.
|
|
@@ -942,7 +957,7 @@ describe("Batched drain", () => {
|
|
|
942
957
|
);
|
|
943
958
|
|
|
944
959
|
// Resolve the cli run → drain pulls the final macos single-message run.
|
|
945
|
-
resolveRun(2);
|
|
960
|
+
await resolveRun(2);
|
|
946
961
|
await waitForPendingRun(4);
|
|
947
962
|
const finalHistory = pendingRuns[3].messages;
|
|
948
963
|
const finalUserText = finalHistory
|
|
@@ -957,7 +972,7 @@ describe("Batched drain", () => {
|
|
|
957
972
|
// Four total runs: msg-1, batched [msg-2, msg-3], msg-4, msg-5.
|
|
958
973
|
expect(pendingRuns.length).toBe(4);
|
|
959
974
|
|
|
960
|
-
resolveRun(3);
|
|
975
|
+
await resolveRun(3);
|
|
961
976
|
await new Promise((r) => setTimeout(r, 10));
|
|
962
977
|
});
|
|
963
978
|
|
|
@@ -977,29 +992,26 @@ describe("Batched drain", () => {
|
|
|
977
992
|
// passthrough slash, so the batch builder stops at "hello" (length 1),
|
|
978
993
|
// then /compact takes the single-message /compact short-circuit path
|
|
979
994
|
// (no new runAgentLoop invocation), then "world" drains as its own run.
|
|
980
|
-
conversation.enqueueMessage(
|
|
981
|
-
"hello",
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
"world",
|
|
994
|
-
|
|
995
|
-
(e) => eventsWorld.push(e),
|
|
996
|
-
"req-world",
|
|
997
|
-
);
|
|
995
|
+
conversation.enqueueMessage({
|
|
996
|
+
content: "hello",
|
|
997
|
+
onEvent: (e) => eventsHello.push(e),
|
|
998
|
+
requestId: "req-hello",
|
|
999
|
+
});
|
|
1000
|
+
conversation.enqueueMessage({
|
|
1001
|
+
content: "/compact",
|
|
1002
|
+
onEvent: (e) => eventsSlash.push(e),
|
|
1003
|
+
requestId: "req-slash",
|
|
1004
|
+
});
|
|
1005
|
+
conversation.enqueueMessage({
|
|
1006
|
+
content: "world",
|
|
1007
|
+
onEvent: (e) => eventsWorld.push(e),
|
|
1008
|
+
requestId: "req-world",
|
|
1009
|
+
});
|
|
998
1010
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
999
1011
|
|
|
1000
1012
|
// Resolve msg-1 → drain pulls "hello" as its own run (batch stops at
|
|
1001
1013
|
// /compact boundary).
|
|
1002
|
-
resolveRun(0);
|
|
1014
|
+
await resolveRun(0);
|
|
1003
1015
|
await p1;
|
|
1004
1016
|
await waitForPendingRun(2);
|
|
1005
1017
|
|
|
@@ -1010,7 +1022,7 @@ describe("Batched drain", () => {
|
|
|
1010
1022
|
|
|
1011
1023
|
// Resolve "hello" → drain pops /compact via the builder-rejected path,
|
|
1012
1024
|
// runs its short-circuit (no new runAgentLoop), then drains "world".
|
|
1013
|
-
resolveRun(1);
|
|
1025
|
+
await resolveRun(1);
|
|
1014
1026
|
await waitForPendingRun(3);
|
|
1015
1027
|
|
|
1016
1028
|
// /compact should have emitted its own message_complete via the short-
|
|
@@ -1019,7 +1031,7 @@ describe("Batched drain", () => {
|
|
|
1019
1031
|
expect(eventsWorld.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
1020
1032
|
expect(pendingRuns.length).toBe(3);
|
|
1021
1033
|
|
|
1022
|
-
resolveRun(2);
|
|
1034
|
+
await resolveRun(2);
|
|
1023
1035
|
await new Promise((r) => setTimeout(r, 10));
|
|
1024
1036
|
});
|
|
1025
1037
|
|
|
@@ -1051,29 +1063,26 @@ describe("Batched drain", () => {
|
|
|
1051
1063
|
// unknown-slash short-circuit path (no new runAgentLoop invocation — it
|
|
1052
1064
|
// emits assistant_text_delta + message_complete inline), then "plain-b"
|
|
1053
1065
|
// drains as its own run.
|
|
1054
|
-
conversation.enqueueMessage(
|
|
1055
|
-
"plain-a",
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
"plain-b",
|
|
1068
|
-
|
|
1069
|
-
(e) => eventsPlainB.push(e),
|
|
1070
|
-
"req-plain-b",
|
|
1071
|
-
);
|
|
1066
|
+
conversation.enqueueMessage({
|
|
1067
|
+
content: "plain-a",
|
|
1068
|
+
onEvent: (e) => eventsPlainA.push(e),
|
|
1069
|
+
requestId: "req-plain-a",
|
|
1070
|
+
});
|
|
1071
|
+
conversation.enqueueMessage({
|
|
1072
|
+
content: "/status",
|
|
1073
|
+
onEvent: (e) => eventsSlash.push(e),
|
|
1074
|
+
requestId: "req-slash",
|
|
1075
|
+
});
|
|
1076
|
+
conversation.enqueueMessage({
|
|
1077
|
+
content: "plain-b",
|
|
1078
|
+
onEvent: (e) => eventsPlainB.push(e),
|
|
1079
|
+
requestId: "req-plain-b",
|
|
1080
|
+
});
|
|
1072
1081
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
1073
1082
|
|
|
1074
1083
|
// Resolve msg-1 → drain pulls "plain-a" as its own run (batch stops at
|
|
1075
1084
|
// the /status boundary).
|
|
1076
|
-
resolveRun(0);
|
|
1085
|
+
await resolveRun(0);
|
|
1077
1086
|
await p1;
|
|
1078
1087
|
await waitForPendingRun(2);
|
|
1079
1088
|
|
|
@@ -1086,7 +1095,7 @@ describe("Batched drain", () => {
|
|
|
1086
1095
|
// runs its unknown-slash short-circuit (no new runAgentLoop, emits
|
|
1087
1096
|
// assistant_text_delta + message_complete inline), then drains "plain-b"
|
|
1088
1097
|
// as its own run.
|
|
1089
|
-
resolveRun(1);
|
|
1098
|
+
await resolveRun(1);
|
|
1090
1099
|
await waitForPendingRun(3);
|
|
1091
1100
|
|
|
1092
1101
|
// /status should have emitted its own assistant_text_delta + message_complete
|
|
@@ -1100,7 +1109,7 @@ describe("Batched drain", () => {
|
|
|
1100
1109
|
// without a runAgentLoop invocation.
|
|
1101
1110
|
expect(pendingRuns.length).toBe(3);
|
|
1102
1111
|
|
|
1103
|
-
resolveRun(2);
|
|
1112
|
+
await resolveRun(2);
|
|
1104
1113
|
await new Promise((r) => setTimeout(r, 10));
|
|
1105
1114
|
});
|
|
1106
1115
|
|
|
@@ -1132,11 +1141,19 @@ describe("Batched drain", () => {
|
|
|
1132
1141
|
filePath: "/tmp/b.png",
|
|
1133
1142
|
},
|
|
1134
1143
|
];
|
|
1135
|
-
conversation.enqueueMessage(
|
|
1136
|
-
|
|
1144
|
+
conversation.enqueueMessage({
|
|
1145
|
+
content: "with-A",
|
|
1146
|
+
attachments: attachA,
|
|
1147
|
+
requestId: "req-A",
|
|
1148
|
+
});
|
|
1149
|
+
conversation.enqueueMessage({
|
|
1150
|
+
content: "with-B",
|
|
1151
|
+
attachments: attachB,
|
|
1152
|
+
requestId: "req-B",
|
|
1153
|
+
});
|
|
1137
1154
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
1138
1155
|
|
|
1139
|
-
resolveRun(0);
|
|
1156
|
+
await resolveRun(0);
|
|
1140
1157
|
await p1;
|
|
1141
1158
|
await waitForPendingRun(2);
|
|
1142
1159
|
|
|
@@ -1170,7 +1187,7 @@ describe("Batched drain", () => {
|
|
|
1170
1187
|
expect(allText).toContain("a.png");
|
|
1171
1188
|
expect(allText).toContain("b.png");
|
|
1172
1189
|
|
|
1173
|
-
resolveRun(1);
|
|
1190
|
+
await resolveRun(1);
|
|
1174
1191
|
await new Promise((r) => setTimeout(r, 10));
|
|
1175
1192
|
});
|
|
1176
1193
|
|
|
@@ -1189,30 +1206,25 @@ describe("Batched drain", () => {
|
|
|
1189
1206
|
await waitForPendingRun(1);
|
|
1190
1207
|
|
|
1191
1208
|
// Fill to just-under budget: two ~500-char messages (1512+1512 = 3024 bytes).
|
|
1192
|
-
const accepted1 = conversation.enqueueMessage(
|
|
1193
|
-
"x".repeat(500),
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
[],
|
|
1201
|
-
() => {},
|
|
1202
|
-
"req-big-2",
|
|
1203
|
-
);
|
|
1209
|
+
const accepted1 = conversation.enqueueMessage({
|
|
1210
|
+
content: "x".repeat(500),
|
|
1211
|
+
requestId: "req-big-1",
|
|
1212
|
+
});
|
|
1213
|
+
const accepted2 = conversation.enqueueMessage({
|
|
1214
|
+
content: "y".repeat(500),
|
|
1215
|
+
requestId: "req-big-2",
|
|
1216
|
+
});
|
|
1204
1217
|
expect(accepted1.queued).toBe(true);
|
|
1205
1218
|
expect(accepted2.queued).toBe(true);
|
|
1206
1219
|
// A third would push the queue over budget → rejected. Capture its
|
|
1207
1220
|
// onEvent callback so we can verify the queue_full error event reaches
|
|
1208
1221
|
// the rejected caller (not just the synchronous return value).
|
|
1209
1222
|
const rejectedEvents: ServerMessage[] = [];
|
|
1210
|
-
const rejected = conversation.enqueueMessage(
|
|
1211
|
-
"z".repeat(500),
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
);
|
|
1223
|
+
const rejected = conversation.enqueueMessage({
|
|
1224
|
+
content: "z".repeat(500),
|
|
1225
|
+
onEvent: (e) => rejectedEvents.push(e),
|
|
1226
|
+
requestId: "req-over",
|
|
1227
|
+
});
|
|
1216
1228
|
expect(rejected.queued).toBe(false);
|
|
1217
1229
|
expect(rejected.rejected).toBe(true);
|
|
1218
1230
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
@@ -1231,13 +1243,13 @@ describe("Batched drain", () => {
|
|
|
1231
1243
|
}
|
|
1232
1244
|
|
|
1233
1245
|
// Complete in-flight → drain pulls both queued passthroughs as ONE batched run.
|
|
1234
|
-
resolveRun(0);
|
|
1246
|
+
await resolveRun(0);
|
|
1235
1247
|
await p1;
|
|
1236
1248
|
await waitForPendingRun(2);
|
|
1237
1249
|
expect(conversation.getQueueDepth()).toBe(0);
|
|
1238
1250
|
|
|
1239
1251
|
// Resolve the batched run.
|
|
1240
|
-
resolveRun(1);
|
|
1252
|
+
await resolveRun(1);
|
|
1241
1253
|
await new Promise((r) => setTimeout(r, 10));
|
|
1242
1254
|
|
|
1243
1255
|
// After the full drain, the byte budget must be fully reclaimed — a fresh
|
|
@@ -1246,18 +1258,22 @@ describe("Batched drain", () => {
|
|
|
1246
1258
|
const p2 = conversation.processMessage("msg-2", [], () => {}, "req-2");
|
|
1247
1259
|
await waitForPendingRun(3);
|
|
1248
1260
|
expect(
|
|
1249
|
-
conversation.enqueueMessage(
|
|
1250
|
-
.
|
|
1261
|
+
conversation.enqueueMessage({
|
|
1262
|
+
content: "a".repeat(500),
|
|
1263
|
+
requestId: "req-a",
|
|
1264
|
+
}).queued,
|
|
1251
1265
|
).toBe(true);
|
|
1252
1266
|
expect(
|
|
1253
|
-
conversation.enqueueMessage(
|
|
1254
|
-
.
|
|
1267
|
+
conversation.enqueueMessage({
|
|
1268
|
+
content: "b".repeat(500),
|
|
1269
|
+
requestId: "req-b",
|
|
1270
|
+
}).queued,
|
|
1255
1271
|
).toBe(true);
|
|
1256
1272
|
|
|
1257
|
-
resolveRun(2);
|
|
1273
|
+
await resolveRun(2);
|
|
1258
1274
|
await p2;
|
|
1259
1275
|
await waitForPendingRun(4);
|
|
1260
|
-
resolveRun(3);
|
|
1276
|
+
await resolveRun(3);
|
|
1261
1277
|
await new Promise((r) => setTimeout(r, 10));
|
|
1262
1278
|
});
|
|
1263
1279
|
});
|
|
@@ -1289,25 +1305,23 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1289
1305
|
// same interface. The batch builder must reject the surface-action head
|
|
1290
1306
|
// so each drains as its own run.
|
|
1291
1307
|
conversation.surfaceActionRequestIds.add("req-surface");
|
|
1292
|
-
conversation.enqueueMessage(
|
|
1293
|
-
"surface action response",
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
"
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
"req-regular",
|
|
1304
|
-
);
|
|
1308
|
+
conversation.enqueueMessage({
|
|
1309
|
+
content: "surface action response",
|
|
1310
|
+
onEvent: (e) => eventsSurface.push(e),
|
|
1311
|
+
requestId: "req-surface",
|
|
1312
|
+
activeSurfaceId: "surface-1",
|
|
1313
|
+
});
|
|
1314
|
+
conversation.enqueueMessage({
|
|
1315
|
+
content: "regular follow-up",
|
|
1316
|
+
onEvent: (e) => eventsRegular.push(e),
|
|
1317
|
+
requestId: "req-regular",
|
|
1318
|
+
});
|
|
1305
1319
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
1306
1320
|
|
|
1307
1321
|
// Complete run 0 → drain must NOT batch the surface-action with the
|
|
1308
1322
|
// regular passthrough. Expect the surface-action to drain as a single
|
|
1309
1323
|
// run first.
|
|
1310
|
-
resolveRun(0);
|
|
1324
|
+
await resolveRun(0);
|
|
1311
1325
|
await p1;
|
|
1312
1326
|
await waitForPendingRun(2);
|
|
1313
1327
|
|
|
@@ -1322,7 +1336,7 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1322
1336
|
|
|
1323
1337
|
// Complete the surface-action run; drain pulls the regular passthrough
|
|
1324
1338
|
// as its own separate run.
|
|
1325
|
-
resolveRun(1);
|
|
1339
|
+
await resolveRun(1);
|
|
1326
1340
|
await waitForPendingRun(3);
|
|
1327
1341
|
expect(pendingRuns.length).toBe(3);
|
|
1328
1342
|
expect(
|
|
@@ -1331,7 +1345,7 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1331
1345
|
|
|
1332
1346
|
// Total runs = 3: msg-1, surface-action, regular — NOT 2 (would mean
|
|
1333
1347
|
// they were batched).
|
|
1334
|
-
resolveRun(2);
|
|
1348
|
+
await resolveRun(2);
|
|
1335
1349
|
await new Promise((r) => setTimeout(r, 10));
|
|
1336
1350
|
});
|
|
1337
1351
|
|
|
@@ -1360,7 +1374,11 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1360
1374
|
// fresh one). Calling abort() now aborts that fresh controller, and
|
|
1361
1375
|
// the drainBatch loop's abort check after msg-3's persist will break,
|
|
1362
1376
|
// so msg-4 never persists.
|
|
1363
|
-
conversation.enqueueMessage(
|
|
1377
|
+
conversation.enqueueMessage({
|
|
1378
|
+
content: "msg-2",
|
|
1379
|
+
onEvent: (e) => events2.push(e),
|
|
1380
|
+
requestId: "req-2",
|
|
1381
|
+
});
|
|
1364
1382
|
|
|
1365
1383
|
// Install a one-shot abort trigger on msg-3's dequeue event. We do
|
|
1366
1384
|
// this before enqueueing so the wrapped callback is what drainBatch
|
|
@@ -1373,8 +1391,16 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1373
1391
|
conversation.abort();
|
|
1374
1392
|
}
|
|
1375
1393
|
};
|
|
1376
|
-
conversation.enqueueMessage(
|
|
1377
|
-
|
|
1394
|
+
conversation.enqueueMessage({
|
|
1395
|
+
content: "msg-3",
|
|
1396
|
+
onEvent: onMsg3Event,
|
|
1397
|
+
requestId: "req-3",
|
|
1398
|
+
});
|
|
1399
|
+
conversation.enqueueMessage({
|
|
1400
|
+
content: "msg-4",
|
|
1401
|
+
onEvent: (e) => events4.push(e),
|
|
1402
|
+
requestId: "req-4",
|
|
1403
|
+
});
|
|
1378
1404
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
1379
1405
|
|
|
1380
1406
|
const persistedUserRowCountBefore = capturedAddMessages.filter(
|
|
@@ -1382,7 +1408,7 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1382
1408
|
).length;
|
|
1383
1409
|
|
|
1384
1410
|
// Complete run 0 → drain pulls the sibling batch.
|
|
1385
|
-
resolveRun(0);
|
|
1411
|
+
await resolveRun(0);
|
|
1386
1412
|
await p1;
|
|
1387
1413
|
|
|
1388
1414
|
// Give the drain loop a chance to iterate. Abort happens on msg-3's
|
|
@@ -1426,28 +1452,25 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1426
1452
|
// msg-tail's requestId (the LAST successful persist), not msg-mid's.
|
|
1427
1453
|
addMessageShouldThrowForContent.add("msg-mid-unique-marker");
|
|
1428
1454
|
|
|
1429
|
-
conversation.enqueueMessage(
|
|
1430
|
-
"msg-head",
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
"
|
|
1443
|
-
|
|
1444
|
-
(e) => events4.push(e),
|
|
1445
|
-
"req-tail",
|
|
1446
|
-
);
|
|
1455
|
+
conversation.enqueueMessage({
|
|
1456
|
+
content: "msg-head",
|
|
1457
|
+
onEvent: (e) => events2.push(e),
|
|
1458
|
+
requestId: "req-head",
|
|
1459
|
+
});
|
|
1460
|
+
conversation.enqueueMessage({
|
|
1461
|
+
content: "msg-mid-unique-marker",
|
|
1462
|
+
onEvent: (e) => events3.push(e),
|
|
1463
|
+
requestId: "req-mid",
|
|
1464
|
+
});
|
|
1465
|
+
conversation.enqueueMessage({
|
|
1466
|
+
content: "msg-tail",
|
|
1467
|
+
onEvent: (e) => events4.push(e),
|
|
1468
|
+
requestId: "req-tail",
|
|
1469
|
+
});
|
|
1447
1470
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
1448
1471
|
|
|
1449
1472
|
// Complete run 0 → batched drain.
|
|
1450
|
-
resolveRun(0);
|
|
1473
|
+
await resolveRun(0);
|
|
1451
1474
|
await p1;
|
|
1452
1475
|
await waitForPendingRun(2);
|
|
1453
1476
|
|
|
@@ -1464,7 +1487,7 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1464
1487
|
).toBe("req-tail");
|
|
1465
1488
|
|
|
1466
1489
|
// Cleanup: resolve the batched run.
|
|
1467
|
-
resolveRun(1);
|
|
1490
|
+
await resolveRun(1);
|
|
1468
1491
|
await new Promise((r) => setTimeout(r, 20));
|
|
1469
1492
|
});
|
|
1470
1493
|
|
|
@@ -1492,31 +1515,28 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1492
1515
|
// desync the client.
|
|
1493
1516
|
addMessageShouldThrowForContent.add("fanout-mid-marker");
|
|
1494
1517
|
|
|
1495
|
-
conversation.enqueueMessage(
|
|
1496
|
-
"fanout-head",
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
"fanout-tail",
|
|
1509
|
-
|
|
1510
|
-
(e) => events4.push(e),
|
|
1511
|
-
"req-fanout-tail",
|
|
1512
|
-
);
|
|
1518
|
+
conversation.enqueueMessage({
|
|
1519
|
+
content: "fanout-head",
|
|
1520
|
+
onEvent: (e) => events2.push(e),
|
|
1521
|
+
requestId: "req-fanout-head",
|
|
1522
|
+
});
|
|
1523
|
+
conversation.enqueueMessage({
|
|
1524
|
+
content: "fanout-mid-marker",
|
|
1525
|
+
onEvent: (e) => events3.push(e),
|
|
1526
|
+
requestId: "req-fanout-mid",
|
|
1527
|
+
});
|
|
1528
|
+
conversation.enqueueMessage({
|
|
1529
|
+
content: "fanout-tail",
|
|
1530
|
+
onEvent: (e) => events4.push(e),
|
|
1531
|
+
requestId: "req-fanout-tail",
|
|
1532
|
+
});
|
|
1513
1533
|
|
|
1514
|
-
resolveRun(0);
|
|
1534
|
+
await resolveRun(0);
|
|
1515
1535
|
await p1;
|
|
1516
1536
|
await waitForPendingRun(2);
|
|
1517
1537
|
|
|
1518
1538
|
// Drive the batched run to emit message_complete via fanOutOnEvent.
|
|
1519
|
-
resolveRun(1);
|
|
1539
|
+
await resolveRun(1);
|
|
1520
1540
|
await new Promise((r) => setTimeout(r, 20));
|
|
1521
1541
|
|
|
1522
1542
|
expect(events3.find((e) => e.type === "error")).toBeDefined();
|
|
@@ -1544,12 +1564,12 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1544
1564
|
const baseline = activityStates.length;
|
|
1545
1565
|
|
|
1546
1566
|
// Enqueue three sibling passthroughs.
|
|
1547
|
-
conversation.enqueueMessage("msg-2",
|
|
1548
|
-
conversation.enqueueMessage("msg-3",
|
|
1549
|
-
conversation.enqueueMessage("msg-4",
|
|
1567
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
1568
|
+
conversation.enqueueMessage({ content: "msg-3", requestId: "req-3" });
|
|
1569
|
+
conversation.enqueueMessage({ content: "msg-4", requestId: "req-4" });
|
|
1550
1570
|
|
|
1551
1571
|
// Complete run 0 → drain pulls the batched siblings as ONE run.
|
|
1552
|
-
resolveRun(0);
|
|
1572
|
+
await resolveRun(0);
|
|
1553
1573
|
await p1;
|
|
1554
1574
|
await waitForPendingRun(2);
|
|
1555
1575
|
|
|
@@ -1569,7 +1589,7 @@ describe("Batched drain correctness fixes", () => {
|
|
|
1569
1589
|
requestId: "req-2", // head's requestId, per the fix
|
|
1570
1590
|
});
|
|
1571
1591
|
|
|
1572
|
-
resolveRun(1);
|
|
1592
|
+
await resolveRun(1);
|
|
1573
1593
|
await new Promise((r) => setTimeout(r, 10));
|
|
1574
1594
|
});
|
|
1575
1595
|
|
|
@@ -1614,13 +1634,13 @@ describe("Conversation queue policy helpers", () => {
|
|
|
1614
1634
|
await waitForPendingRun(1);
|
|
1615
1635
|
|
|
1616
1636
|
// Enqueue a message while processing
|
|
1617
|
-
conversation.enqueueMessage("msg-2",
|
|
1637
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
1618
1638
|
expect(conversation.hasQueuedMessages()).toBe(true);
|
|
1619
1639
|
|
|
1620
1640
|
// Cleanup: resolve the pending run
|
|
1621
|
-
resolveRun(0);
|
|
1641
|
+
await resolveRun(0);
|
|
1622
1642
|
await waitForPendingRun(2);
|
|
1623
|
-
resolveRun(1);
|
|
1643
|
+
await resolveRun(1);
|
|
1624
1644
|
await new Promise((r) => setTimeout(r, 10));
|
|
1625
1645
|
});
|
|
1626
1646
|
|
|
@@ -1645,7 +1665,7 @@ describe("Conversation queue policy helpers", () => {
|
|
|
1645
1665
|
expect(conversation.canHandoffAtCheckpoint()).toBe(false);
|
|
1646
1666
|
|
|
1647
1667
|
// Cleanup
|
|
1648
|
-
resolveRun(0);
|
|
1668
|
+
await resolveRun(0);
|
|
1649
1669
|
await new Promise((r) => setTimeout(r, 10));
|
|
1650
1670
|
});
|
|
1651
1671
|
|
|
@@ -1658,16 +1678,16 @@ describe("Conversation queue policy helpers", () => {
|
|
|
1658
1678
|
await waitForPendingRun(1);
|
|
1659
1679
|
|
|
1660
1680
|
// Enqueue a message
|
|
1661
|
-
conversation.enqueueMessage("msg-2",
|
|
1681
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
1662
1682
|
|
|
1663
1683
|
expect(conversation.isProcessing()).toBe(true);
|
|
1664
1684
|
expect(conversation.hasQueuedMessages()).toBe(true);
|
|
1665
1685
|
expect(conversation.canHandoffAtCheckpoint()).toBe(true);
|
|
1666
1686
|
|
|
1667
1687
|
// Cleanup
|
|
1668
|
-
resolveRun(0);
|
|
1688
|
+
await resolveRun(0);
|
|
1669
1689
|
await waitForPendingRun(2);
|
|
1670
|
-
resolveRun(1);
|
|
1690
|
+
await resolveRun(1);
|
|
1671
1691
|
await new Promise((r) => setTimeout(r, 10));
|
|
1672
1692
|
});
|
|
1673
1693
|
|
|
@@ -1714,7 +1734,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1714
1734
|
await waitForPendingRun(1);
|
|
1715
1735
|
|
|
1716
1736
|
// Enqueue a second message while the first is processing
|
|
1717
|
-
conversation.enqueueMessage("msg-2",
|
|
1737
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
1718
1738
|
expect(conversation.hasQueuedMessages()).toBe(true);
|
|
1719
1739
|
|
|
1720
1740
|
// The pending run should have received an onCheckpoint callback.
|
|
@@ -1732,7 +1752,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1732
1752
|
expect(decision).toBe("yield");
|
|
1733
1753
|
|
|
1734
1754
|
// Complete the run so the conversation finishes cleanly
|
|
1735
|
-
resolveRun(0);
|
|
1755
|
+
await resolveRun(0);
|
|
1736
1756
|
await p1;
|
|
1737
1757
|
|
|
1738
1758
|
// After yield, the first message should emit generation_handoff
|
|
@@ -1747,7 +1767,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1747
1767
|
|
|
1748
1768
|
// The queued message should now be draining (second run started)
|
|
1749
1769
|
await waitForPendingRun(2);
|
|
1750
|
-
resolveRun(1);
|
|
1770
|
+
await resolveRun(1);
|
|
1751
1771
|
await new Promise((r) => setTimeout(r, 10));
|
|
1752
1772
|
});
|
|
1753
1773
|
|
|
@@ -1775,7 +1795,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1775
1795
|
expect(decision).toBe("continue");
|
|
1776
1796
|
|
|
1777
1797
|
// Cleanup
|
|
1778
|
-
resolveRun(0);
|
|
1798
|
+
await resolveRun(0);
|
|
1779
1799
|
await p1;
|
|
1780
1800
|
});
|
|
1781
1801
|
|
|
@@ -1798,9 +1818,21 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1798
1818
|
await waitForPendingRun(1);
|
|
1799
1819
|
|
|
1800
1820
|
// Enqueue three sibling passthroughs while msg-1 is mid-turn
|
|
1801
|
-
conversation.enqueueMessage(
|
|
1802
|
-
|
|
1803
|
-
|
|
1821
|
+
conversation.enqueueMessage({
|
|
1822
|
+
content: "msg-2",
|
|
1823
|
+
onEvent: (e) => events2.push(e),
|
|
1824
|
+
requestId: "req-2",
|
|
1825
|
+
});
|
|
1826
|
+
conversation.enqueueMessage({
|
|
1827
|
+
content: "msg-3",
|
|
1828
|
+
onEvent: (e) => events3.push(e),
|
|
1829
|
+
requestId: "req-3",
|
|
1830
|
+
});
|
|
1831
|
+
conversation.enqueueMessage({
|
|
1832
|
+
content: "msg-4",
|
|
1833
|
+
onEvent: (e) => events4.push(e),
|
|
1834
|
+
requestId: "req-4",
|
|
1835
|
+
});
|
|
1804
1836
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
1805
1837
|
|
|
1806
1838
|
// Simulate the agent loop yielding at the checkpoint (first run is mid-tool-use)
|
|
@@ -1815,7 +1847,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1815
1847
|
expect(decision).toBe("yield");
|
|
1816
1848
|
|
|
1817
1849
|
// Complete first run
|
|
1818
|
-
resolveRun(0);
|
|
1850
|
+
await resolveRun(0);
|
|
1819
1851
|
await p1;
|
|
1820
1852
|
|
|
1821
1853
|
// The yielded drain pulls ALL THREE queued siblings as ONE batched run —
|
|
@@ -1829,7 +1861,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1829
1861
|
expect(events4.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
1830
1862
|
|
|
1831
1863
|
// Resolve the batched run — message_complete fans out to all three clients.
|
|
1832
|
-
resolveRun(1);
|
|
1864
|
+
await resolveRun(1);
|
|
1833
1865
|
await new Promise((r) => setTimeout(r, 10));
|
|
1834
1866
|
|
|
1835
1867
|
expect(events2.some((e) => e.type === "message_complete")).toBe(true);
|
|
@@ -1854,7 +1886,11 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1854
1886
|
await waitForPendingRun(1);
|
|
1855
1887
|
|
|
1856
1888
|
// Enqueue a second message while the first is processing
|
|
1857
|
-
conversation.enqueueMessage(
|
|
1889
|
+
conversation.enqueueMessage({
|
|
1890
|
+
content: "msg-2",
|
|
1891
|
+
onEvent: (e) => events2.push(e),
|
|
1892
|
+
requestId: "req-2",
|
|
1893
|
+
});
|
|
1858
1894
|
expect(conversation.hasQueuedMessages()).toBe(true);
|
|
1859
1895
|
|
|
1860
1896
|
// Simulate tool-use turns: the agent loop calls onCheckpoint at each turn boundary.
|
|
@@ -1873,7 +1909,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1873
1909
|
expect(decision).toBe("yield");
|
|
1874
1910
|
|
|
1875
1911
|
// Complete the run (AgentLoop resolves after yielding)
|
|
1876
|
-
resolveRun(0);
|
|
1912
|
+
await resolveRun(0);
|
|
1877
1913
|
await p1;
|
|
1878
1914
|
|
|
1879
1915
|
// Verify generation_handoff was emitted (not plain message_complete)
|
|
@@ -1896,7 +1932,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1896
1932
|
expect(events2.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
1897
1933
|
|
|
1898
1934
|
// Complete the second run
|
|
1899
|
-
resolveRun(1);
|
|
1935
|
+
await resolveRun(1);
|
|
1900
1936
|
await new Promise((r) => setTimeout(r, 10));
|
|
1901
1937
|
});
|
|
1902
1938
|
|
|
@@ -1926,33 +1962,24 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1926
1962
|
userMessageInterface: iface,
|
|
1927
1963
|
assistantMessageInterface: iface,
|
|
1928
1964
|
});
|
|
1929
|
-
conversation.enqueueMessage(
|
|
1930
|
-
"msg-B",
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
"
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
"
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
"
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
meta("
|
|
1946
|
-
);
|
|
1947
|
-
conversation.enqueueMessage(
|
|
1948
|
-
"msg-D",
|
|
1949
|
-
[],
|
|
1950
|
-
makeHandler("D"),
|
|
1951
|
-
"req-D",
|
|
1952
|
-
undefined,
|
|
1953
|
-
undefined,
|
|
1954
|
-
meta("vellum"),
|
|
1955
|
-
);
|
|
1965
|
+
conversation.enqueueMessage({
|
|
1966
|
+
content: "msg-B",
|
|
1967
|
+
onEvent: makeHandler("B"),
|
|
1968
|
+
requestId: "req-B",
|
|
1969
|
+
metadata: meta("macos"),
|
|
1970
|
+
});
|
|
1971
|
+
conversation.enqueueMessage({
|
|
1972
|
+
content: "msg-C",
|
|
1973
|
+
onEvent: makeHandler("C"),
|
|
1974
|
+
requestId: "req-C",
|
|
1975
|
+
metadata: meta("cli"),
|
|
1976
|
+
});
|
|
1977
|
+
conversation.enqueueMessage({
|
|
1978
|
+
content: "msg-D",
|
|
1979
|
+
onEvent: makeHandler("D"),
|
|
1980
|
+
requestId: "req-D",
|
|
1981
|
+
metadata: meta("vellum"),
|
|
1982
|
+
});
|
|
1956
1983
|
expect(conversation.getQueueDepth()).toBe(3);
|
|
1957
1984
|
|
|
1958
1985
|
// Handoff from A -> B
|
|
@@ -1966,7 +1993,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1966
1993
|
history: [],
|
|
1967
1994
|
}),
|
|
1968
1995
|
).toBe("yield");
|
|
1969
|
-
resolveRun(0);
|
|
1996
|
+
await resolveRun(0);
|
|
1970
1997
|
await pA;
|
|
1971
1998
|
|
|
1972
1999
|
// B should be draining
|
|
@@ -1983,7 +2010,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1983
2010
|
history: [],
|
|
1984
2011
|
}),
|
|
1985
2012
|
).toBe("yield");
|
|
1986
|
-
resolveRun(1);
|
|
2013
|
+
await resolveRun(1);
|
|
1987
2014
|
await waitForPendingRun(3);
|
|
1988
2015
|
|
|
1989
2016
|
// Handoff from C -> D
|
|
@@ -1998,7 +2025,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
1998
2025
|
history: [],
|
|
1999
2026
|
}),
|
|
2000
2027
|
).toBe("yield");
|
|
2001
|
-
resolveRun(2);
|
|
2028
|
+
await resolveRun(2);
|
|
2002
2029
|
await waitForPendingRun(4);
|
|
2003
2030
|
|
|
2004
2031
|
// D has no more queued -> checkpoint should return 'continue'
|
|
@@ -2013,7 +2040,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
2013
2040
|
}),
|
|
2014
2041
|
).toBe("continue");
|
|
2015
2042
|
|
|
2016
|
-
resolveRun(3);
|
|
2043
|
+
await resolveRun(3);
|
|
2017
2044
|
await new Promise((r) => setTimeout(r, 10));
|
|
2018
2045
|
|
|
2019
2046
|
// Verify FIFO dequeue order
|
|
@@ -2038,12 +2065,20 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
2038
2065
|
await waitForPendingRun(1);
|
|
2039
2066
|
|
|
2040
2067
|
// Enqueue B (empty content — will fail to persist) and C (valid)
|
|
2041
|
-
conversation.enqueueMessage(
|
|
2042
|
-
|
|
2068
|
+
conversation.enqueueMessage({
|
|
2069
|
+
content: "",
|
|
2070
|
+
onEvent: (e) => eventsB.push(e),
|
|
2071
|
+
requestId: "req-B",
|
|
2072
|
+
});
|
|
2073
|
+
conversation.enqueueMessage({
|
|
2074
|
+
content: "msg-C",
|
|
2075
|
+
onEvent: (e) => eventsC.push(e),
|
|
2076
|
+
requestId: "req-C",
|
|
2077
|
+
});
|
|
2043
2078
|
expect(conversation.getQueueDepth()).toBe(2);
|
|
2044
2079
|
|
|
2045
2080
|
// Complete message A — triggers drain. B should fail, C should proceed.
|
|
2046
|
-
resolveRun(0);
|
|
2081
|
+
await resolveRun(0);
|
|
2047
2082
|
await pA;
|
|
2048
2083
|
|
|
2049
2084
|
// C should have been dequeued and started a new AgentLoop.run
|
|
@@ -2060,7 +2095,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
2060
2095
|
expect(eventsC.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
2061
2096
|
|
|
2062
2097
|
// Complete C's run
|
|
2063
|
-
resolveRun(1);
|
|
2098
|
+
await resolveRun(1);
|
|
2064
2099
|
await new Promise((r) => setTimeout(r, 10));
|
|
2065
2100
|
|
|
2066
2101
|
// C should have completed successfully
|
|
@@ -2097,7 +2132,7 @@ describe("Conversation checkpoint handoff", () => {
|
|
|
2097
2132
|
expect(pendingRuns[1].onCheckpoint).toBeDefined();
|
|
2098
2133
|
|
|
2099
2134
|
// Complete retry cleanly
|
|
2100
|
-
resolveRun(1);
|
|
2135
|
+
await resolveRun(1);
|
|
2101
2136
|
await p1;
|
|
2102
2137
|
});
|
|
2103
2138
|
});
|
|
@@ -2120,7 +2155,7 @@ describe("Conversation usage requestId correlation", () => {
|
|
|
2120
2155
|
await waitForPendingRun(1);
|
|
2121
2156
|
|
|
2122
2157
|
// Complete the run — this triggers recordUsage with the request's ID
|
|
2123
|
-
resolveRun(0);
|
|
2158
|
+
await resolveRun(0);
|
|
2124
2159
|
await p1;
|
|
2125
2160
|
|
|
2126
2161
|
// The usage event should carry the request ID, not null
|
|
@@ -2153,12 +2188,12 @@ describe("Terminal trace events on rejection/failure", () => {
|
|
|
2153
2188
|
await waitForPendingRun(1);
|
|
2154
2189
|
|
|
2155
2190
|
// Enqueue empty content (will fail persistUserMessage)
|
|
2156
|
-
conversation.enqueueMessage("",
|
|
2191
|
+
conversation.enqueueMessage({ content: "", requestId: "req-bad" });
|
|
2157
2192
|
// Enqueue valid message so drain continues
|
|
2158
|
-
conversation.enqueueMessage("msg-3",
|
|
2193
|
+
conversation.enqueueMessage({ content: "msg-3", requestId: "req-3" });
|
|
2159
2194
|
|
|
2160
2195
|
// Complete first — triggers drain, empty msg fails persist
|
|
2161
|
-
resolveRun(0);
|
|
2196
|
+
await resolveRun(0);
|
|
2162
2197
|
await p1;
|
|
2163
2198
|
await waitForPendingRun(2);
|
|
2164
2199
|
|
|
@@ -2173,7 +2208,7 @@ describe("Terminal trace events on rejection/failure", () => {
|
|
|
2173
2208
|
expect(errorTrace).toBeDefined();
|
|
2174
2209
|
|
|
2175
2210
|
// Cleanup
|
|
2176
|
-
resolveRun(1);
|
|
2211
|
+
await resolveRun(1);
|
|
2177
2212
|
await new Promise((r) => setTimeout(r, 10));
|
|
2178
2213
|
});
|
|
2179
2214
|
});
|
|
@@ -2215,6 +2250,7 @@ describe("Conversation host attachment directives", () => {
|
|
|
2215
2250
|
},
|
|
2216
2251
|
],
|
|
2217
2252
|
};
|
|
2253
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
2218
2254
|
run.onEvent({
|
|
2219
2255
|
type: "usage",
|
|
2220
2256
|
inputTokens: 10,
|
|
@@ -2284,6 +2320,7 @@ describe("Conversation host attachment directives", () => {
|
|
|
2284
2320
|
},
|
|
2285
2321
|
],
|
|
2286
2322
|
};
|
|
2323
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
2287
2324
|
run.onEvent({
|
|
2288
2325
|
type: "usage",
|
|
2289
2326
|
inputTokens: 10,
|
|
@@ -2377,6 +2414,7 @@ describe("Conversation attachment event payloads", () => {
|
|
|
2377
2414
|
} as any,
|
|
2378
2415
|
],
|
|
2379
2416
|
});
|
|
2417
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
2380
2418
|
run.onEvent({
|
|
2381
2419
|
type: "usage",
|
|
2382
2420
|
inputTokens: 10,
|
|
@@ -2423,7 +2461,7 @@ describe("Conversation attachment event payloads", () => {
|
|
|
2423
2461
|
await waitForPendingRun(1);
|
|
2424
2462
|
|
|
2425
2463
|
// Queue a second message so the first run yields via checkpoint handoff.
|
|
2426
|
-
conversation.enqueueMessage("msg-2",
|
|
2464
|
+
conversation.enqueueMessage({ content: "msg-2", requestId: "req-2" });
|
|
2427
2465
|
|
|
2428
2466
|
const run = pendingRuns[0];
|
|
2429
2467
|
expect(run.onCheckpoint).toBeDefined();
|
|
@@ -2452,6 +2490,7 @@ describe("Conversation attachment event payloads", () => {
|
|
|
2452
2490
|
} as any,
|
|
2453
2491
|
],
|
|
2454
2492
|
});
|
|
2493
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
2455
2494
|
run.onEvent({
|
|
2456
2495
|
type: "usage",
|
|
2457
2496
|
inputTokens: 10,
|
|
@@ -2478,7 +2517,7 @@ describe("Conversation attachment event payloads", () => {
|
|
|
2478
2517
|
expect(attachments[0].data).toBe("iVBORw0K");
|
|
2479
2518
|
|
|
2480
2519
|
await waitForPendingRun(2);
|
|
2481
|
-
resolveRun(1);
|
|
2520
|
+
await resolveRun(1);
|
|
2482
2521
|
await new Promise((r) => setTimeout(r, 10));
|
|
2483
2522
|
});
|
|
2484
2523
|
});
|
|
@@ -2510,7 +2549,7 @@ describe("Regression: cancel semantics and error channel split", () => {
|
|
|
2510
2549
|
conversation.abort();
|
|
2511
2550
|
|
|
2512
2551
|
// Resolve the pending run so the abort-check path fires
|
|
2513
|
-
resolveRun(0);
|
|
2552
|
+
await resolveRun(0);
|
|
2514
2553
|
await p1;
|
|
2515
2554
|
|
|
2516
2555
|
// generation_cancelled should be emitted via the per-message callback
|
|
@@ -2556,6 +2595,7 @@ describe("Regression: cancel semantics and error channel split", () => {
|
|
|
2556
2595
|
} as any,
|
|
2557
2596
|
],
|
|
2558
2597
|
});
|
|
2598
|
+
await run.onEvent({ type: "llm_call_started" });
|
|
2559
2599
|
run.onEvent({
|
|
2560
2600
|
type: "usage",
|
|
2561
2601
|
inputTokens: 10,
|
|
@@ -2622,18 +2662,16 @@ describe("Regression: cancel semantics and error channel split", () => {
|
|
|
2622
2662
|
);
|
|
2623
2663
|
await waitForPendingRun(1);
|
|
2624
2664
|
|
|
2625
|
-
conversation.enqueueMessage(
|
|
2626
|
-
"msg-2",
|
|
2627
|
-
[],
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
"req-3",
|
|
2636
|
-
);
|
|
2665
|
+
conversation.enqueueMessage({
|
|
2666
|
+
content: "msg-2",
|
|
2667
|
+
onEvent: (e) => eventsPerMsg[1].push(e),
|
|
2668
|
+
requestId: "req-2",
|
|
2669
|
+
});
|
|
2670
|
+
conversation.enqueueMessage({
|
|
2671
|
+
content: "msg-3",
|
|
2672
|
+
onEvent: (e) => eventsPerMsg[2].push(e),
|
|
2673
|
+
requestId: "req-3",
|
|
2674
|
+
});
|
|
2637
2675
|
|
|
2638
2676
|
conversation.abort();
|
|
2639
2677
|
|
|
@@ -2677,10 +2715,14 @@ describe("Regression: cancel semantics and error channel split", () => {
|
|
|
2677
2715
|
await waitForPendingRun(1);
|
|
2678
2716
|
|
|
2679
2717
|
// Enqueue a second message while the first is processing
|
|
2680
|
-
conversation.enqueueMessage(
|
|
2718
|
+
conversation.enqueueMessage({
|
|
2719
|
+
content: "msg-2",
|
|
2720
|
+
onEvent: (e) => events2.push(e),
|
|
2721
|
+
requestId: "req-2",
|
|
2722
|
+
});
|
|
2681
2723
|
|
|
2682
2724
|
// Complete the first agent loop run
|
|
2683
|
-
resolveRun(0);
|
|
2725
|
+
await resolveRun(0);
|
|
2684
2726
|
|
|
2685
2727
|
// The turn should still complete (timeout fires) and drain the queue
|
|
2686
2728
|
// even though commitTurnChanges never resolves.
|
|
@@ -2701,7 +2743,7 @@ describe("Regression: cancel semantics and error channel split", () => {
|
|
|
2701
2743
|
|
|
2702
2744
|
// Complete the second run so the test can clean up
|
|
2703
2745
|
turnCommitHangForever = false;
|
|
2704
|
-
resolveRun(1);
|
|
2746
|
+
await resolveRun(1);
|
|
2705
2747
|
await new Promise((r) => origSetTimeout(r, 10));
|
|
2706
2748
|
} finally {
|
|
2707
2749
|
turnCommitHangForever = false;
|