@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
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedules the onboarding "Day 2 Check-in" calendar event server-side.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Resolve the Google OAuth connection, requiring the calendar.events scope.
|
|
6
|
+
* No connection / missing scope → a `scheduled: false` result (never an
|
|
7
|
+
* error): the web caller treats this as a best-effort skip.
|
|
8
|
+
* 2. List tomorrow's timed events in the 8am–8pm window (user's timezone) to
|
|
9
|
+
* derive busy intervals. Uses events.list rather than freeBusy.query
|
|
10
|
+
* because the onboarding grant is the narrow `calendar.events` scope, which
|
|
11
|
+
* authorizes events.list/insert but not freeBusy.query.
|
|
12
|
+
* 3. Choose the first open 15-minute slot (12pm–5pm, widening to 8am–8pm).
|
|
13
|
+
* 4. Create the event with the locked title + HTML description, sendUpdates=all.
|
|
14
|
+
*
|
|
15
|
+
* Authenticates via `resolveOAuthConnection("google")` + `connection.request()`,
|
|
16
|
+
* the same path the calendar watcher uses — no skill subprocess.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { canonicalizeTimeZone } from "../daemon/date-context.js";
|
|
20
|
+
import type { OAuthConnection } from "../oauth/connection.js";
|
|
21
|
+
import { resolveOAuthConnection } from "../oauth/connection-resolver.js";
|
|
22
|
+
import { getLogger } from "../util/logger.js";
|
|
23
|
+
import {
|
|
24
|
+
buildCheckinDescription,
|
|
25
|
+
buildCheckinTitle,
|
|
26
|
+
checkinAvailabilityWindow,
|
|
27
|
+
type CheckinNames,
|
|
28
|
+
chooseCheckinSlot,
|
|
29
|
+
extractBusyFromEvents,
|
|
30
|
+
type GcalEvent,
|
|
31
|
+
} from "./checkin-event.js";
|
|
32
|
+
|
|
33
|
+
const log = getLogger("onboarding:schedule-checkin");
|
|
34
|
+
|
|
35
|
+
const GOOGLE_CALENDAR_BASE_URL = "https://www.googleapis.com/calendar/v3";
|
|
36
|
+
const GOOGLE_CALENDAR_EVENTS_SCOPE =
|
|
37
|
+
"https://www.googleapis.com/auth/calendar.events";
|
|
38
|
+
/** Calendar shares the Google OAuth connection with Gmail. */
|
|
39
|
+
const GOOGLE_PROVIDER = "google";
|
|
40
|
+
const PRIMARY_CALENDAR_ID = "primary";
|
|
41
|
+
|
|
42
|
+
export interface ScheduleCheckinInput extends CheckinNames {
|
|
43
|
+
/** IANA timezone reported by the client (e.g. "America/New_York"). */
|
|
44
|
+
timeZone?: string;
|
|
45
|
+
/** Override "now" for deterministic tests. Defaults to the current time. */
|
|
46
|
+
nowMs?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type ScheduleCheckinResult =
|
|
50
|
+
| {
|
|
51
|
+
scheduled: true;
|
|
52
|
+
eventId: string;
|
|
53
|
+
htmlLink: string | null;
|
|
54
|
+
/** Event start, ISO 8601 (UTC). */
|
|
55
|
+
start: string;
|
|
56
|
+
/** Event end, ISO 8601 (UTC). */
|
|
57
|
+
end: string;
|
|
58
|
+
timeZone: string;
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
scheduled: false;
|
|
62
|
+
/**
|
|
63
|
+
* Why nothing was booked. `calendar_unavailable` covers both "not
|
|
64
|
+
* connected" and "calendar scope not granted" — the client surfaces a
|
|
65
|
+
* single best-effort skip either way.
|
|
66
|
+
*/
|
|
67
|
+
reason: "calendar_unavailable";
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
interface EventsListResponse {
|
|
71
|
+
items?: GcalEvent[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Subset of the events.insert response we surface back to the caller. */
|
|
75
|
+
interface CreatedEvent {
|
|
76
|
+
id?: string;
|
|
77
|
+
htmlLink?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Schedule the Day 2 check-in. Resolves to a `scheduled: false` result when no
|
|
82
|
+
* calendar is connected; throws only on unexpected Calendar API failures (the
|
|
83
|
+
* route handler maps those to a 5xx, the web caller swallows them).
|
|
84
|
+
*/
|
|
85
|
+
export async function scheduleOnboardingCheckin(
|
|
86
|
+
input: ScheduleCheckinInput,
|
|
87
|
+
): Promise<ScheduleCheckinResult> {
|
|
88
|
+
const timeZone =
|
|
89
|
+
canonicalizeTimeZone(input.timeZone) ??
|
|
90
|
+
// Fall back to the daemon host timezone when the client didn't report one.
|
|
91
|
+
Intl.DateTimeFormat().resolvedOptions().timeZone ??
|
|
92
|
+
"UTC";
|
|
93
|
+
const nowMs = input.nowMs ?? Date.now();
|
|
94
|
+
|
|
95
|
+
let connection: OAuthConnection;
|
|
96
|
+
try {
|
|
97
|
+
connection = await resolveOAuthConnection(GOOGLE_PROVIDER, {
|
|
98
|
+
requiredScopes: [GOOGLE_CALENDAR_EVENTS_SCOPE],
|
|
99
|
+
});
|
|
100
|
+
} catch (err) {
|
|
101
|
+
// No active connection or the calendar scope wasn't granted — skip quietly.
|
|
102
|
+
log.info(
|
|
103
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
104
|
+
"Check-in skipped: Google Calendar not available",
|
|
105
|
+
);
|
|
106
|
+
return { scheduled: false, reason: "calendar_unavailable" };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { timeMinMs, timeMaxMs } = checkinAvailabilityWindow(nowMs, timeZone);
|
|
110
|
+
|
|
111
|
+
const eventsResp = await connection.request({
|
|
112
|
+
method: "GET",
|
|
113
|
+
path: `/calendars/${encodeURIComponent(PRIMARY_CALENDAR_ID)}/events`,
|
|
114
|
+
query: {
|
|
115
|
+
timeMin: new Date(timeMinMs).toISOString(),
|
|
116
|
+
timeMax: new Date(timeMaxMs).toISOString(),
|
|
117
|
+
// Expand recurring events into instances so each occurrence is a concrete
|
|
118
|
+
// busy interval in the window.
|
|
119
|
+
singleEvents: "true",
|
|
120
|
+
orderBy: "startTime",
|
|
121
|
+
maxResults: "250",
|
|
122
|
+
},
|
|
123
|
+
baseUrl: GOOGLE_CALENDAR_BASE_URL,
|
|
124
|
+
headers: { "Content-Type": "application/json" },
|
|
125
|
+
});
|
|
126
|
+
if (eventsResp.status < 200 || eventsResp.status >= 300) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Calendar events.list ${eventsResp.status}: ${stringifyBody(eventsResp.body)}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const busy = extractBusyFromEvents(
|
|
133
|
+
(eventsResp.body as EventsListResponse).items ?? [],
|
|
134
|
+
);
|
|
135
|
+
const slot = chooseCheckinSlot(nowMs, timeZone, busy);
|
|
136
|
+
|
|
137
|
+
const uuid = crypto.randomUUID();
|
|
138
|
+
const eventResp = await connection.request({
|
|
139
|
+
method: "POST",
|
|
140
|
+
path: `/calendars/${encodeURIComponent(PRIMARY_CALENDAR_ID)}/events`,
|
|
141
|
+
query: { sendUpdates: "all" },
|
|
142
|
+
baseUrl: GOOGLE_CALENDAR_BASE_URL,
|
|
143
|
+
headers: { "Content-Type": "application/json" },
|
|
144
|
+
body: {
|
|
145
|
+
summary: buildCheckinTitle(input),
|
|
146
|
+
description: buildCheckinDescription(uuid),
|
|
147
|
+
start: {
|
|
148
|
+
dateTime: new Date(slot.startMs).toISOString(),
|
|
149
|
+
timeZone,
|
|
150
|
+
},
|
|
151
|
+
end: {
|
|
152
|
+
dateTime: new Date(slot.endMs).toISOString(),
|
|
153
|
+
timeZone,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
if (eventResp.status < 200 || eventResp.status >= 300) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Calendar event create ${eventResp.status}: ${stringifyBody(eventResp.body)}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const event = eventResp.body as CreatedEvent;
|
|
164
|
+
if (!event.id) {
|
|
165
|
+
throw new Error("Calendar event create returned no event id");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
log.info(
|
|
169
|
+
{
|
|
170
|
+
eventId: event.id,
|
|
171
|
+
start: new Date(slot.startMs).toISOString(),
|
|
172
|
+
window: slot.window,
|
|
173
|
+
timeZone,
|
|
174
|
+
},
|
|
175
|
+
"Scheduled onboarding Day 2 check-in",
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
scheduled: true,
|
|
180
|
+
eventId: event.id,
|
|
181
|
+
htmlLink: event.htmlLink ?? null,
|
|
182
|
+
start: new Date(slot.startMs).toISOString(),
|
|
183
|
+
end: new Date(slot.endMs).toISOString(),
|
|
184
|
+
timeZone,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function stringifyBody(body: unknown): string {
|
|
189
|
+
return typeof body === "string" ? body : JSON.stringify(body ?? "");
|
|
190
|
+
}
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
|
|
10
10
|
// Use a tiny timeout so the setTimeout branch fires quickly in tests
|
|
11
11
|
const mockConfig = {
|
|
12
|
-
timeouts: {
|
|
12
|
+
timeouts: { questionResponseTimeoutSec: 0.05 },
|
|
13
13
|
};
|
|
14
14
|
// Preserve every other export from the real config/loader so other
|
|
15
15
|
// tests in the same `bun test` run (which share module-level mocks)
|
|
@@ -156,9 +156,12 @@ export interface QuestionBatchMetadata {
|
|
|
156
156
|
* the whole batch to `/v1/question-response` when the user is done — no
|
|
157
157
|
* per-question accumulator, no partial state machine.
|
|
158
158
|
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
159
|
+
* The idle timeout is a backstop (`getConfig().timeouts.questionResponseTimeoutSec`,
|
|
160
|
+
* default 30 min), not the primary way a prompt is dismissed. An interactive
|
|
161
|
+
* user who moves on instead of answering enqueues another message, which
|
|
162
|
+
* supersedes the open prompt at the enqueue handler (see conversation-routes.ts);
|
|
163
|
+
* a non-interactive turn resolves immediately at the tool. The backstop only
|
|
164
|
+
* fires when a prompt is left open with no response and no follow-up message.
|
|
162
165
|
*/
|
|
163
166
|
export class QuestionPrompter {
|
|
164
167
|
async prompt(params: QuestionPromptParams): Promise<QuestionPromptResult> {
|
|
@@ -199,7 +202,7 @@ export class QuestionPrompter {
|
|
|
199
202
|
const requestId = uuid();
|
|
200
203
|
|
|
201
204
|
return new Promise<QuestionPromptResult>((resolve, reject) => {
|
|
202
|
-
const timeoutMs = getConfig().timeouts.
|
|
205
|
+
const timeoutMs = getConfig().timeouts.questionResponseTimeoutSec * 1000;
|
|
203
206
|
|
|
204
207
|
// Closure-scoped idempotency guard. Every resolution path (timeout,
|
|
205
208
|
// abort, route resolution via `rpcResolve`/`rpcReject`) routes through
|
package/src/plugin-api/index.ts
CHANGED
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
* (optionally overriding the profile) and run inference through the
|
|
38
38
|
* workspace's configured profiles and credentials — no plugin-supplied API key
|
|
39
39
|
*
|
|
40
|
-
* - {@link
|
|
41
|
-
* - {@link
|
|
40
|
+
* - {@link InitContext} — passed to `init` hook at bootstrap
|
|
41
|
+
* - {@link ShutdownContext} — passed to `shutdown` hook at teardown
|
|
42
42
|
* - {@link UserPromptSubmitContext} — passed to `user-prompt-submit` hook,
|
|
43
43
|
* fired immediately before the agent loop receives a user's prompt
|
|
44
44
|
* - {@link PostCompactContext} — passed to `post-compact` hook, fired after
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
* - {@link PostModelCallContext} — passed to `post-model-call` hook, fired at
|
|
56
56
|
* every model-call outcome (a finalized reply or a provider rejection) to
|
|
57
57
|
* transform content and decide whether to retry
|
|
58
|
-
* - {@link
|
|
58
|
+
* - {@link HookFunction} — signature every lifecycle hook implements
|
|
59
59
|
* - {@link PluginLogger} — pino-compatible logger shape on the contexts
|
|
60
60
|
* - {@link ToolDefinition} — author-facing tool spec (default-export shape
|
|
61
61
|
* for both plugin tool files and workspace tool files)
|
|
@@ -98,16 +98,16 @@ export type {
|
|
|
98
98
|
export type { LLMCallSite } from "../config/schemas/llm.js";
|
|
99
99
|
export type {
|
|
100
100
|
AgentLoopExitReason,
|
|
101
|
+
HookFunction,
|
|
102
|
+
InitContext,
|
|
101
103
|
ModelProfileInfo,
|
|
102
|
-
PluginHookFn,
|
|
103
|
-
PluginInitContext,
|
|
104
104
|
PluginLogger,
|
|
105
|
-
PluginShutdownContext,
|
|
106
105
|
PostCompactContext,
|
|
107
106
|
PostModelCallContext,
|
|
108
107
|
PostModelCallDecision,
|
|
109
108
|
PostToolUseContext,
|
|
110
109
|
PreModelCallContext,
|
|
110
|
+
ShutdownContext,
|
|
111
111
|
StopContext,
|
|
112
112
|
ToolContext,
|
|
113
113
|
ToolDefinition,
|
|
@@ -130,12 +130,12 @@ export type {
|
|
|
130
130
|
} from "../runtime/assistant-event-hub.js";
|
|
131
131
|
export { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
132
132
|
export { getModelProfiles } from "./model-profiles.js";
|
|
133
|
-
// Check whether a
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
133
|
+
// Check whether a model or profile can process image input. Accepts a concrete
|
|
134
|
+
// model id, a profile key, or a `ModelProfileInfo`; a bare string is resolved
|
|
135
|
+
// as a model id first and then as a profile key. Profile resolution merges over
|
|
136
|
+
// the workspace default and infers the provider for model-only profiles, then
|
|
137
|
+
// looks up the model catalog's `supportsVision` flag (mix profiles are
|
|
138
|
+
// vision-capable if any arm is). Returns false when nothing resolves.
|
|
139
139
|
export { doesSupportVision } from "./vision-support.js";
|
|
140
140
|
// Resolve a provider for a call site (optionally overriding the profile) so a
|
|
141
141
|
// plugin can run inference through the workspace's configured profiles and
|
package/src/plugin-api/types.ts
CHANGED
|
@@ -57,30 +57,28 @@ export interface PluginLogger {
|
|
|
57
57
|
* empty model that with `| null`, not `| undefined`.
|
|
58
58
|
*
|
|
59
59
|
* Each known hook key has a documented context shape:
|
|
60
|
-
* - `init` — {@link
|
|
61
|
-
* - `shutdown` — {@link
|
|
60
|
+
* - `init` — {@link InitContext}
|
|
61
|
+
* - `shutdown` — {@link ShutdownContext}
|
|
62
62
|
* - `user-prompt-submit` — {@link UserPromptSubmitContext}
|
|
63
63
|
* - `pre-model-call` — {@link PreModelCallContext}
|
|
64
64
|
* - `post-tool-use` — {@link PostToolUseContext}
|
|
65
65
|
* - `stop` — {@link StopContext}
|
|
66
66
|
* - `post-model-call` — {@link PostModelCallContext}
|
|
67
67
|
*/
|
|
68
|
-
export type
|
|
68
|
+
export type HookFunction<TCtx = unknown> = (
|
|
69
69
|
ctx: TCtx,
|
|
70
70
|
) => Promise<Partial<TCtx> | void>;
|
|
71
71
|
|
|
72
72
|
// ─── Init context ────────────────────────────────────────────────────────────
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
* Context passed to `Plugin.init()` during bootstrap. Carries resolved
|
|
76
|
-
* config
|
|
77
|
-
*
|
|
75
|
+
* Context passed to `Plugin.init()` during bootstrap. Carries the resolved
|
|
76
|
+
* config, a pino-compatible logger scoped to the plugin, a per-plugin
|
|
77
|
+
* writable data directory, and the assistant's version metadata.
|
|
78
78
|
*/
|
|
79
|
-
export interface
|
|
79
|
+
export interface InitContext {
|
|
80
80
|
/** Parsed config for this plugin (may be `unknown` until the manifest validates). */
|
|
81
81
|
config: unknown;
|
|
82
|
-
/** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
|
|
83
|
-
credentials: Record<string, string>;
|
|
84
82
|
/** Pino-compatible child logger bound to `{ plugin: <name> }`. */
|
|
85
83
|
logger: PluginLogger;
|
|
86
84
|
/** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
|
|
@@ -127,7 +125,7 @@ export interface ModelProfileInfo {
|
|
|
127
125
|
|
|
128
126
|
/**
|
|
129
127
|
* Context passed to the `shutdown` hook during daemon teardown. Kept
|
|
130
|
-
* intentionally narrower than {@link
|
|
128
|
+
* intentionally narrower than {@link InitContext} — most teardown
|
|
131
129
|
* paths only need to know which assistant version they're shutting
|
|
132
130
|
* down against (e.g. for version-conditional cleanup of state files
|
|
133
131
|
* written by a previous boot).
|
|
@@ -137,7 +135,7 @@ export interface ModelProfileInfo {
|
|
|
137
135
|
* stash a version stamp at init can compare against the same name on
|
|
138
136
|
* tear-down without keeping their own copy.
|
|
139
137
|
*/
|
|
140
|
-
export interface
|
|
138
|
+
export interface ShutdownContext {
|
|
141
139
|
/** Assistant semver for compatibility checks inside the plugin. */
|
|
142
140
|
assistantVersion: string;
|
|
143
141
|
}
|
|
@@ -153,7 +151,7 @@ export interface PluginShutdownContext {
|
|
|
153
151
|
*
|
|
154
152
|
* The hook may transform `latestMessages` either by mutating it in place
|
|
155
153
|
* (`push` / `splice` / `length = 0`) or by returning a new context with
|
|
156
|
-
* a fresh `latestMessages` array — see {@link
|
|
154
|
+
* a fresh `latestMessages` array — see {@link HookFunction}'s polymorphic
|
|
157
155
|
* return shape. The daemon threads the final `latestMessages` value into
|
|
158
156
|
* `agentLoop.run()` as the run-messages argument.
|
|
159
157
|
*
|
|
@@ -246,7 +244,7 @@ export interface UserPromptSubmitContext {
|
|
|
246
244
|
* their own injected context the same way.
|
|
247
245
|
*
|
|
248
246
|
* The hook re-injects by mutating `history` in place (or returning a new
|
|
249
|
-
* context with a replacement `history`) — see {@link
|
|
247
|
+
* context with a replacement `history`) — see {@link HookFunction}'s
|
|
250
248
|
* polymorphic return shape. The agent loop reads the settled `history` back off
|
|
251
249
|
* the context and resumes the turn from it. Multiple plugins' hooks chain in
|
|
252
250
|
* registration order, each seeing the previous plugin's edits.
|
|
@@ -303,7 +301,7 @@ export interface PostCompactContext {
|
|
|
303
301
|
*
|
|
304
302
|
* The hook may transform the result either by mutating `toolResponse` in
|
|
305
303
|
* place (e.g. reassigning `toolResponse.content`) or by returning a new
|
|
306
|
-
* context with a fresh `toolResponse` — see {@link
|
|
304
|
+
* context with a fresh `toolResponse` — see {@link HookFunction}'s
|
|
307
305
|
* polymorphic return shape. The daemon threads the final `toolResponse`
|
|
308
306
|
* into the provider-bound history.
|
|
309
307
|
*
|
|
@@ -84,16 +84,16 @@ describe("doesSupportVision", () => {
|
|
|
84
84
|
expect(doesSupportVision(profile("text-profile"))).toBe(false);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
test("
|
|
87
|
+
test("returns false for an unknown profile key not in config", () => {
|
|
88
88
|
setMockConfig({});
|
|
89
|
-
expect(doesSupportVision(profile("nonexistent"))).toBe(
|
|
89
|
+
expect(doesSupportVision(profile("nonexistent"))).toBe(false);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
-
test("
|
|
92
|
+
test("returns false for an unknown provider/model pair", () => {
|
|
93
93
|
setMockConfig({
|
|
94
94
|
"unknown-model": { provider: "unknown-provider", model: "unknown-model" },
|
|
95
95
|
});
|
|
96
|
-
expect(doesSupportVision(profile("unknown-model"))).toBe(
|
|
96
|
+
expect(doesSupportVision(profile("unknown-model"))).toBe(false);
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
test("inherits provider from llm.default when profile only sets model", () => {
|
|
@@ -147,3 +147,27 @@ describe("doesSupportVision", () => {
|
|
|
147
147
|
expect(doesSupportVision(profile("mix-profile"))).toBe(false);
|
|
148
148
|
});
|
|
149
149
|
});
|
|
150
|
+
|
|
151
|
+
describe("doesSupportVision with a bare string", () => {
|
|
152
|
+
test("returns true for a known vision-capable model id", () => {
|
|
153
|
+
expect(doesSupportVision("claude-opus-4-6")).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("returns false for a known text-only model id", () => {
|
|
157
|
+
expect(doesSupportVision("accounts/fireworks/models/glm-5p2")).toBe(false);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("falls back to resolving the string as a profile key", () => {
|
|
161
|
+
// "vision-profile" is not a catalog model id, so it resolves as a profile
|
|
162
|
+
// key → anthropic/claude-opus-4-6 (vision-capable).
|
|
163
|
+
setMockConfig({
|
|
164
|
+
"vision-profile": { provider: "anthropic", model: "claude-opus-4-6" },
|
|
165
|
+
});
|
|
166
|
+
expect(doesSupportVision("vision-profile")).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("returns false for a string that is neither a model nor a profile", () => {
|
|
170
|
+
setMockConfig({});
|
|
171
|
+
expect(doesSupportVision("some-unknown-string")).toBe(false);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A plugin that gates image processing on vision capability (e.g. an
|
|
5
5
|
* image-to-text fallback for text-only models) calls {@link doesSupportVision}
|
|
6
|
-
* instead of hardcoding model names.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* instead of hardcoding model names. One entry point serves both shapes a
|
|
7
|
+
* caller might hold:
|
|
8
|
+
* - a concrete model id (e.g. the provider-reported model that just ran), and
|
|
9
|
+
* - a profile — either a {@link ModelProfileInfo} or a bare profile key —
|
|
10
|
+
* resolved through `llm.profiles` to an effective `(provider, model)`.
|
|
11
|
+
*
|
|
12
|
+
* A bare string is tried as a model id first and then as a profile key, so the
|
|
13
|
+
* two callers share one function. Resolution returns `false` when nothing
|
|
14
|
+
* resolves (rather than failing open): a consumer gating an image→text
|
|
15
|
+
* fallback wants an unknown model treated as "can't show images" — caption it —
|
|
16
|
+
* over silently shipping a raw image to a provider that may reject it.
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
import { getConfig } from "../config/loader.js";
|
|
@@ -17,46 +24,74 @@ import {
|
|
|
17
24
|
import type { ModelProfileInfo } from "./types.js";
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
|
-
* Whether
|
|
27
|
+
* Whether the given model or profile can process image input.
|
|
21
28
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
* `modelOrProfile` may be a concrete model id, a profile key, or a
|
|
30
|
+
* {@link ModelProfileInfo}. A bare string is resolved as a model id first and,
|
|
31
|
+
* failing that, as a profile key. Returns `false` when nothing resolves.
|
|
32
|
+
*/
|
|
33
|
+
export function doesSupportVision(
|
|
34
|
+
modelOrProfile: ModelProfileInfo | string,
|
|
35
|
+
): boolean {
|
|
36
|
+
if (typeof modelOrProfile === "string") {
|
|
37
|
+
// Concrete model id first, then fall back to treating it as a profile key.
|
|
38
|
+
return (
|
|
39
|
+
modelVision(modelOrProfile) ?? profileVision(modelOrProfile) ?? false
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return profileVision(modelOrProfile.key) ?? false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Catalog vision flag for a concrete model id, or `undefined` when the catalog
|
|
47
|
+
* doesn't know the model. The same model id carries the same capability under
|
|
48
|
+
* every provider that offers it, so the first catalog match wins.
|
|
33
49
|
*/
|
|
34
|
-
|
|
50
|
+
function modelVision(model: string): boolean | undefined {
|
|
51
|
+
for (const provider of PROVIDER_CATALOG) {
|
|
52
|
+
const catalogModel = provider.models.find((m) => m.id === model);
|
|
53
|
+
if (catalogModel != null) return catalogModel.supportsVision ?? false;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a profile key through `llm.profiles` to its vision capability, or
|
|
60
|
+
* `undefined` when the key is unknown or resolves to a model the catalog
|
|
61
|
+
* doesn't know. A mix profile resolves to `true` if any arm supports vision
|
|
62
|
+
* (the mix can route to it) and `false` only once every arm is a known
|
|
63
|
+
* text-only model.
|
|
64
|
+
*/
|
|
65
|
+
function profileVision(profileKey: string): boolean | undefined {
|
|
35
66
|
const { llm } = getConfig();
|
|
36
|
-
const entry = llm.profiles[
|
|
37
|
-
if (entry == null) return
|
|
67
|
+
const entry = llm.profiles[profileKey];
|
|
68
|
+
if (entry == null) return undefined;
|
|
38
69
|
|
|
39
|
-
// Mix: fail-open if any arm supports vision.
|
|
40
70
|
if (entry.mix != null) {
|
|
41
|
-
|
|
71
|
+
let sawUnknown = false;
|
|
72
|
+
for (const arm of entry.mix) {
|
|
42
73
|
const armEntry = llm.profiles[arm.profile];
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
const armVision =
|
|
75
|
+
armEntry == null ? undefined : resolveEntryVision(armEntry, llm);
|
|
76
|
+
if (armVision === true) return true;
|
|
77
|
+
if (armVision == null) sawUnknown = true;
|
|
78
|
+
}
|
|
79
|
+
return sawUnknown ? undefined : false;
|
|
46
80
|
}
|
|
47
81
|
|
|
48
|
-
return
|
|
82
|
+
return resolveEntryVision(entry, llm);
|
|
49
83
|
}
|
|
50
84
|
|
|
51
85
|
/**
|
|
52
86
|
* Resolve whether a concrete (non-mix) profile entry supports vision by
|
|
53
|
-
* merging its fields over `llm.default` and inferring the provider when
|
|
54
|
-
*
|
|
87
|
+
* merging its fields over `llm.default` and inferring the provider when only
|
|
88
|
+
* the model is set. Returns `undefined` when the effective `(provider, model)`
|
|
89
|
+
* can't be determined or isn't in the catalog.
|
|
55
90
|
*/
|
|
56
|
-
function
|
|
91
|
+
function resolveEntryVision(
|
|
57
92
|
entry: { provider?: string; model?: string },
|
|
58
93
|
llm: { default?: { provider?: string; model?: string } },
|
|
59
|
-
): boolean {
|
|
94
|
+
): boolean | undefined {
|
|
60
95
|
const provider = entry.provider ?? llm.default?.provider;
|
|
61
96
|
const model = entry.model ?? llm.default?.model;
|
|
62
97
|
|
|
@@ -67,12 +102,12 @@ function resolveEntrySupportsVision(
|
|
|
67
102
|
(typeof model === "string" ? getCatalogProviderForModel(model) : undefined);
|
|
68
103
|
|
|
69
104
|
if (typeof effectiveProvider !== "string" || typeof model !== "string") {
|
|
70
|
-
return
|
|
105
|
+
return undefined;
|
|
71
106
|
}
|
|
72
107
|
|
|
73
108
|
const catalogProvider = PROVIDER_CATALOG.find(
|
|
74
109
|
(p) => p.id === effectiveProvider,
|
|
75
110
|
);
|
|
76
111
|
const catalogModel = catalogProvider?.models.find((m) => m.id === model);
|
|
77
|
-
return catalogModel?.supportsVision
|
|
112
|
+
return catalogModel?.supportsVision;
|
|
78
113
|
}
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* ignores the decision — so the hook returns early for both.
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
-
import type {
|
|
49
|
+
import type { HookFunction, PostModelCallContext } from "@vellumai/plugin-api";
|
|
50
50
|
|
|
51
51
|
import type { ContentBlock, Message } from "../../../../providers/types.js";
|
|
52
52
|
import {
|
|
@@ -112,7 +112,7 @@ function currentCycleMessages(
|
|
|
112
112
|
return messages;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const postModelCall:
|
|
115
|
+
const postModelCall: HookFunction<PostModelCallContext> = async (ctx) => {
|
|
116
116
|
// A provider rejection carries no turn content to assess (a recovery hook
|
|
117
117
|
// owns the rejection); the sibling `stop` hook clears the mark when the turn
|
|
118
118
|
// terminates.
|
|
@@ -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 { clearEmptyResponseNudged } from "../nudge-state-store.js";
|
|
17
17
|
|
|
18
|
-
const stop:
|
|
18
|
+
const stop: HookFunction<StopContext> = async (ctx) => {
|
|
19
19
|
clearEmptyResponseNudged(ctx.conversationId);
|
|
20
20
|
};
|
|
21
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Default `post-tool-use` hook: when a turn's exploration tool calls (bash,
|
|
3
|
-
* file_read, file_list) show drift — a long unbroken run with no text sent to
|
|
3
|
+
* code_search, file_read, file_list) show drift — a long unbroken run with no text sent to
|
|
4
4
|
* the user, or the model re-issuing the exact same call — surface a notice
|
|
5
5
|
* via `additionalContext` that coaches it to (a) give the user a brief
|
|
6
6
|
* progress summary and (b) delegate the rest of the investigation to an
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
* per-tool-result hot path.
|
|
56
56
|
*/
|
|
57
57
|
|
|
58
|
-
import type {
|
|
58
|
+
import type { HookFunction, PostToolUseContext } from "@vellumai/plugin-api";
|
|
59
59
|
|
|
60
60
|
import type { Message } from "../../../../providers/types.js";
|
|
61
61
|
|
|
@@ -105,6 +105,7 @@ const LOOP_PRONE_MODEL_PATTERN = /kimi-k2[p.]6|minimax-m3/i;
|
|
|
105
105
|
/** Read-only exploration tools whose unbroken runs indicate inline drift. */
|
|
106
106
|
const EXPLORATION_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
107
107
|
"bash",
|
|
108
|
+
"code_search",
|
|
108
109
|
"file_read",
|
|
109
110
|
"file_list",
|
|
110
111
|
]);
|
|
@@ -232,7 +233,7 @@ function currentCallRepeatCount(
|
|
|
232
233
|
return count;
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
const postToolUse:
|
|
236
|
+
const postToolUse: HookFunction<PostToolUseContext> = async (ctx) => {
|
|
236
237
|
const usesById = toolUsesById(ctx.messages);
|
|
237
238
|
const currentUse = usesById.get(ctx.toolResponse.tool_use_id);
|
|
238
239
|
if (currentUse === undefined || !EXPLORATION_TOOL_NAMES.has(currentUse.name))
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* empty-response hook; only a provider rejection is this hook's to act on.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import type {
|
|
26
|
+
import type { HookFunction, PostModelCallContext } from "@vellumai/plugin-api";
|
|
27
27
|
|
|
28
28
|
import {
|
|
29
29
|
isOrderingRepairAttempted,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "../repair-state-store.js";
|
|
32
32
|
import { deepRepairHistory, isRepairableOrderingError } from "../terminal.js";
|
|
33
33
|
|
|
34
|
-
const postModelCall:
|
|
34
|
+
const postModelCall: HookFunction<PostModelCallContext> = async (ctx) => {
|
|
35
35
|
if (
|
|
36
36
|
ctx.error &&
|
|
37
37
|
isRepairableOrderingError(ctx.error.message) &&
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* retry the loop's per-run backstop refused).
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import type {
|
|
14
|
+
import type { HookFunction, StopContext } from "@vellumai/plugin-api";
|
|
15
15
|
|
|
16
16
|
import { clearOrderingRepairAttempted } from "../repair-state-store.js";
|
|
17
17
|
|
|
18
|
-
const stop:
|
|
18
|
+
const stop: HookFunction<StopContext> = async (ctx) => {
|
|
19
19
|
clearOrderingRepairAttempted(ctx.conversationId);
|
|
20
20
|
};
|
|
21
21
|
|