@vellumai/assistant 0.10.0 → 0.10.1-dev.202606240317.ea25efe
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +36 -37
- package/bun.lock +3 -0
- package/docs/workflows.md +12 -7
- package/eslint-rules/cli-no-daemon-internals.js +12 -0
- package/node_modules/@slack/types/LICENSE +23 -0
- package/node_modules/@slack/types/README.md +32 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
- package/node_modules/@slack/types/dist/calls.d.ts +26 -0
- package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/calls.js +6 -0
- package/node_modules/@slack/types/dist/calls.js.map +1 -0
- package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
- package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/chunk.js +3 -0
- package/node_modules/@slack/types/dist/chunk.js.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
- package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
- package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/dialog.js +3 -0
- package/node_modules/@slack/types/dist/dialog.js.map +1 -0
- package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
- package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/app.js +3 -0
- package/node_modules/@slack/types/dist/events/app.js.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.js +3 -0
- package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
- package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/call.js +3 -0
- package/node_modules/@slack/types/dist/events/call.js.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.js +3 -0
- package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.js +3 -0
- package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
- package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
- package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/email.js +3 -0
- package/node_modules/@slack/types/dist/events/email.js.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.js +3 -0
- package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
- package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/file.js +4 -0
- package/node_modules/@slack/types/dist/events/file.js.map +1 -0
- package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
- package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/function.js +3 -0
- package/node_modules/@slack/types/dist/events/function.js.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
- package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
- package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/group.js +3 -0
- package/node_modules/@slack/types/dist/events/group.js.map +1 -0
- package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
- package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/im.js +3 -0
- package/node_modules/@slack/types/dist/events/im.js.map +1 -0
- package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/index.js +43 -0
- package/node_modules/@slack/types/dist/events/index.js.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.js +3 -0
- package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
- package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
- package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
- package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/member.js +3 -0
- package/node_modules/@slack/types/dist/events/member.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
- package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message.js +3 -0
- package/node_modules/@slack/types/dist/events/message.js.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.js +3 -0
- package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.js +3 -0
- package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
- package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/star.js +3 -0
- package/node_modules/@slack/types/dist/events/star.js.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.js +3 -0
- package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
- package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
- package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/team.js +3 -0
- package/node_modules/@slack/types/dist/events/team.js.map +1 -0
- package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/token.js +3 -0
- package/node_modules/@slack/types/dist/events/token.js.map +1 -0
- package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
- package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/user.js +3 -0
- package/node_modules/@slack/types/dist/events/user.js.map +1 -0
- package/node_modules/@slack/types/dist/index.d.ts +12 -0
- package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/index.js +28 -0
- package/node_modules/@slack/types/dist/index.js.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.js +3 -0
- package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.js +27 -0
- package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/views.d.ts +71 -0
- package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/views.js +3 -0
- package/node_modules/@slack/types/dist/views.js.map +1 -0
- package/node_modules/@slack/types/package.json +47 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -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 +96 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +28 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +95 -0
- package/openapi.yaml +458 -18
- package/package.json +2 -1
- package/scripts/memory-inspect.ts +24 -14
- package/scripts/test.sh +36 -15
- package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
- package/src/__tests__/activation-early-marking.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +39 -17
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
- package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
- package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
- package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/anthropic-provider.test.ts +210 -9
- package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
- package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
- package/src/__tests__/app-source-watcher.test.ts +30 -10
- package/src/__tests__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
- package/src/__tests__/approval-primitive.test.ts +1 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +155 -0
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
- package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
- package/src/__tests__/attachments-store.test.ts +1 -1
- package/src/__tests__/audit-log-rotation.test.ts +50 -54
- package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
- package/src/__tests__/background-shell-bash.test.ts +4 -1
- package/src/__tests__/background-shell-host-bash.test.ts +17 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-controller.test.ts +20 -1
- package/src/__tests__/call-conversation-messages.test.ts +1 -1
- package/src/__tests__/call-domain.test.ts +1 -1
- package/src/__tests__/call-pointer-messages.test.ts +3 -4
- package/src/__tests__/call-recovery.test.ts +1 -1
- package/src/__tests__/call-routes-http.test.ts +1 -1
- package/src/__tests__/call-store.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/canonical-guardian-store.test.ts +24 -1
- package/src/__tests__/card-surface-data.test.ts +60 -0
- package/src/__tests__/channel-approval-routes.test.ts +73 -1119
- package/src/__tests__/channel-delivery-store.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +291 -641
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
- package/src/__tests__/channel-retry-sweep.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +6 -0
- package/src/__tests__/compaction-trail-store.test.ts +6 -5
- package/src/__tests__/compaction.benchmark.test.ts +0 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +188 -52
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
- package/src/__tests__/contact-store-user-file.test.ts +2 -2
- package/src/__tests__/contacts-relay-reads.test.ts +409 -0
- package/src/__tests__/contacts-tools.test.ts +4 -4
- package/src/__tests__/contacts-write.test.ts +1 -2
- package/src/__tests__/context-search-conversations-source.test.ts +1 -1
- package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
- package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -5
- package/src/__tests__/conversation-attention-store.test.ts +1 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
- package/src/__tests__/conversation-clear-safety.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +10 -8
- package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
- package/src/__tests__/conversation-fork-route.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-lifecycle.test.ts +117 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -3
- package/src/__tests__/conversation-process-callsite.test.ts +6 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +95 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +12 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +12 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-starter-routes.test.ts +5 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +4 -4
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +352 -0
- package/src/__tests__/conversation-sync-tags.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-wipe.test.ts +9 -8
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +2 -2
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
- package/src/__tests__/db-migration-rollback.test.ts +129 -39
- package/src/__tests__/db-proxy-transaction.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
- package/src/__tests__/db-test-helpers.ts +36 -19
- package/src/__tests__/delete-propagation.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +28 -8
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/disk-pressure-tools.test.ts +41 -1
- package/src/__tests__/dm-backfill.test.ts +1 -1
- package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
- package/src/__tests__/dynamic-page-surface.test.ts +0 -94
- package/src/__tests__/edit-propagation.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +93 -5
- package/src/__tests__/empty-response-hook.test.ts +42 -0
- package/src/__tests__/events-client-registration.test.ts +1 -1
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gemini-count-tokens.test.ts +70 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +76 -11
- package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +96 -2
- package/src/__tests__/guardian-outbound-http.test.ts +20 -12
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +1 -2
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +2 -2
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +6 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +92 -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-conversation-lineage.test.ts +1 -1
- package/src/__tests__/http-user-message-parity.test.ts +165 -8
- package/src/__tests__/image-recovery-hook.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
- package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
- package/src/__tests__/inference-profile-reaper.test.ts +1 -1
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +11 -6
- package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +244 -43
- package/src/__tests__/invite-routes-http.test.ts +35 -186
- package/src/__tests__/invite-service-ipc.test.ts +287 -0
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
- package/src/__tests__/list-messages-attachments.test.ts +42 -1
- package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
- package/src/__tests__/list-messages-page-latest.test.ts +1 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-context-route-provider.test.ts +69 -4
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
- package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
- package/src/__tests__/llm-resolver.test.ts +205 -5
- package/src/__tests__/llm-usage-store.test.ts +65 -1
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
- package/src/__tests__/memory-recall-log-store.test.ts +1 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
- package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +375 -0
- package/src/__tests__/non-member-access-request.test.ts +190 -19
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +4 -0
- package/src/__tests__/notification-guardian-path.test.ts +20 -1
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +1 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
- package/src/__tests__/persist-unsendable-image.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +39 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
- package/src/__tests__/plugin-bootstrap.test.ts +78 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
- package/src/__tests__/provider-usage-tracking.test.ts +40 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +1026 -73
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -1
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-retry.test.ts +1 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +1 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
- package/src/__tests__/scheduler-wake.test.ts +2 -1
- package/src/__tests__/scoped-approval-grants.test.ts +1 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
- package/src/__tests__/secret-ingress-http.test.ts +12 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +31 -9
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +40 -1
- package/src/__tests__/settings-routes.test.ts +11 -10
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +48 -5
- package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
- package/src/__tests__/subagent-tools.test.ts +1 -31
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
- package/src/__tests__/task-compiler.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-memory-cleanup.test.ts +9 -6
- package/src/__tests__/task-scheduler.test.ts +1 -1
- package/src/__tests__/thread-backfill.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +37 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
- package/src/__tests__/turn-events-store.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +98 -3
- package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
- package/src/__tests__/usage-routes.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +34 -29
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/voice-invite-redemption.test.ts +134 -36
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-git-service.test.ts +114 -1
- package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
- package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
- package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
- package/src/__tests__/workspace-tool-loader.test.ts +3 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
- package/src/a2a/__tests__/task-store.test.ts +1 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
- package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
- package/src/acp/__tests__/session-manager.test.ts +72 -1
- package/src/acp/index.ts +10 -0
- package/src/acp/session-manager.ts +35 -0
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +101 -27
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/ui-surface-show.ts +8 -3
- package/src/api/index.ts +7 -6
- package/src/api/responses/conversation-message.ts +4 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +33 -0
- package/src/approvals/AGENTS.md +1 -2
- package/src/approvals/guardian-decision-primitive.ts +13 -210
- package/src/approvals/guardian-request-resolvers.ts +104 -58
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +349 -65
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +56 -0
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +231 -72
- package/src/calls/relay-setup-router.ts +57 -13
- package/src/calls/relay-verification.ts +7 -7
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +13 -3
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +6 -24
- package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
- package/src/cli/commands/db/__tests__/status.test.ts +7 -3
- package/src/cli/commands/db/status.ts +212 -33
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +4 -0
- package/src/cli/commands/memory/memory-retrospective.ts +129 -0
- package/src/cli/commands/memory/memory-v3.ts +176 -4
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +343 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
- package/src/cli/lib/install-from-github.ts +47 -6
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -0
- package/src/cli/lib/toggle-plugin.ts +146 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
- package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
- package/src/config/bundled-skills/contacts/SKILL.md +7 -12
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
- package/src/config/bundled-skills/workflows/SKILL.md +4 -3
- package/src/config/call-site-defaults.ts +11 -2
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/llm-resolver.ts +151 -14
- package/src/config/loader.ts +36 -5
- package/src/config/profile-dispatchability.ts +11 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +17 -3
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +32 -0
- package/src/config/seed-inference-profiles.ts +147 -50
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +13 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contact-store.ts +21 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-status.ts +9 -0
- package/src/credential-health/credential-health-service.ts +1 -5
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
- package/src/daemon/app-source-watcher.ts +31 -18
- package/src/daemon/assistant-attachments.ts +94 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
- package/src/daemon/conversation-agent-loop.ts +18 -36
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-runtime-assembly.ts +91 -66
- package/src/daemon/conversation-surfaces.ts +273 -18
- package/src/daemon/conversation-tool-setup.ts +24 -64
- package/src/daemon/conversation.ts +149 -53
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.test.ts +85 -0
- package/src/daemon/event-loop-watchdog.ts +133 -0
- package/src/daemon/external-plugins-bootstrap.ts +26 -80
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
- package/src/daemon/handlers/config-channels.ts +41 -27
- package/src/daemon/handlers/conversations.ts +84 -0
- package/src/daemon/handlers/shared.ts +7 -0
- package/src/daemon/lifecycle.ts +44 -5
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/inbox.ts +0 -6
- package/src/daemon/message-types/messages.ts +0 -4
- package/src/daemon/message-types/surfaces.ts +12 -11
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +7 -5
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +70 -0
- package/src/daemon/workspace-tools-watcher.ts +7 -3
- package/src/documents/document-comments-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
- package/src/heartbeat/heartbeat-service.ts +3 -4
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
- package/src/ipc/assistant-server.ts +10 -2
- package/src/ipc/gateway-client.ts +2 -1
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
- package/src/ipc/routes/invite-ipc-routes.ts +66 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
- package/src/memory/__tests__/activation-session-store.test.ts +1 -1
- package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
- package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
- package/src/memory/__tests__/conversation-queries.test.ts +1 -1
- package/src/memory/__tests__/db-async-query.test.ts +1 -1
- package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
- package/src/memory/__tests__/db-maintenance.test.ts +28 -36
- package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
- package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
- package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
- package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
- package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/table-relocation.test.ts +129 -0
- package/src/memory/conversation-crud.ts +461 -152
- package/src/memory/db-async-query.ts +89 -5
- package/src/memory/db-connection.ts +101 -18
- package/src/memory/db-init.ts +409 -234
- package/src/memory/db-maintenance.ts +43 -38
- package/src/memory/db-singleton.ts +45 -19
- package/src/memory/embedding-gemini.test.ts +3 -1
- package/src/memory/embedding-gemini.ts +18 -2
- package/src/memory/fork-message-copy.ts +170 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
- package/src/memory/graph/bootstrap.test.ts +6 -3
- package/src/memory/graph/retriever.test.ts +12 -12
- package/src/memory/graph/store.test.ts +15 -25
- package/src/memory/graph/store.ts +23 -14
- package/src/memory/graph/tool-handlers.ts +34 -5
- package/src/memory/graph/tools.ts +5 -2
- package/src/memory/indexer.ts +21 -9
- package/src/memory/job-handlers/cleanup.ts +10 -3
- package/src/memory/job-handlers/embedding.test.ts +4 -4
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
- package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
- package/src/memory/jobs-store.ts +36 -24
- package/src/memory/llm-request-log-store.ts +51 -19
- package/src/memory/llm-usage-store.ts +79 -21
- package/src/memory/memory-retrospective-job.ts +27 -19
- package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
- package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/104-core-indexes.ts +1 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
- package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +241 -219
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
- package/src/memory/migrations/141-rename-verification-table.ts +45 -48
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
- package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
- package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
- package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
- package/src/memory/migrations/157-invite-contact-id.ts +73 -76
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
- package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
- package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
- package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
- package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
- package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
- package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +135 -68
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
- package/src/memory/migrations/217-conversation-host-access.ts +13 -18
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
- package/src/memory/migrations/230-acp-session-history.ts +23 -28
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
- package/src/memory/migrations/232-activation-state.ts +11 -16
- package/src/memory/migrations/233-document-conversations.ts +20 -25
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
- package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
- package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
- package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
- package/src/memory/migrations/242-message-bookmarks.ts +17 -22
- package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
- package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
- package/src/memory/migrations/251-a2a-tasks.ts +27 -32
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
- package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
- package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
- package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
- package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
- package/src/memory/migrations/270-schedule-description.ts +7 -12
- package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
- package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
- package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
- package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
- package/src/memory/migrations/helpers/relocation.ts +227 -0
- package/src/memory/migrations/registry.ts +63 -0
- package/src/memory/migrations/run-migrations.ts +187 -16
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +50 -145
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/raw-query.ts +47 -2
- package/src/memory/skill-loaded-events-store.test.ts +1 -1
- package/src/memory/task-memory-cleanup.ts +62 -41
- package/src/memory/tool-executed-events-store.test.ts +1 -1
- package/src/memory/turn-trace-store.test.ts +1 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
- 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/v3-eval/__tests__/eval-packets.test.ts +38 -0
- package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
- package/src/memory/v3-eval/eval-packets.ts +197 -12
- package/src/memory/v3-eval/eval-tally.ts +234 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/messaging/provider.ts +10 -0
- package/src/messaging/providers/gmail/adapter.ts +1 -0
- package/src/messaging/providers/gmail/client.ts +13 -0
- package/src/messaging/providers/index.ts +1 -1
- package/src/messaging/providers/slack/send.test.ts +87 -39
- package/src/messaging/providers/slack/send.ts +84 -105
- package/src/notifications/README.md +9 -5
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
- package/src/notifications/adapters/slack.ts +12 -10
- package/src/notifications/approval-card-builder.ts +81 -20
- package/src/notifications/approval-card-data.ts +8 -5
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/canonical-delivery-recorder.ts +7 -5
- package/src/notifications/conversation-candidates.ts +24 -59
- package/src/notifications/copy-composer.ts +48 -68
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/deterministic-checks.ts +19 -16
- package/src/notifications/emit-signal.ts +68 -15
- package/src/notifications/trusted-contact-payloads.ts +70 -0
- package/src/oauth/byo-connection.test.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +174 -6
- package/src/oauth/connection-resolver.ts +132 -5
- package/src/oauth/oauth-store.ts +16 -3
- package/src/oauth/scope-utils.ts +39 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +9 -4
- package/src/plugin-api/model-profiles.test.ts +123 -0
- package/src/plugin-api/model-profiles.ts +5 -1
- package/src/plugin-api/vision-support.test.ts +173 -0
- package/src/plugin-api/vision-support.ts +113 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +90 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +65 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/compaction/window-manager.ts +45 -64
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +441 -0
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +57 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +61 -0
- package/src/plugins/defaults/image-fallback/package.json +14 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +108 -0
- package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
- package/src/plugins/defaults/image-fallback/src/image-persist.ts +56 -0
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
- package/src/plugins/defaults/index.ts +27 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
- package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +134 -5
- 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 +246 -19
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/external-plugin-loader.ts +47 -6
- package/src/plugins/mtime-cache.ts +772 -0
- package/src/plugins/pipeline.ts +7 -2
- package/src/plugins/registry.ts +16 -5
- package/src/plugins/user-loader.ts +22 -76
- package/src/prompts/persona-resolver.ts +29 -11
- package/src/prompts/system-prompt.ts +1 -1
- package/src/prompts/templates/system-sections.ts +4 -4
- package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
- package/src/providers/anthropic/client.ts +290 -185
- package/src/providers/call-site-routing.ts +14 -0
- package/src/providers/gemini/client.ts +43 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +6 -1
- package/src/providers/model-catalog.ts +53 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +13 -0
- package/src/providers/retry.ts +14 -0
- package/src/providers/together/client.ts +35 -0
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +11 -0
- package/src/runtime/AGENTS.md +9 -1
- package/src/runtime/__tests__/agent-wake.test.ts +259 -4
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +64 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +670 -0
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +8 -16
- package/src/runtime/agent-wake.ts +183 -60
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- 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-reply-delivery.ts +6 -3
- package/src/runtime/channel-verification-service.ts +24 -0
- package/src/runtime/guardian-decision-types.ts +3 -22
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/http-server.ts +1 -15
- package/src/runtime/invite-redemption-service.ts +155 -6
- package/src/runtime/invite-service.ts +113 -62
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +163 -0
- package/src/runtime/routes/acp-routes-list.test.ts +4 -0
- package/src/runtime/routes/acp-routes.test.ts +5 -6
- package/src/runtime/routes/attachment-routes.ts +21 -17
- package/src/runtime/routes/browser-routes.ts +19 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
- package/src/runtime/routes/channel-verification-routes.ts +13 -2
- package/src/runtime/routes/contact-routes.ts +275 -164
- package/src/runtime/routes/conversation-query-routes.ts +15 -5
- package/src/runtime/routes/conversation-routes.ts +80 -66
- package/src/runtime/routes/conversation-starter-routes.ts +7 -8
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/guardian-approval-interception.ts +13 -274
- 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 +1 -1
- package/src/runtime/routes/inbound-message-handler.ts +21 -16
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +376 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +86 -64
- package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- 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/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/log-export-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/memory-eval-routes.ts +92 -0
- package/src/runtime/routes/memory-item-routes.test.ts +12 -11
- package/src/runtime/routes/migration-routes.ts +51 -40
- package/src/runtime/routes/plugins-routes.ts +164 -8
- package/src/runtime/routes/schedule-routes.ts +1 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +39 -51
- package/src/runtime/routes/usage-routes.ts +3 -0
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/slack-block-formatting.ts +46 -48
- package/src/runtime/trust-verdict-consumer.ts +210 -0
- package/src/schedule/scheduler.ts +6 -9
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +89 -52
- package/src/tools/ask-question/ask-question-tool.ts +27 -73
- package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
- package/src/tools/browser/browser-execution.ts +16 -4
- package/src/tools/document/document-comment-tool.test.ts +1 -1
- package/src/tools/executor.ts +15 -3
- package/src/tools/host-terminal/host-shell.ts +28 -9
- package/src/tools/memory/register.test.ts +32 -0
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +4 -10
- package/src/tools/terminal/shell.ts +16 -5
- package/src/tools/tool-defaults.ts +2 -0
- package/src/tools/types.ts +18 -2
- package/src/tools/ui-surface/definitions.ts +0 -43
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/log-redact.ts +2 -4
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/memory-db-path.ts +23 -0
- package/src/util/platform.ts +5 -0
- package/src/watcher/providers/gmail.ts +7 -2
- package/src/workflows/engine-integration.test.ts +1 -1
- package/src/workflows/engine.test.ts +1 -1
- package/src/workflows/engine.ts +22 -0
- package/src/workflows/fanout-load.test.ts +1 -1
- package/src/workflows/journal-store.test.ts +1 -1
- package/src/workflows/leaf-runner.test.ts +40 -1
- package/src/workflows/leaf-runner.ts +26 -1
- package/src/workspace/git-service.ts +144 -29
- package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
- package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/migrations/runner.ts +32 -2
- package/src/__tests__/access-request-decision.test.ts +0 -375
- package/src/__tests__/guardian-grant-minting.test.ts +0 -607
- package/src/__tests__/plugin-source-watcher.test.ts +0 -302
- package/src/api/events/turn-profile-auto-routed.ts +0 -28
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
- package/src/daemon/plugin-source-watcher.ts +0 -278
- package/src/daemon/switch-inference-profile-tool.ts +0 -62
- package/src/memory/guardian-approvals.ts +0 -361
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
- package/src/memory/migrations/038-actor-token-records.ts +0 -45
- package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
- package/src/memory/migrations/103-complex-migrations.ts +0 -23
- package/src/memory/migrations/113-late-migrations.ts +0 -30
- package/src/memory/migrations/index.ts +0 -301
- package/src/runtime/routes/access-request-decision.ts +0 -297
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
- package/src/runtime/routes/channel-guardian-routes.ts +0 -19
- package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared image→text substitution for the image-fallback plugin's hooks.
|
|
3
|
+
*
|
|
4
|
+
* Two hooks replace `image` content blocks with a text caption when the turn's
|
|
5
|
+
* model can't process images: `user-prompt-submit` handles user-attached
|
|
6
|
+
* images, and `post-tool-use` handles images a tool returns (e.g. a browser
|
|
7
|
+
* screenshot). This module holds what they share — deciding whether a profile
|
|
8
|
+
* needs the fallback ({@link needsImageFallback}) and the per-block
|
|
9
|
+
* substitution ({@link captionImageBlocks}): persist the original image to a
|
|
10
|
+
* known location, caption it via a vision-capable profile, and swap in a
|
|
11
|
+
* `[Image …]` text block.
|
|
12
|
+
*
|
|
13
|
+
* The substitution mutates the blocks in place, so the caption replaces the
|
|
14
|
+
* image everywhere the block is referenced (the provider-bound history and the
|
|
15
|
+
* persisted/displayed copy alike) — a text-only turn does not keep the raw
|
|
16
|
+
* image around.
|
|
17
|
+
*
|
|
18
|
+
* The caption text states up front that the model can't view images and the
|
|
19
|
+
* image was auto-described to text, so the model treats the block as a derived
|
|
20
|
+
* description rather than a verbatim transcript.
|
|
21
|
+
*
|
|
22
|
+
* Fail-open is the dominant error mode: a captioning failure leaves a
|
|
23
|
+
* placeholder text block rather than the raw image (which a text-only provider
|
|
24
|
+
* would reject) or nothing (which would lose information).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
type ContentBlock,
|
|
29
|
+
doesSupportVision,
|
|
30
|
+
getModelProfiles,
|
|
31
|
+
type ImageContent,
|
|
32
|
+
type PluginLogger,
|
|
33
|
+
} from "@vellumai/plugin-api";
|
|
34
|
+
|
|
35
|
+
import { persistImage } from "./image-persist.js";
|
|
36
|
+
import { captionImage } from "./vision-caption.js";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether the profile a turn runs needs image→text fallback (i.e. it can't
|
|
40
|
+
* process images itself).
|
|
41
|
+
*
|
|
42
|
+
* Used by `user-prompt-submit`, whose context carries the profile key rather
|
|
43
|
+
* than the resolved model id: prefer the turn's `modelProfileKey` — which
|
|
44
|
+
* carries a text-only override even when the workspace's active profile is
|
|
45
|
+
* vision-capable — and fall back to the active profile only when the key is
|
|
46
|
+
* `null` (profile unchanged since the last notified turn). Returns `false` when
|
|
47
|
+
* no profile resolves or the resolved model already supports vision, in which
|
|
48
|
+
* case the image reaches the model untouched.
|
|
49
|
+
*/
|
|
50
|
+
export function needsImageFallback(modelProfileKey: string | null): boolean {
|
|
51
|
+
const profiles = getModelProfiles();
|
|
52
|
+
const activeProfile =
|
|
53
|
+
modelProfileKey != null
|
|
54
|
+
? profiles.find((p) => p.key === modelProfileKey)
|
|
55
|
+
: profiles.find((p) => p.isActive);
|
|
56
|
+
if (activeProfile == null) return false;
|
|
57
|
+
return !doesSupportVision(activeProfile);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Replace every `image` block in `blocks` (in place) with a text caption so a
|
|
62
|
+
* text-only model can still reason about the image's content. Returns the
|
|
63
|
+
* number of image blocks replaced.
|
|
64
|
+
*
|
|
65
|
+
* @param blocks Content-block array to scan and mutate in place.
|
|
66
|
+
* @param visionProfileKey Key of a vision-capable profile for captioning, or
|
|
67
|
+
* `null` when none is configured (fail-open
|
|
68
|
+
* placeholder).
|
|
69
|
+
* @param logger Turn-scoped logger for attribution.
|
|
70
|
+
*/
|
|
71
|
+
export async function captionImageBlocks(
|
|
72
|
+
blocks: ContentBlock[],
|
|
73
|
+
visionProfileKey: string | null,
|
|
74
|
+
logger: PluginLogger,
|
|
75
|
+
): Promise<number> {
|
|
76
|
+
let imageCount = 0;
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
79
|
+
const block = blocks[i];
|
|
80
|
+
if (block.type !== "image") continue;
|
|
81
|
+
|
|
82
|
+
imageCount++;
|
|
83
|
+
const image = block as ImageContent;
|
|
84
|
+
|
|
85
|
+
// Persist the original to a known, content-hash-deduped location so it
|
|
86
|
+
// survives the text substitution and stays findable on disk.
|
|
87
|
+
persistImage(image.source.data, image.source.media_type);
|
|
88
|
+
|
|
89
|
+
if (visionProfileKey != null) {
|
|
90
|
+
const caption = await captionImage(image, visionProfileKey, logger);
|
|
91
|
+
blocks[i] = {
|
|
92
|
+
type: "text",
|
|
93
|
+
text:
|
|
94
|
+
caption != null
|
|
95
|
+
? `[Image auto-described for text-only model: ${caption}]`
|
|
96
|
+
: `[Image: auto-description failed (text-only model)]`,
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
// No vision profile configured at all — fail-open placeholder.
|
|
100
|
+
blocks[i] = {
|
|
101
|
+
type: "text",
|
|
102
|
+
text: `[Image: no vision-capable model configured to describe it]`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return imageCount;
|
|
108
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory LRU cache for image captions, keyed by the sha-256 hash of the
|
|
3
|
+
* image's base64 data.
|
|
4
|
+
*
|
|
5
|
+
* The cache survives across turns within a session, which is the primary
|
|
6
|
+
* correctness concern: without it, the same image would be re-captioned
|
|
7
|
+
* (and re-billed) on every turn because `user-prompt-submit` rebuilds
|
|
8
|
+
* `latestMessages` from the stored conversation each time. Re-captioning
|
|
9
|
+
* on a daemon restart is acceptable — captions are cheap and the image
|
|
10
|
+
* is still in the history.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
|
|
15
|
+
const MAX_ENTRIES = 500;
|
|
16
|
+
|
|
17
|
+
const cache = new Map<string, string>();
|
|
18
|
+
|
|
19
|
+
/** sha-256 hex digest of an image's base64 payload. */
|
|
20
|
+
export function imageHash(data: string): string {
|
|
21
|
+
return createHash("sha256").update(data).digest("hex");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Look up a cached caption. `undefined` = miss; a string (even empty) = hit. */
|
|
25
|
+
export function getCachedCaption(hash: string): string | undefined {
|
|
26
|
+
const value = cache.get(hash);
|
|
27
|
+
if (value !== undefined) {
|
|
28
|
+
// Move to end (most-recently-used) for LRU eviction.
|
|
29
|
+
cache.delete(hash);
|
|
30
|
+
cache.set(hash, value);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Store a caption, evicting the least-recently-used entry if at capacity. */
|
|
36
|
+
export function setCachedCaption(hash: string, caption: string): void {
|
|
37
|
+
if (cache.size >= MAX_ENTRIES) {
|
|
38
|
+
const oldest = cache.keys().next();
|
|
39
|
+
if (!oldest.done) {
|
|
40
|
+
cache.delete(oldest.value as string);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
cache.set(hash, caption);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Test-only: clear the cache. */
|
|
47
|
+
export function resetCaptionCacheForTests(): void {
|
|
48
|
+
cache.clear();
|
|
49
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persist image data to the workspace attachments directory.
|
|
3
|
+
*
|
|
4
|
+
* When the active model is text-only, the image-fallback plugin captions the
|
|
5
|
+
* image and substitutes a text block. Saving the raw image to a known,
|
|
6
|
+
* content-hash-deduped location means the original survives the text
|
|
7
|
+
* substitution and stays findable on disk for the user (or a subagent with a
|
|
8
|
+
* vision-capable model that reads it via file_read).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import { imageHash } from "./caption-cache.js";
|
|
15
|
+
|
|
16
|
+
/** The workspace attachments directory. */
|
|
17
|
+
const ATTACHMENTS_DIR = "/workspace/data/attachments";
|
|
18
|
+
|
|
19
|
+
/** File extension for a given media type, falling back to `.bin`. */
|
|
20
|
+
function extensionForMediaType(mediaType: string): string {
|
|
21
|
+
switch (mediaType) {
|
|
22
|
+
case "image/png":
|
|
23
|
+
return ".png";
|
|
24
|
+
case "image/jpeg":
|
|
25
|
+
return ".jpg";
|
|
26
|
+
case "image/gif":
|
|
27
|
+
return ".gif";
|
|
28
|
+
case "image/webp":
|
|
29
|
+
return ".webp";
|
|
30
|
+
default:
|
|
31
|
+
return ".bin";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Save an image's base64 data to the attachments dir if not already present.
|
|
37
|
+
* Returns the absolute file path, or `null` when the write fails.
|
|
38
|
+
*/
|
|
39
|
+
export function persistImage(data: string, mediaType: string): string | null {
|
|
40
|
+
try {
|
|
41
|
+
mkdirSync(ATTACHMENTS_DIR, { recursive: true });
|
|
42
|
+
|
|
43
|
+
const hash = imageHash(data);
|
|
44
|
+
const ext = extensionForMediaType(mediaType);
|
|
45
|
+
const filename = `${hash}${ext}`;
|
|
46
|
+
const filepath = join(ATTACHMENTS_DIR, filename);
|
|
47
|
+
|
|
48
|
+
// Skip if already saved (content-hash dedup).
|
|
49
|
+
if (existsSync(filepath)) return filepath;
|
|
50
|
+
|
|
51
|
+
writeFileSync(filepath, Buffer.from(data, "base64"));
|
|
52
|
+
return filepath;
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vision-based image captioning for the image-fallback plugin.
|
|
3
|
+
*
|
|
4
|
+
* When the active model cannot process images, this module finds a
|
|
5
|
+
* vision-capable profile in the workspace's configured profiles and runs a
|
|
6
|
+
* one-shot captioning call through the assistant's own inference (no
|
|
7
|
+
* plugin-supplied API key). The caption replaces the image block in the
|
|
8
|
+
* outgoing message history.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
doesSupportVision,
|
|
13
|
+
getConfiguredProvider,
|
|
14
|
+
getModelProfiles,
|
|
15
|
+
type ImageContent,
|
|
16
|
+
type PluginLogger,
|
|
17
|
+
} from "@vellumai/plugin-api";
|
|
18
|
+
|
|
19
|
+
import { extractAllText } from "../../../../providers/provider-send-message.js";
|
|
20
|
+
import {
|
|
21
|
+
getCachedCaption,
|
|
22
|
+
imageHash,
|
|
23
|
+
setCachedCaption,
|
|
24
|
+
} from "./caption-cache.js";
|
|
25
|
+
|
|
26
|
+
const CAPTION_TIMEOUT_MS = 30_000;
|
|
27
|
+
|
|
28
|
+
const CAPTION_SYSTEM_PROMPT =
|
|
29
|
+
"You are a vision assistant. Describe the image concisely in 1-2 sentences. " +
|
|
30
|
+
"Focus on the key visual content, text, charts, or UI elements that would be " +
|
|
31
|
+
"relevant for a text-based assistant to understand and reason about.";
|
|
32
|
+
|
|
33
|
+
const CAPTION_USER_PROMPT = "Describe this image concisely for a text-only assistant.";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Find a vision-capable, enabled profile key for captioning.
|
|
37
|
+
*
|
|
38
|
+
* Scans the workspace's profiles in `getModelProfiles()` order (the same order
|
|
39
|
+
* the `/model` picker shows them) and returns the first enabled profile whose
|
|
40
|
+
* resolved model supports vision. Returns `null` when no vision profile exists
|
|
41
|
+
* — the hook fails-open in that case, leaving a placeholder text block.
|
|
42
|
+
*/
|
|
43
|
+
export function findVisionProfile(): string | null {
|
|
44
|
+
for (const profile of getModelProfiles()) {
|
|
45
|
+
if (profile.isDisabled) continue;
|
|
46
|
+
if (doesSupportVision(profile)) {
|
|
47
|
+
return profile.key;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Caption a single image block via a vision-capable profile.
|
|
55
|
+
*
|
|
56
|
+
* @param image The image content block to caption.
|
|
57
|
+
* @param profileKey Key of a vision-capable profile (from {@link findVisionProfile}).
|
|
58
|
+
* @param logger Turn-scoped logger for attribution.
|
|
59
|
+
* @returns The caption text, or `null` when captioning failed (caller should
|
|
60
|
+
* use a fail-open placeholder).
|
|
61
|
+
*/
|
|
62
|
+
export async function captionImage(
|
|
63
|
+
image: ImageContent,
|
|
64
|
+
profileKey: string,
|
|
65
|
+
logger: PluginLogger,
|
|
66
|
+
): Promise<string | null> {
|
|
67
|
+
const hash = imageHash(image.source.data);
|
|
68
|
+
const cached = getCachedCaption(hash);
|
|
69
|
+
if (cached !== undefined) {
|
|
70
|
+
return cached;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const provider = await getConfiguredProvider("vision", {
|
|
75
|
+
overrideProfile: profileKey,
|
|
76
|
+
forceOverrideProfile: true,
|
|
77
|
+
});
|
|
78
|
+
if (!provider) {
|
|
79
|
+
logger.warn(
|
|
80
|
+
{ plugin: "image-fallback" },
|
|
81
|
+
"No provider resolved for vision captioning profile",
|
|
82
|
+
);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const response = await provider.sendMessage(
|
|
87
|
+
[
|
|
88
|
+
{
|
|
89
|
+
role: "user",
|
|
90
|
+
content: [image, { type: "text", text: CAPTION_USER_PROMPT }],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
{
|
|
94
|
+
systemPrompt: CAPTION_SYSTEM_PROMPT,
|
|
95
|
+
config: {
|
|
96
|
+
callSite: "vision",
|
|
97
|
+
overrideProfile: profileKey,
|
|
98
|
+
forceOverrideProfile: true,
|
|
99
|
+
tool_choice: { type: "none" },
|
|
100
|
+
},
|
|
101
|
+
signal: AbortSignal.timeout(CAPTION_TIMEOUT_MS),
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const caption = extractAllText(response).trim();
|
|
106
|
+
if (caption.length > 0) {
|
|
107
|
+
setCachedCaption(hash, caption);
|
|
108
|
+
return caption;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
logger.warn({ plugin: "image-fallback" }, "Vision captioning returned empty text");
|
|
112
|
+
return null;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.warn(
|
|
115
|
+
{ plugin: "image-fallback", err },
|
|
116
|
+
"Vision captioning call failed",
|
|
117
|
+
);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -47,6 +47,10 @@ import historyRepairStop from "./history-repair/hooks/stop.js";
|
|
|
47
47
|
import historyRepairUserPromptSubmit from "./history-repair/hooks/user-prompt-submit.js";
|
|
48
48
|
import historyRepairPkg from "./history-repair/package.json" with { type: "json" };
|
|
49
49
|
import { resetRepairStateStoreForTests } from "./history-repair/repair-state-store.js";
|
|
50
|
+
import imageFallbackPostToolUse from "./image-fallback/hooks/post-tool-use.js";
|
|
51
|
+
import imageFallbackUserPromptSubmit from "./image-fallback/hooks/user-prompt-submit.js";
|
|
52
|
+
import imageFallbackPkg from "./image-fallback/package.json" with { type: "json" };
|
|
53
|
+
import { resetCaptionCacheForTests } from "./image-fallback/src/caption-cache.js";
|
|
50
54
|
import imageRecoveryPostModelCall from "./image-recovery/hooks/post-model-call.js";
|
|
51
55
|
import imageRecoveryStop from "./image-recovery/hooks/stop.js";
|
|
52
56
|
import { resetImageRecoveryStoreForTests } from "./image-recovery/image-recovery-state-store.js";
|
|
@@ -77,6 +81,27 @@ import toolErrorPkg from "./tool-error/package.json" with { type: "json" };
|
|
|
77
81
|
import toolResultTruncatePostToolUse from "./tool-result-truncate/hooks/post-tool-use.js";
|
|
78
82
|
import toolResultTruncatePkg from "./tool-result-truncate/package.json" with { type: "json" };
|
|
79
83
|
|
|
84
|
+
/**
|
|
85
|
+
* `image-fallback` — captions image blocks via a vision-capable profile when
|
|
86
|
+
* the active model is text-only, substituting the caption as an `[Image …]`
|
|
87
|
+
* text block so the model can still reason about the image's content. The
|
|
88
|
+
* `user-prompt-submit` hook handles user-attached images; the `post-tool-use`
|
|
89
|
+
* hook handles images a tool returns (e.g. a browser screenshot) nested in the
|
|
90
|
+
* tool result's `contentBlocks`. Fail-open with a placeholder when no vision
|
|
91
|
+
* profile is configured or captioning fails. An in-memory content-hash cache
|
|
92
|
+
* avoids re-captioning the same image across turns.
|
|
93
|
+
*/
|
|
94
|
+
export const defaultImageFallbackPlugin: Plugin = {
|
|
95
|
+
manifest: {
|
|
96
|
+
name: imageFallbackPkg.name,
|
|
97
|
+
version: imageFallbackPkg.version,
|
|
98
|
+
},
|
|
99
|
+
hooks: {
|
|
100
|
+
"user-prompt-submit": imageFallbackUserPromptSubmit,
|
|
101
|
+
"post-tool-use": imageFallbackPostToolUse,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
80
105
|
/**
|
|
81
106
|
* `compaction` — compaction is implemented in `compaction/compact.ts` as
|
|
82
107
|
* `defaultCompact`, which the agent loop calls directly. The plugin stays
|
|
@@ -337,6 +362,7 @@ export const defaultAdvisorPlugin: Plugin = {
|
|
|
337
362
|
function getAllDefaultPlugins(): readonly Plugin[] {
|
|
338
363
|
return [
|
|
339
364
|
defaultMemoryRetrievalPlugin,
|
|
365
|
+
defaultImageFallbackPlugin,
|
|
340
366
|
defaultToolResultTruncatePlugin,
|
|
341
367
|
defaultEmptyResponsePlugin,
|
|
342
368
|
defaultMaxTokensContinuePlugin,
|
|
@@ -399,5 +425,6 @@ export function resetPluginRegistryAndRegisterDefaults(): void {
|
|
|
399
425
|
resetTaskProgressNudgeStateForTests();
|
|
400
426
|
resetSurfaceCompletionNudgeStoreForTests();
|
|
401
427
|
resetAdvisorStateForTests();
|
|
428
|
+
resetCaptionCacheForTests();
|
|
402
429
|
registerDefaultPlugins();
|
|
403
430
|
}
|
|
@@ -194,6 +194,9 @@ function persistInjectionBlocks(
|
|
|
194
194
|
!blocks.pkbContextBlock &&
|
|
195
195
|
!blocks.memoryV2StaticBlock &&
|
|
196
196
|
!blocks.memoryV3InjectedBlock &&
|
|
197
|
+
!blocks.backgroundTurnBlock &&
|
|
198
|
+
!blocks.channelCapabilitiesBlock &&
|
|
199
|
+
!blocks.nonInteractiveContextBlock &&
|
|
197
200
|
!removeV2Block
|
|
198
201
|
) {
|
|
199
202
|
return;
|
|
@@ -229,6 +232,17 @@ function persistInjectionBlocks(
|
|
|
229
232
|
if (blocks.memoryV2StaticBlock) {
|
|
230
233
|
metadataUpdates.memoryV2StaticBlock = blocks.memoryV2StaticBlock;
|
|
231
234
|
}
|
|
235
|
+
if (blocks.backgroundTurnBlock) {
|
|
236
|
+
metadataUpdates.backgroundTurnBlock = blocks.backgroundTurnBlock;
|
|
237
|
+
}
|
|
238
|
+
if (blocks.channelCapabilitiesBlock) {
|
|
239
|
+
metadataUpdates.channelCapabilitiesBlock =
|
|
240
|
+
blocks.channelCapabilitiesBlock;
|
|
241
|
+
}
|
|
242
|
+
if (blocks.nonInteractiveContextBlock) {
|
|
243
|
+
metadataUpdates.nonInteractiveContextBlock =
|
|
244
|
+
blocks.nonInteractiveContextBlock;
|
|
245
|
+
}
|
|
232
246
|
updateMessageMetadata(ctx.userMessageId, metadataUpdates);
|
|
233
247
|
} catch (err) {
|
|
234
248
|
ctx.logger.warn(
|
|
@@ -264,7 +278,6 @@ const userPromptSubmitMemoryRetrieval: PluginHookFn<
|
|
|
264
278
|
resolveTrustClass(conversation?.trustContext) === "guardian";
|
|
265
279
|
const actorContext = resolveTurnInboundActorContext(
|
|
266
280
|
conversation?.trustContext,
|
|
267
|
-
conversation?.assistantId,
|
|
268
281
|
);
|
|
269
282
|
|
|
270
283
|
// v2 graph retrieval is the deprecated path: `shouldRunV2Retrieval` skips it
|
|
@@ -117,13 +117,13 @@ export const DEFAULT_INJECTOR_ORDER = {
|
|
|
117
117
|
} as const satisfies Record<string, number>;
|
|
118
118
|
|
|
119
119
|
export const DISK_PRESSURE_WARNING_PROMPT = `<disk_pressure_warning>
|
|
120
|
-
|
|
120
|
+
Storage is critically low and normal work is suspended until space is freed.
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Your first user-visible paragraph must warn the user that storage is critically low and normal work is suspended.
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Before taking cleanup actions, call \`skill_load\` with \`skill: "system-storage-cleanup"\` and follow the cleanup skill.
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
Unrelated work remains blocked until disk usage drops below the critical threshold or the guardian explicitly overrides the lock. Background processes and trusted-contact messages remain blocked while this cleanup mode is active.
|
|
127
127
|
</disk_pressure_warning>`;
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -49,6 +49,7 @@ interface ProviderCall {
|
|
|
49
49
|
options: SendMessageOptions | undefined;
|
|
50
50
|
}
|
|
51
51
|
const providerCalls: ProviderCall[] = [];
|
|
52
|
+
const warnCalls: Array<{ args: unknown[] }> = [];
|
|
52
53
|
|
|
53
54
|
mock.module("../../../../providers/provider-send-message.js", () => ({
|
|
54
55
|
getConfiguredProvider: async () => providerStub,
|
|
@@ -57,10 +58,12 @@ mock.module("../../../../providers/provider-send-message.js", () => ({
|
|
|
57
58
|
}));
|
|
58
59
|
|
|
59
60
|
mock.module("../../../../util/logger.js", () => ({
|
|
60
|
-
getLogger: () =>
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
getLogger: () => ({
|
|
62
|
+
warn: (...args: unknown[]) => warnCalls.push({ args }),
|
|
63
|
+
child: () => ({
|
|
64
|
+
warn: (...args: unknown[]) => warnCalls.push({ args }),
|
|
63
65
|
}),
|
|
66
|
+
}),
|
|
64
67
|
}));
|
|
65
68
|
|
|
66
69
|
const { selectPool, MemoryV3RetrievalUnavailableError } =
|
|
@@ -97,10 +100,21 @@ function noToolResponse(): ProviderResponse {
|
|
|
97
100
|
model: "stub-model",
|
|
98
101
|
stopReason: "end_turn",
|
|
99
102
|
usage: { inputTokens: 0, outputTokens: 0 },
|
|
103
|
+
rawRequest: { model: "MiniMaxAI/MiniMax-M3" },
|
|
104
|
+
rawResponse: { model: "accounts/fireworks/models/minimax-m3" },
|
|
100
105
|
content: [{ type: "text", text: "no tool call" }],
|
|
101
106
|
};
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
function wrongToolResponse(): ProviderResponse {
|
|
110
|
+
return {
|
|
111
|
+
model: "stub-model",
|
|
112
|
+
stopReason: "tool_use",
|
|
113
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
114
|
+
content: [{ type: "tool_use", id: "tu-1", name: "wrong_tool", input: {} }],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
/** Provider returning a different response per call (the i-th call returns
|
|
105
119
|
* responses[i], or the last entry once exhausted). */
|
|
106
120
|
function makeSequenceProvider(responses: ProviderResponse[]): Provider {
|
|
@@ -118,12 +132,12 @@ function makeSequenceProvider(responses: ProviderResponse[]): Provider {
|
|
|
118
132
|
|
|
119
133
|
/** Provider that records each call and then throws — the throw-after-retries
|
|
120
134
|
* path (the provider's own RetryProvider has already exhausted its backoff). */
|
|
121
|
-
function makeThrowingProvider(): Provider {
|
|
135
|
+
function makeThrowingProvider(message = "boom"): Provider {
|
|
122
136
|
return {
|
|
123
137
|
name: "throwing",
|
|
124
138
|
sendMessage: async (messages, options) => {
|
|
125
139
|
providerCalls.push({ messages, options });
|
|
126
|
-
throw new Error(
|
|
140
|
+
throw new Error(message);
|
|
127
141
|
},
|
|
128
142
|
};
|
|
129
143
|
}
|
|
@@ -167,9 +181,19 @@ function sentBlocks(callIndex = 0): RenderedBlock[] {
|
|
|
167
181
|
.content as unknown as RenderedBlock[];
|
|
168
182
|
}
|
|
169
183
|
|
|
184
|
+
function warnPayloads(): Array<Record<string, unknown>> {
|
|
185
|
+
return warnCalls
|
|
186
|
+
.map((call) => call.args[0])
|
|
187
|
+
.filter(
|
|
188
|
+
(payload): payload is Record<string, unknown> =>
|
|
189
|
+
payload !== null && typeof payload === "object",
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
170
193
|
beforeEach(() => {
|
|
171
194
|
providerStub = null;
|
|
172
195
|
providerCalls.length = 0;
|
|
196
|
+
warnCalls.length = 0;
|
|
173
197
|
});
|
|
174
198
|
|
|
175
199
|
// ---------------------------------------------------------------------------
|
|
@@ -250,6 +274,62 @@ describe("selectPool — infrastructure failures throw", () => {
|
|
|
250
274
|
MemoryV3RetrievalUnavailableError,
|
|
251
275
|
);
|
|
252
276
|
expect(providerCalls).toHaveLength(3);
|
|
277
|
+
const payloads = warnPayloads();
|
|
278
|
+
const attemptPayloads = payloads.filter(
|
|
279
|
+
(payload) => payload.reason === "missing_tool_use",
|
|
280
|
+
);
|
|
281
|
+
expect(attemptPayloads).toHaveLength(3);
|
|
282
|
+
expect(attemptPayloads[0]).toMatchObject({
|
|
283
|
+
attempt: 1,
|
|
284
|
+
reason: "missing_tool_use",
|
|
285
|
+
providerName: "stub",
|
|
286
|
+
candidateCount: 4,
|
|
287
|
+
stableCount: 2,
|
|
288
|
+
finderCount: 2,
|
|
289
|
+
response: {
|
|
290
|
+
model: "stub-model",
|
|
291
|
+
stopReason: "end_turn",
|
|
292
|
+
requestModel: "MiniMaxAI/MiniMax-M3",
|
|
293
|
+
responseModel: "accounts/fireworks/models/minimax-m3",
|
|
294
|
+
contentBlockTypes: ["text"],
|
|
295
|
+
toolUseNames: [],
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
const aggregatePayload = payloads.find((payload) =>
|
|
299
|
+
Array.isArray(payload.failures),
|
|
300
|
+
);
|
|
301
|
+
expect(aggregatePayload?.providerName).toBe("stub");
|
|
302
|
+
const failures = aggregatePayload?.failures as
|
|
303
|
+
| Array<Record<string, unknown>>
|
|
304
|
+
| undefined;
|
|
305
|
+
expect(failures?.[0]).toMatchObject({ reason: "missing_tool_use" });
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("wrong tool_use name logs the unexpected name before throwing", async () => {
|
|
309
|
+
providerStub = makeProvider(wrongToolResponse());
|
|
310
|
+
await expect(selectPool(makePool(), makeTurn("x"))).rejects.toThrow(
|
|
311
|
+
MemoryV3RetrievalUnavailableError,
|
|
312
|
+
);
|
|
313
|
+
expect(providerCalls).toHaveLength(3);
|
|
314
|
+
expect(
|
|
315
|
+
warnPayloads().filter(
|
|
316
|
+
(payload) => payload.reason === "unexpected_tool_name",
|
|
317
|
+
),
|
|
318
|
+
).toEqual([
|
|
319
|
+
expect.objectContaining({
|
|
320
|
+
attempt: 1,
|
|
321
|
+
reason: "unexpected_tool_name",
|
|
322
|
+
providerName: "stub",
|
|
323
|
+
toolName: "wrong_tool",
|
|
324
|
+
response: expect.objectContaining({
|
|
325
|
+
stopReason: "tool_use",
|
|
326
|
+
contentBlockTypes: ["tool_use"],
|
|
327
|
+
toolUseNames: ["wrong_tool"],
|
|
328
|
+
}),
|
|
329
|
+
}),
|
|
330
|
+
expect.objectContaining({ attempt: 2 }),
|
|
331
|
+
expect.objectContaining({ attempt: 3 }),
|
|
332
|
+
]);
|
|
253
333
|
});
|
|
254
334
|
|
|
255
335
|
test("schema mismatch → throws after retrying", async () => {
|
|
@@ -258,6 +338,17 @@ describe("selectPool — infrastructure failures throw", () => {
|
|
|
258
338
|
MemoryV3RetrievalUnavailableError,
|
|
259
339
|
);
|
|
260
340
|
expect(providerCalls).toHaveLength(3);
|
|
341
|
+
expect(
|
|
342
|
+
warnPayloads().filter((payload) => payload.reason === "schema_mismatch"),
|
|
343
|
+
).toEqual([
|
|
344
|
+
expect.objectContaining({
|
|
345
|
+
attempt: 1,
|
|
346
|
+
reason: "schema_mismatch",
|
|
347
|
+
schemaIssues: [expect.objectContaining({ path: "ids" })],
|
|
348
|
+
}),
|
|
349
|
+
expect.objectContaining({ attempt: 2 }),
|
|
350
|
+
expect.objectContaining({ attempt: 3 }),
|
|
351
|
+
]);
|
|
261
352
|
});
|
|
262
353
|
|
|
263
354
|
test("provider throw → throws after retrying", async () => {
|
|
@@ -266,6 +357,44 @@ describe("selectPool — infrastructure failures throw", () => {
|
|
|
266
357
|
MemoryV3RetrievalUnavailableError,
|
|
267
358
|
);
|
|
268
359
|
expect(providerCalls).toHaveLength(3);
|
|
360
|
+
expect(
|
|
361
|
+
warnPayloads().filter((payload) => payload.reason === "provider_error"),
|
|
362
|
+
).toEqual([
|
|
363
|
+
expect.objectContaining({
|
|
364
|
+
attempt: 1,
|
|
365
|
+
reason: "provider_error",
|
|
366
|
+
providerName: "throwing",
|
|
367
|
+
error: { name: "Error", message: "boom" },
|
|
368
|
+
}),
|
|
369
|
+
expect.objectContaining({ attempt: 2 }),
|
|
370
|
+
expect.objectContaining({ attempt: 3 }),
|
|
371
|
+
]);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("provider throw redacts sensitive message details in diagnostics", async () => {
|
|
375
|
+
const providerSecret = ["sk-proj-", "a".repeat(40)].join("");
|
|
376
|
+
const message = `provider rejected Authorization: Bearer ${providerSecret}`;
|
|
377
|
+
providerStub = makeThrowingProvider(message);
|
|
378
|
+
|
|
379
|
+
let thrown: unknown;
|
|
380
|
+
try {
|
|
381
|
+
await selectPool(makePool(), makeTurn("x"));
|
|
382
|
+
} catch (error) {
|
|
383
|
+
thrown = error;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
expect(thrown).toBeInstanceOf(MemoryV3RetrievalUnavailableError);
|
|
387
|
+
expect((thrown as Error).message).not.toContain(providerSecret);
|
|
388
|
+
expect((thrown as Error).message).toContain("[REDACTED]");
|
|
389
|
+
|
|
390
|
+
const providerErrors = warnPayloads().filter(
|
|
391
|
+
(payload) => payload.reason === "provider_error",
|
|
392
|
+
);
|
|
393
|
+
const error = providerErrors[0]?.error as
|
|
394
|
+
| Record<string, unknown>
|
|
395
|
+
| undefined;
|
|
396
|
+
expect(error?.message).not.toContain(providerSecret);
|
|
397
|
+
expect(error?.message).toContain("[REDACTED]");
|
|
269
398
|
});
|
|
270
399
|
|
|
271
400
|
test("a malformed response that recovers on retry returns its pages", async () => {
|
|
@@ -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,
|