@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5
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/bun.lock +20 -0
- package/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/openapi.yaml +196 -56
- package/package.json +4 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +42 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-approval-routes.test.ts +21 -26
- package/src/__tests__/channel-delivery-store.test.ts +28 -0
- package/src/__tests__/channel-guardian.test.ts +164 -78
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/code-search-tool.test.ts +585 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-ledger-store.test.ts +128 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/config-loader-backfill.test.ts +123 -10
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/consult-deadline.test.ts +60 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
- package/src/__tests__/contact-store-user-file.test.ts +7 -10
- package/src/__tests__/contacts-relay-reads.test.ts +19 -24
- package/src/__tests__/contacts-write.test.ts +0 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +134 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-fork-crud.test.ts +354 -24
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/delete-propagation.test.ts +5 -3
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-backfill.test.ts +6 -4
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/exploration-drift-hook.test.ts +3 -2
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
- package/src/__tests__/guardian-dispatch.test.ts +140 -1
- package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/guardian-routing-state.test.ts +6 -10
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
- package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
- package/src/__tests__/helpers/mock-logger.ts +1 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +290 -8
- package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +471 -53
- package/src/__tests__/invite-routes-http.test.ts +34 -0
- package/src/__tests__/invite-service-ipc.test.ts +65 -2
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
- package/src/__tests__/mcp-health-check.test.ts +2 -1
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +275 -5
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +191 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/onboarding-persona-write.test.ts +52 -22
- package/src/__tests__/openai-provider.test.ts +22 -12
- package/src/__tests__/openai-responses-provider.test.ts +12 -2
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/persona-resolver.test.ts +75 -45
- package/src/__tests__/plugin-bootstrap.test.ts +21 -83
- package/src/__tests__/plugin-disabled-state.test.ts +190 -0
- package/src/__tests__/plugin-pipeline.test.ts +96 -0
- package/src/__tests__/plugin-route-contribution.test.ts +6 -19
- package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
- package/src/__tests__/plugin-types.test.ts +2 -4
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-error-scenarios.test.ts +5 -4
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
- package/src/__tests__/reaction-persistence.test.ts +51 -4
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +4 -1
- package/src/__tests__/relay-server.test.ts +758 -32
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/settings-routes.test.ts +32 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +49 -15
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -6
- package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +398 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +3 -3
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
- package/src/__tests__/trusted-contact-verification.test.ts +79 -54
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
- package/src/__tests__/voice-invite-redemption.test.ts +216 -20
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
- package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
- package/src/agent/loop-exclusive-tool.test.ts +154 -0
- package/src/agent/loop-native-web-search.test.ts +200 -0
- package/src/agent/loop.ts +164 -1
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/conversation-notice.ts +26 -0
- package/src/api/index.ts +19 -1
- package/src/api/responses/llm-request-log-entry.ts +29 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +39 -3
- package/src/approvals/guardian-channel-delivery.ts +30 -0
- package/src/approvals/guardian-expiry-notifier.ts +148 -0
- package/src/approvals/guardian-request-resolvers.ts +17 -15
- package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +14 -9
- package/src/calls/inbound-trust-reader.ts +24 -2
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-access-wait.ts +6 -6
- package/src/calls/relay-server.ts +188 -51
- package/src/calls/relay-setup-router.ts +47 -17
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/channels/types.ts +10 -20
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +10 -7
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +242 -0
- package/src/cli/commands/plugins.ts +125 -13
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/publish-plugin.ts +633 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/feature-flag-registry.json +5 -13
- package/src/config/llm-resolver.ts +0 -3
- package/src/config/loader.ts +38 -5
- package/src/config/prune-seeded-callsite-defaults.ts +110 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/heartbeat.ts +2 -5
- package/src/config/schemas/llm.ts +3 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +30 -34
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +12 -16
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
- package/src/contacts/contact-store.ts +27 -237
- package/src/contacts/contacts-write.ts +18 -55
- package/src/contacts/gateway-channel-read.ts +51 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-write-relay.ts +183 -0
- package/src/contacts/types.ts +3 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
- package/src/daemon/assistant-attachments.ts +27 -4
- package/src/daemon/conversation-agent-loop.ts +28 -0
- package/src/daemon/conversation-notices.ts +60 -0
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-surfaces.ts +111 -38
- package/src/daemon/conversation-tool-setup.ts +71 -30
- package/src/daemon/conversation.ts +23 -1
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +17 -41
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +67 -26
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/lifecycle.ts +16 -0
- package/src/daemon/mcp-reload-service.ts +10 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/heartbeat/heartbeat-service.ts +5 -0
- package/src/home/relationship-state-writer.ts +5 -0
- package/src/hooks/hook-loader.ts +341 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -0
- package/src/mcp/client.ts +15 -1
- package/src/mcp/mcp-auth-orchestrator.ts +6 -1
- package/src/mcp/mcp-header-store.ts +134 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -8
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/compaction-ledger-store.ts +107 -0
- package/src/memory/conversation-crud.ts +129 -61
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +37 -503
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +104 -0
- package/src/memory/llm-request-log-store.ts +26 -1
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +14 -8
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/302-create-compaction-events.ts +107 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +106 -10
- package/src/memory/migrations/validate-migration-state.ts +105 -67
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/contacts.ts +6 -2
- package/src/memory/schema/conversations.ts +37 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +1294 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +204 -0
- package/src/memory/worker-process.ts +89 -0
- package/src/messaging/channel-binding-metadata.ts +31 -0
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/providers/slack/binding-metadata.ts +60 -0
- package/src/notifications/__tests__/broadcaster.test.ts +8 -8
- package/src/notifications/__tests__/connected-channels.test.ts +86 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +53 -25
- package/src/notifications/emit-signal.ts +34 -15
- package/src/onboarding/checkin-event.test.ts +222 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +12 -12
- package/src/plugin-api/types.ts +12 -14
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
- package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
- package/src/plugins/defaults/index.ts +0 -35
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
- package/src/plugins/disabled-state.ts +31 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/mtime-cache.ts +186 -330
- package/src/plugins/pipeline.ts +111 -13
- package/src/plugins/registry.ts +59 -16
- package/src/plugins/surface-import.ts +121 -0
- package/src/plugins/types.ts +7 -9
- package/src/prompts/persona-resolver.ts +43 -11
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +45 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
- package/src/providers/openai/api-error-normalization.ts +270 -0
- package/src/providers/openai/chat-completions-provider.ts +37 -83
- package/src/providers/openai/responses-provider.ts +50 -46
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +10 -0
- package/src/providers/ratelimit.ts +10 -0
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +10 -0
- package/src/providers/types.ts +22 -0
- package/src/providers/usage-tracking.ts +10 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
- package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
- package/src/runtime/access-request-helper.ts +18 -39
- package/src/runtime/actor-trust-resolver.ts +46 -19
- package/src/runtime/anchored-guardian.test.ts +109 -0
- package/src/runtime/anchored-guardian.ts +86 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +69 -8
- package/src/runtime/invite-redemption-service.ts +213 -187
- package/src/runtime/local-actor-identity.test.ts +108 -0
- package/src/runtime/local-actor-identity.ts +85 -13
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/member-verdict-cache.ts +0 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
- package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +48 -57
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-query-routes.ts +72 -0
- package/src/runtime/routes/conversation-routes.ts +84 -85
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +16 -1
- package/src/runtime/routes/identity-routes.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +83 -0
- package/src/runtime/routes/mcp-auth-routes.ts +171 -19
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/settings-routes.ts +8 -3
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +42 -56
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +13 -58
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +111 -40
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
- package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
- package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
- package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
- package/src/subagent/index.ts +1 -1
- package/src/subagent/manager.ts +254 -33
- package/src/subagent/types.ts +11 -4
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/executor.ts +4 -4
- package/src/tools/filesystem/search.ts +543 -0
- package/src/tools/registry.ts +38 -0
- package/src/tools/shared/filesystem/path-policy.ts +12 -5
- package/src/tools/subagent/consult-deadline.ts +49 -0
- package/src/tools/subagent/spawn.ts +234 -5
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/tool-manifest.ts +3 -0
- package/src/tools/types.ts +131 -25
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/errors.ts +26 -1
- package/src/util/logger.ts +9 -0
- package/src/util/platform.ts +19 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workflows/library.test.ts +140 -0
- package/src/workflows/library.ts +82 -28
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/workspace/migrations/031-drop-user-md.ts +232 -148
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
- package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
- package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
- package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
- package/src/plugins/defaults/advisor/config.ts +0 -21
- package/src/plugins/defaults/advisor/consult.ts +0 -93
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/advisor/package.json +0 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
- package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
|
@@ -808,7 +808,7 @@ describe("memory-v3 shadow plugin", () => {
|
|
|
808
808
|
});
|
|
809
809
|
});
|
|
810
810
|
|
|
811
|
-
describe("memory-v3 infrastructure-failure handling
|
|
811
|
+
describe("memory-v3 infrastructure-failure handling", () => {
|
|
812
812
|
const throwInfra = () =>
|
|
813
813
|
orchestrateSpy.mockImplementationOnce(async () => {
|
|
814
814
|
throw new MemoryV3RetrievalUnavailableError(
|
|
@@ -816,14 +816,12 @@ describe("memory-v3 infrastructure-failure handling (hard-fail vs swallow)", ()
|
|
|
816
816
|
);
|
|
817
817
|
});
|
|
818
818
|
|
|
819
|
-
test("LIVE injector
|
|
819
|
+
test("LIVE injector logs and degrades to no v3 block on an infra failure", async () => {
|
|
820
820
|
liveEnabled = true;
|
|
821
821
|
shadowEnabled = false;
|
|
822
822
|
throwInfra();
|
|
823
823
|
|
|
824
|
-
await
|
|
825
|
-
MemoryV3RetrievalUnavailableError,
|
|
826
|
-
);
|
|
824
|
+
expect(await produce("conv-infra-live", 0)).toBeNull();
|
|
827
825
|
});
|
|
828
826
|
|
|
829
827
|
test("SHADOW injector swallows an infra failure (v2 fallback) — no throw, no block", async () => {
|
|
@@ -832,7 +830,7 @@ describe("memory-v3 infrastructure-failure handling (hard-fail vs swallow)", ()
|
|
|
832
830
|
throwInfra();
|
|
833
831
|
|
|
834
832
|
// Shadow mode: v2 retrieval still ran this turn, so the v3 injector returns
|
|
835
|
-
// null
|
|
833
|
+
// null.
|
|
836
834
|
expect(await produce("conv-infra-shadow", 0)).toBeNull();
|
|
837
835
|
});
|
|
838
836
|
|
|
@@ -853,8 +851,6 @@ describe("memory-v3 infrastructure-failure handling (hard-fail vs swallow)", ()
|
|
|
853
851
|
throw new Error("some unexpected non-infra bug");
|
|
854
852
|
});
|
|
855
853
|
|
|
856
|
-
// Only INFRA failures hard-fail; any other error stays non-fatal so a bug
|
|
857
|
-
// in one lane can't take every turn down.
|
|
858
854
|
expect(await produce("conv-nonfatal-live", 0)).toBeNull();
|
|
859
855
|
});
|
|
860
856
|
});
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* `../injector.js` and re-apply it here. Until then this hook does nothing.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type { HookFunction } from "@vellumai/plugin-api";
|
|
11
11
|
|
|
12
|
-
const postCompact:
|
|
12
|
+
const postCompact: HookFunction = async () => {};
|
|
13
13
|
|
|
14
14
|
export default postCompact;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type {
|
|
13
|
-
|
|
13
|
+
HookFunction,
|
|
14
14
|
UserPromptSubmitContext,
|
|
15
15
|
} from "@vellumai/plugin-api";
|
|
16
16
|
|
|
17
|
-
const userPromptSubmit:
|
|
17
|
+
const userPromptSubmit: HookFunction<UserPromptSubmitContext> = async () => {};
|
|
18
18
|
|
|
19
19
|
export default userPromptSubmit;
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
|
|
64
64
|
import { getConfig } from "../../../config/loader.js";
|
|
65
65
|
import { isMemoryV3Live } from "../../../config/memory-v3-gate.js";
|
|
66
|
+
import {
|
|
67
|
+
type PendingConversationNotice,
|
|
68
|
+
queueConversationNotice,
|
|
69
|
+
} from "../../../daemon/conversation-notices.js";
|
|
66
70
|
import { isPersonalMemoryAllowed } from "../../../daemon/trust-context.js";
|
|
67
71
|
import {
|
|
68
72
|
wrapMemoryBlock,
|
|
@@ -120,6 +124,26 @@ function lruSet<V>(map: Map<string, V>, key: string, value: V): void {
|
|
|
120
124
|
map.set(key, value);
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
function queueMemoryV3ConversationNotice(
|
|
128
|
+
err: MemoryV3RetrievalUnavailableError,
|
|
129
|
+
ctx: TurnContext,
|
|
130
|
+
live: boolean,
|
|
131
|
+
): void {
|
|
132
|
+
if (!live) return;
|
|
133
|
+
const notice: PendingConversationNotice = err.conversationNotice ?? {
|
|
134
|
+
source: "memory_v3",
|
|
135
|
+
code: "UNKNOWN",
|
|
136
|
+
userMessage:
|
|
137
|
+
"Memory is temporarily unavailable, so this response may not use your saved memories. You can retry in a moment.",
|
|
138
|
+
errorCategory: "memory_v3_degraded",
|
|
139
|
+
};
|
|
140
|
+
queueConversationNotice(
|
|
141
|
+
ctx.conversationId,
|
|
142
|
+
`memory_v3:${ctx.turnIndex}:${notice.errorCategory ?? notice.code}`,
|
|
143
|
+
notice,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
123
147
|
// ─── shared per-turn orchestration memo ─────────────────────────────────────
|
|
124
148
|
|
|
125
149
|
interface ObservedTurn {
|
|
@@ -245,16 +269,16 @@ export const memoryV3Injector: Injector = {
|
|
|
245
269
|
try {
|
|
246
270
|
observed = await observeTurnOnce(ctx.conversationId, ctx.turnIndex);
|
|
247
271
|
} catch (err) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
272
|
+
if (err instanceof MemoryV3RetrievalUnavailableError) {
|
|
273
|
+
queueMemoryV3ConversationNotice(err, ctx, live);
|
|
274
|
+
log.error(
|
|
275
|
+
{
|
|
276
|
+
err: err.message,
|
|
277
|
+
conversationId: ctx.conversationId,
|
|
278
|
+
mode: live ? "live" : "shadow",
|
|
279
|
+
},
|
|
280
|
+
"memory-v3 selection failed; skipping v3 memory for this turn",
|
|
281
|
+
);
|
|
258
282
|
}
|
|
259
283
|
return null;
|
|
260
284
|
}
|
|
@@ -405,12 +429,16 @@ export const memoryV3SpotlightInjector: Injector = {
|
|
|
405
429
|
placement: "after-memory-prefix",
|
|
406
430
|
};
|
|
407
431
|
} catch (err) {
|
|
408
|
-
// Live-only injector: an infra failure must hard-fail the turn. The cards
|
|
409
|
-
// injector (ordered ahead of this one) normally throws first, so this
|
|
410
|
-
// path is defensive — it keeps the behavior correct if the cards injector
|
|
411
|
-
// is ever disabled or reordered.
|
|
412
432
|
if (err instanceof MemoryV3RetrievalUnavailableError) {
|
|
413
|
-
|
|
433
|
+
queueMemoryV3ConversationNotice(err, ctx, true);
|
|
434
|
+
log.error(
|
|
435
|
+
{
|
|
436
|
+
err: err.message,
|
|
437
|
+
conversationId: ctx.conversationId,
|
|
438
|
+
},
|
|
439
|
+
"memory-v3 spotlight selection failed; skipping spotlight",
|
|
440
|
+
);
|
|
441
|
+
return null;
|
|
414
442
|
}
|
|
415
443
|
log.warn(
|
|
416
444
|
{
|
|
@@ -119,6 +119,10 @@ export interface OrchestrateDeps {
|
|
|
119
119
|
/** Hard cap on total learned-lane surfaced articles; `0` disables the pass
|
|
120
120
|
* (canonical value: `memory.v3.learnedEdges.cap`). */
|
|
121
121
|
learnedCap?: number;
|
|
122
|
+
/** The selector's system prompt. Omitted → the selector's bundled default.
|
|
123
|
+
* The live caller resolves `memory.v3.selectorPromptPath` (workspace-relative
|
|
124
|
+
* file override) via `resolveSelectorPrompt` and threads the result here. */
|
|
125
|
+
selectorPrompt?: string;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
/** A finder-lane candidate: the slug, the descriptor that justified it, and
|
|
@@ -378,8 +382,13 @@ export async function orchestrate(
|
|
|
378
382
|
|
|
379
383
|
// Step 3: a SINGLE forced-tool select over the cache-ordered pool. The
|
|
380
384
|
// selections come back slug-deduped (pinned flags ORed) — `selectPool`'s
|
|
381
|
-
// contract.
|
|
382
|
-
|
|
385
|
+
// contract. `selectorPrompt` is the (optionally overridden) instruction
|
|
386
|
+
// scaffold; `undefined` falls through to the bundled default.
|
|
387
|
+
const selections = await selectPool(
|
|
388
|
+
{ stable, finder: finderTail },
|
|
389
|
+
turn,
|
|
390
|
+
deps.selectorPrompt,
|
|
391
|
+
);
|
|
383
392
|
|
|
384
393
|
return {
|
|
385
394
|
selections,
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `pool-select.ts` `selectPool` — focused on error SURFACING:
|
|
3
|
+
* - a provider call that THROWS on every attempt surfaces the underlying
|
|
4
|
+
* provider error (e.g. an upstream HTTP 4xx) in the thrown
|
|
5
|
+
* `MemoryV3RetrievalUnavailableError` message, rather than the generic
|
|
6
|
+
* "no usable selection" string that hid it;
|
|
7
|
+
* - a 200 response carrying no usable `tool_use` still throws the generic
|
|
8
|
+
* "no usable selection" message;
|
|
9
|
+
* - happy paths preserved: explicit ids → selection, omitted ids → keepAll,
|
|
10
|
+
* empty pool → [].
|
|
11
|
+
*
|
|
12
|
+
* `mock.module` is process-global and leaks into sibling files in a directory
|
|
13
|
+
* run, so the provider-send-message stub DELEGATES to the real implementation
|
|
14
|
+
* (keeping the real `extractToolUse`) unless this test is actively running
|
|
15
|
+
* (`selectMockActive`) — mirrors `prune.test.ts` / `ever-injected-store.test.ts`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
19
|
+
|
|
20
|
+
import type {
|
|
21
|
+
ContentBlock,
|
|
22
|
+
Provider,
|
|
23
|
+
ProviderResponse,
|
|
24
|
+
} from "../../../providers/types.js";
|
|
25
|
+
import type { MemoryRoutingTurn, Slug } from "./types.js";
|
|
26
|
+
|
|
27
|
+
const realProviderSend = {
|
|
28
|
+
...(await import("../../../providers/provider-send-message.js")),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let selectMockActive = false;
|
|
32
|
+
let sendMessageImpl: (() => Promise<ProviderResponse>) | null = null;
|
|
33
|
+
|
|
34
|
+
const mockProvider = {
|
|
35
|
+
name: "mock-memory-v3-selector",
|
|
36
|
+
async sendMessage(): Promise<ProviderResponse> {
|
|
37
|
+
if (!sendMessageImpl) throw new Error("sendMessageImpl not configured");
|
|
38
|
+
return sendMessageImpl();
|
|
39
|
+
},
|
|
40
|
+
} as unknown as Provider;
|
|
41
|
+
|
|
42
|
+
mock.module("../../../providers/provider-send-message.js", () => ({
|
|
43
|
+
...realProviderSend,
|
|
44
|
+
getConfiguredProvider: (
|
|
45
|
+
...args: Parameters<typeof realProviderSend.getConfiguredProvider>
|
|
46
|
+
) =>
|
|
47
|
+
selectMockActive
|
|
48
|
+
? Promise.resolve(mockProvider)
|
|
49
|
+
: realProviderSend.getConfiguredProvider(...args),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
const { MemoryV3RetrievalUnavailableError, selectPool } =
|
|
53
|
+
await import("./pool-select.js");
|
|
54
|
+
|
|
55
|
+
function response(content: ContentBlock[]): ProviderResponse {
|
|
56
|
+
return {
|
|
57
|
+
content,
|
|
58
|
+
model: "mock",
|
|
59
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
60
|
+
} as ProviderResponse;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const turn: MemoryRoutingTurn = {
|
|
64
|
+
conversationId: "conv-1",
|
|
65
|
+
turnNumber: 0,
|
|
66
|
+
currentMessage: "echo something back",
|
|
67
|
+
recentContext: "",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const pool = {
|
|
71
|
+
stable: [],
|
|
72
|
+
finder: [{ slug: "page-a" as Slug, descriptor: "a descriptor" }],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
describe("selectPool", () => {
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
selectMockActive = true;
|
|
78
|
+
sendMessageImpl = null;
|
|
79
|
+
});
|
|
80
|
+
afterAll(() => {
|
|
81
|
+
selectMockActive = false;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("a provider throw surfaces the underlying error in the thrown message", async () => {
|
|
85
|
+
const upstream = "Together AI API error (400): 400 status code (no body)";
|
|
86
|
+
sendMessageImpl = async () => {
|
|
87
|
+
throw new Error(upstream);
|
|
88
|
+
};
|
|
89
|
+
let caught: unknown;
|
|
90
|
+
try {
|
|
91
|
+
await selectPool(pool, turn);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
caught = err;
|
|
94
|
+
}
|
|
95
|
+
expect(caught).toBeInstanceOf(MemoryV3RetrievalUnavailableError);
|
|
96
|
+
expect((caught as Error).message).toContain(
|
|
97
|
+
"provider call failed after retries",
|
|
98
|
+
);
|
|
99
|
+
// The real upstream error is no longer hidden behind the generic message.
|
|
100
|
+
expect((caught as Error).message).toContain(upstream);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("a 200 with no usable tool_use throws the generic message", async () => {
|
|
104
|
+
sendMessageImpl = async () =>
|
|
105
|
+
response([{ type: "text", text: "I cannot call the tool." }]);
|
|
106
|
+
let caught: unknown;
|
|
107
|
+
try {
|
|
108
|
+
await selectPool(pool, turn);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
caught = err;
|
|
111
|
+
}
|
|
112
|
+
expect(caught).toBeInstanceOf(MemoryV3RetrievalUnavailableError);
|
|
113
|
+
expect((caught as Error).message).toBe(
|
|
114
|
+
"memory-v3 pool selector returned no usable selection after retries",
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("explicit ids select the matching candidates", async () => {
|
|
119
|
+
sendMessageImpl = async () =>
|
|
120
|
+
response([
|
|
121
|
+
{
|
|
122
|
+
type: "tool_use",
|
|
123
|
+
id: "call-1",
|
|
124
|
+
name: "select_pages",
|
|
125
|
+
input: { ids: [1] },
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
expect(await selectPool(pool, turn)).toEqual([
|
|
129
|
+
{ slug: "page-a", pinned: false },
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("omitted ids keep all candidates (recall-safe)", async () => {
|
|
134
|
+
sendMessageImpl = async () =>
|
|
135
|
+
response([
|
|
136
|
+
{ type: "tool_use", id: "call-1", name: "select_pages", input: {} },
|
|
137
|
+
]);
|
|
138
|
+
expect(await selectPool(pool, turn)).toEqual([
|
|
139
|
+
{ slug: "page-a", pinned: false },
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("an empty candidate pool returns no selections", async () => {
|
|
144
|
+
expect(await selectPool({ stable: [], finder: [] }, turn)).toEqual([]);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -41,15 +41,16 @@
|
|
|
41
41
|
* - infrastructure failure (selector provider unavailable — e.g. a transient
|
|
42
42
|
* CES credential blip drops the API key — or no usable `tool_use` / schema
|
|
43
43
|
* mismatch surviving the short re-prompt retry) → throw
|
|
44
|
-
* {@link MemoryV3RetrievalUnavailableError}.
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* while the shadow/observation path swallows it and lets v2 retrieval serve
|
|
48
|
-
* the turn.
|
|
44
|
+
* {@link MemoryV3RetrievalUnavailableError}. The live injector treats this
|
|
45
|
+
* as a logged memory miss for the turn; shadow/observation callers swallow
|
|
46
|
+
* it so v2 retrieval can serve the turn.
|
|
49
47
|
*/
|
|
50
48
|
|
|
51
49
|
import { z } from "zod";
|
|
52
50
|
|
|
51
|
+
import { classifyConversationError } from "../../../daemon/conversation-error.js";
|
|
52
|
+
import type { PendingConversationNotice } from "../../../daemon/conversation-notices.js";
|
|
53
|
+
import { loadPromptOverride } from "../../../memory/prompt-override.js";
|
|
53
54
|
import { cachedTextBlock } from "../../../providers/cache-control.js";
|
|
54
55
|
import {
|
|
55
56
|
extractToolUse,
|
|
@@ -76,17 +77,43 @@ const log = getLogger("memory-v3-pool-select");
|
|
|
76
77
|
* re-prompt retry. Deliberately DISTINCT from a deliberate empty selection
|
|
77
78
|
* (`ids: []`) and an empty candidate pool, both of which return normally.
|
|
78
79
|
*
|
|
79
|
-
* The
|
|
80
|
-
* retryable failure) rather than silently shipping with no memory; the
|
|
80
|
+
* The live memory-v3 injector logs this as a memory miss for the turn; the
|
|
81
81
|
* shadow/observation path catches and swallows it.
|
|
82
82
|
*/
|
|
83
83
|
export class MemoryV3RetrievalUnavailableError extends Error {
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
readonly conversationNotice?: PendingConversationNotice;
|
|
85
|
+
|
|
86
|
+
constructor(
|
|
87
|
+
message: string,
|
|
88
|
+
options?: {
|
|
89
|
+
cause?: unknown;
|
|
90
|
+
conversationNotice?: PendingConversationNotice;
|
|
91
|
+
},
|
|
92
|
+
) {
|
|
93
|
+
super(
|
|
94
|
+
message,
|
|
95
|
+
options?.cause === undefined ? undefined : { cause: options.cause },
|
|
96
|
+
);
|
|
86
97
|
this.name = "MemoryV3RetrievalUnavailableError";
|
|
98
|
+
this.conversationNotice = options?.conversationNotice;
|
|
87
99
|
}
|
|
88
100
|
}
|
|
89
101
|
|
|
102
|
+
function providerBillingNoticeFromError(
|
|
103
|
+
error: unknown,
|
|
104
|
+
): PendingConversationNotice | undefined {
|
|
105
|
+
const classified = classifyConversationError(error, {
|
|
106
|
+
phase: "agent_loop",
|
|
107
|
+
});
|
|
108
|
+
if (classified.code !== "PROVIDER_BILLING") return undefined;
|
|
109
|
+
return {
|
|
110
|
+
source: "memory_v3",
|
|
111
|
+
code: classified.code,
|
|
112
|
+
userMessage: classified.userMessage,
|
|
113
|
+
errorCategory: classified.errorCategory,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
/** A dynamic-tail (finder) candidate: the slug plus the descriptor that
|
|
91
118
|
* justifies it — a matched section for a needle/dense hit, or a curated link
|
|
92
119
|
* description for an edge page. Rendered as a one-line snippet, prefixed
|
|
@@ -201,6 +228,28 @@ A page can be relevant because of the current situation — the date or the live
|
|
|
201
228
|
|
|
202
229
|
If the conversation is centrally ABOUT a page (rather than only peripherally relevant to it), mark that page as pinned. Call \`select_pages\` with the chosen IDs. Omit \`ids\` only as a recall-safe fallback when you cannot judge the pool (keeps every candidate); return \`[]\` when candidates are present but none are relevant.`;
|
|
203
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Resolve the selector system prompt: the file at `overridePath` when it is set
|
|
233
|
+
* and usable, otherwise the bundled {@link SYSTEM_PROMPT}. Path resolution and
|
|
234
|
+
* fallback follow the shared override loader (workspace-relative; a missing,
|
|
235
|
+
* empty, oversized, or unreadable file degrades to the bundled prompt with a
|
|
236
|
+
* warning). The selector prompt takes no placeholders — the candidate pool is
|
|
237
|
+
* the user message — so an override file is used verbatim.
|
|
238
|
+
*/
|
|
239
|
+
export function resolveSelectorPrompt(
|
|
240
|
+
overridePath: string | null,
|
|
241
|
+
workspaceDir: string,
|
|
242
|
+
): string {
|
|
243
|
+
return (
|
|
244
|
+
loadPromptOverride({
|
|
245
|
+
overridePath,
|
|
246
|
+
workspaceDir,
|
|
247
|
+
log,
|
|
248
|
+
label: "memory-v3 selector prompt",
|
|
249
|
+
}) ?? SYSTEM_PROMPT
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
204
253
|
/** Collapse a descriptor to one line and cap its length for a finder line. */
|
|
205
254
|
function renderSnippet(descriptor: string): string {
|
|
206
255
|
return truncate(descriptor.replace(/\s+/g, " ").trim(), SNIPPET_MAX_CHARS);
|
|
@@ -315,10 +364,15 @@ function dedupeBySlug(
|
|
|
315
364
|
* relevant" signal); an explicit `[]` keeps none; an infrastructure failure
|
|
316
365
|
* (after a short re-prompt retry) keeps none, degrading to the deterministic
|
|
317
366
|
* recall lanes the orchestrator unions in.
|
|
367
|
+
*
|
|
368
|
+
* `systemPrompt` is the selector's instruction scaffold; it defaults to the
|
|
369
|
+
* bundled {@link SYSTEM_PROMPT} and is overridable via `memory.v3.selectorPromptPath`
|
|
370
|
+
* (resolved by {@link resolveSelectorPrompt} at the call site).
|
|
318
371
|
*/
|
|
319
372
|
export async function selectPool(
|
|
320
373
|
pool: SelectorPool,
|
|
321
374
|
turn: MemoryRoutingTurn,
|
|
375
|
+
systemPrompt: string = SYSTEM_PROMPT,
|
|
322
376
|
): Promise<SelectedPage[]> {
|
|
323
377
|
// The concatenated numbering: ids 1…m are the stable-prefix cards, ids
|
|
324
378
|
// m+1… are the finder lines.
|
|
@@ -340,7 +394,7 @@ export async function selectPool(
|
|
|
340
394
|
stableCount: pool.stable.length,
|
|
341
395
|
finderCount: pool.finder.length,
|
|
342
396
|
},
|
|
343
|
-
"pool selector provider unavailable
|
|
397
|
+
"pool selector provider unavailable",
|
|
344
398
|
);
|
|
345
399
|
throw new MemoryV3RetrievalUnavailableError(
|
|
346
400
|
"memory-v3 pool selector provider unavailable",
|
|
@@ -394,6 +448,12 @@ export async function selectPool(
|
|
|
394
448
|
// (no usable tool_use, or tool input that fails the schema) re-prompts before
|
|
395
449
|
// we give up. `null` from an attempt means "unusable, retry"; the provider
|
|
396
450
|
// layer already backs off transient throws, so this loop adds no delay.
|
|
451
|
+
//
|
|
452
|
+
// `lastError` captures the most recent attempt's thrown provider error —
|
|
453
|
+
// `retryForResult` swallows attempt throws, so without this an infrastructure
|
|
454
|
+
// failure (e.g. an upstream HTTP 4xx/5xx) is indistinguishable from a 200 that
|
|
455
|
+
// carried no usable tool_use. It is cleared on every attempt that reaches a
|
|
456
|
+
// response, so it reflects the LAST attempt's failure mode.
|
|
397
457
|
let lastError: unknown = null;
|
|
398
458
|
const parsed = await retryForResult(async () => {
|
|
399
459
|
attempt += 1;
|
|
@@ -401,7 +461,7 @@ export async function selectPool(
|
|
|
401
461
|
try {
|
|
402
462
|
response = await provider.sendMessage([userMsg], {
|
|
403
463
|
tools: [SELECT_PAGES_TOOL],
|
|
404
|
-
systemPrompt
|
|
464
|
+
systemPrompt,
|
|
405
465
|
config: {
|
|
406
466
|
callSite: MEMORY_V3_SELECT_CALL_SITE,
|
|
407
467
|
tool_choice: { type: "tool" as const, name: SELECT_PAGES_TOOL_NAME },
|
|
@@ -476,10 +536,14 @@ export async function selectPool(
|
|
|
476
536
|
providerName: provider.name,
|
|
477
537
|
failures,
|
|
478
538
|
},
|
|
479
|
-
"pool selector provider call failed after retries
|
|
539
|
+
"pool selector provider call failed after retries",
|
|
480
540
|
);
|
|
481
541
|
throw new MemoryV3RetrievalUnavailableError(
|
|
482
542
|
`memory-v3 pool selector provider call failed after retries: ${redactedDetail}`,
|
|
543
|
+
{
|
|
544
|
+
cause: lastError,
|
|
545
|
+
conversationNotice: providerBillingNoticeFromError(lastError),
|
|
546
|
+
},
|
|
483
547
|
);
|
|
484
548
|
}
|
|
485
549
|
log.warn(
|
|
@@ -491,7 +555,7 @@ export async function selectPool(
|
|
|
491
555
|
providerName: provider.name,
|
|
492
556
|
failures,
|
|
493
557
|
},
|
|
494
|
-
"pool selector returned no usable tool_use after retries
|
|
558
|
+
"pool selector returned no usable tool_use after retries",
|
|
495
559
|
);
|
|
496
560
|
throw new MemoryV3RetrievalUnavailableError(
|
|
497
561
|
"memory-v3 pool selector returned no usable selection after retries",
|
|
@@ -56,7 +56,10 @@ import { computeHotSet } from "./hot-set.js";
|
|
|
56
56
|
import { computeLearnedEdgeGraph } from "./learned-edges.js";
|
|
57
57
|
import type { OrchestrateResult } from "./orchestrate.js";
|
|
58
58
|
import { orchestrate } from "./orchestrate.js";
|
|
59
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
MemoryV3RetrievalUnavailableError,
|
|
61
|
+
resolveSelectorPrompt,
|
|
62
|
+
} from "./pool-select.js";
|
|
60
63
|
import { ensureSectionCollection } from "./section-dense-store.js";
|
|
61
64
|
import type { SectionNeedle } from "./section-needle.js";
|
|
62
65
|
import { buildSectionNeedle } from "./section-needle.js";
|
|
@@ -576,6 +579,10 @@ export async function observeTurn(
|
|
|
576
579
|
learnedGraph: lanes.learnedGraph,
|
|
577
580
|
learnedPerSeed: v3.learnedEdges.perSeed,
|
|
578
581
|
learnedCap: v3.learnedEdges.cap,
|
|
582
|
+
selectorPrompt: resolveSelectorPrompt(
|
|
583
|
+
v3.selectorPromptPath,
|
|
584
|
+
getWorkspaceDir(),
|
|
585
|
+
),
|
|
579
586
|
});
|
|
580
587
|
|
|
581
588
|
// A zero-selection turn over a non-trivial pool is unusual enough to be
|
|
@@ -598,13 +605,9 @@ export async function observeTurn(
|
|
|
598
605
|
writeSelections(conversationId, turnIndex, rows);
|
|
599
606
|
return result;
|
|
600
607
|
} catch (err) {
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
// so
|
|
604
|
-
// rather than shipping it with no `<memory>` block. The shadow/observation
|
|
605
|
-
// callers (the injector in shadow mode, runShadowObservation) catch this
|
|
606
|
-
// and swallow it, so observation never fails a turn. Other (non-infra)
|
|
607
|
-
// errors stay non-fatal and degrade to no v3 block, as before.
|
|
608
|
+
// Infrastructure failures are surfaced to callers that want distinct
|
|
609
|
+
// logging from ordinary orchestration misses. Observation callers swallow
|
|
610
|
+
// them so memory-v3 never fails the turn.
|
|
608
611
|
if (err instanceof MemoryV3RetrievalUnavailableError) {
|
|
609
612
|
throw err;
|
|
610
613
|
}
|
|
@@ -634,8 +637,6 @@ export async function runShadowObservation(
|
|
|
634
637
|
try {
|
|
635
638
|
await observeTurn(conversationId, turnIndex);
|
|
636
639
|
} catch {
|
|
637
|
-
// Shadow observation is fire-and-forget and must
|
|
638
|
-
// `observeTurn` now re-throws infra failures so the LIVE injector can
|
|
639
|
-
// hard-fail on them; here (observation only) we swallow them.
|
|
640
|
+
// Shadow observation is fire-and-forget and must never fail a turn.
|
|
640
641
|
}
|
|
641
642
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* the `post-model-call` chain — later hooks see (and may override) its decision.
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
import type {
|
|
48
|
+
import type { HookFunction, PostModelCallContext } from "@vellumai/plugin-api";
|
|
49
49
|
|
|
50
50
|
import type { ContentBlock, Message } from "../../../../providers/types.js";
|
|
51
51
|
import {
|
|
@@ -246,7 +246,7 @@ function hasDanglingProgressSurface(messages: ReadonlyArray<Message>): boolean {
|
|
|
246
246
|
return false;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
const postModelCall:
|
|
249
|
+
const postModelCall: HookFunction<PostModelCallContext> = async (ctx) => {
|
|
250
250
|
// A provider rejection carries no turn content to assess (a recovery hook
|
|
251
251
|
// owns the rejection).
|
|
252
252
|
if (ctx.error) return;
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* refused).
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import type {
|
|
14
|
+
import type { HookFunction, StopContext } from "@vellumai/plugin-api";
|
|
15
15
|
|
|
16
16
|
import { clearSurfaceCompletionNudged } from "../nudge-state-store.js";
|
|
17
17
|
|
|
18
|
-
const stop:
|
|
18
|
+
const stop: HookFunction<StopContext> = async (ctx) => {
|
|
19
19
|
clearSurfaceCompletionNudged(ctx.conversationId);
|
|
20
20
|
};
|
|
21
21
|
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* below it (a new turn restarts counting low).
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
import type {
|
|
48
|
+
import type { HookFunction, PostToolUseContext } from "@vellumai/plugin-api";
|
|
49
49
|
|
|
50
50
|
import type { ContentBlock, Message } from "../../../../providers/types.js";
|
|
51
51
|
import { isWeakOpenModel } from "../../../../providers/weak-open-model.js";
|
|
@@ -134,7 +134,7 @@ function scanTurn(messages: ReadonlyArray<Message>): {
|
|
|
134
134
|
return { rounds, taskProgressShown };
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
const postToolUse:
|
|
137
|
+
const postToolUse: HookFunction<PostToolUseContext> = async (ctx) => {
|
|
138
138
|
if (!isWeakOpenModel(ctx.model)) return;
|
|
139
139
|
|
|
140
140
|
const { rounds, taskProgressShown } = scanTurn(ctx.messages);
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* stateless and means a mid-run array rewrite (compaction) can't invalidate it.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import type {
|
|
21
|
+
import type { HookFunction, StopContext } from "@vellumai/plugin-api";
|
|
22
22
|
|
|
23
23
|
import { getConfig } from "../../../../config/loader.js";
|
|
24
24
|
import { getConversation } from "../../../../memory/conversation-crud.js";
|
|
@@ -65,7 +65,7 @@ function shouldRetryFallbackTitle(conversation: {
|
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const stop:
|
|
68
|
+
const stop: HookFunction<StopContext> = async (ctx) => {
|
|
69
69
|
// Re-title only at a genuine successful turn end (the model returned a reply
|
|
70
70
|
// with no tool calls). Any other terminal — a provider rejection, abort, or
|
|
71
71
|
// an output-limit cutoff — produced no new topic to re-title from.
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type {
|
|
14
|
-
|
|
14
|
+
HookFunction,
|
|
15
15
|
UserPromptSubmitContext,
|
|
16
16
|
} from "@vellumai/plugin-api";
|
|
17
17
|
|
|
18
18
|
import { getConversation } from "../../../../memory/conversation-crud.js";
|
|
19
19
|
import { queueGenerateConversationTitle } from "../../../../memory/conversation-title-service.js";
|
|
20
20
|
|
|
21
|
-
const userPromptSubmit:
|
|
21
|
+
const userPromptSubmit: HookFunction<UserPromptSubmitContext> = async (ctx) => {
|
|
22
22
|
// System conversations (background/scheduled) carry a deterministic title
|
|
23
23
|
// from bootstrap. Their own job prompts arrive as non-interactive turns and
|
|
24
24
|
// must not spend an LLM call on a title nobody reads — only a genuine user
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* result for the tool resets its streak.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import type {
|
|
25
|
+
import type { HookFunction, PostToolUseContext } from "@vellumai/plugin-api";
|
|
26
26
|
|
|
27
27
|
import type { Message } from "../../../../providers/types.js";
|
|
28
28
|
|
|
@@ -85,7 +85,7 @@ function priorConsecutiveErrors(
|
|
|
85
85
|
return streak;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const postToolUse:
|
|
88
|
+
const postToolUse: HookFunction<PostToolUseContext> = async (ctx) => {
|
|
89
89
|
if (ctx.toolResponse.is_error !== true) return;
|
|
90
90
|
|
|
91
91
|
const namesById = toolNamesById(ctx.messages);
|