@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
package/src/plugins/pipeline.ts
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* A "hook" is a named lifecycle event (`user-prompt-submit`, `post-tool-use`,
|
|
5
5
|
* ...) that every registered plugin may handle. The runner walks each plugin's
|
|
6
6
|
* hook for a given event in registration order, threading a context value
|
|
7
|
-
* through the chain so hooks can observe and transform it.
|
|
8
|
-
*
|
|
9
|
-
* context whose fields are merged
|
|
7
|
+
* through the chain so hooks can observe and transform it. Each hook receives
|
|
8
|
+
* an isolated draft of the current context. A hook either mutates the draft in
|
|
9
|
+
* place (returning `void`) or returns a partial context whose fields are merged
|
|
10
|
+
* onto the draft. Failed hook drafts are discarded.
|
|
10
11
|
*
|
|
11
12
|
* `getHooksFor` is now async — it pulls user-land hooks from the mtime
|
|
12
13
|
* cache (filesystem-as-truth) and default plugin hooks from the registry
|
|
@@ -16,34 +17,131 @@
|
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
import type { HookName } from "../plugin-api/constants.js";
|
|
20
|
+
import { getLogger } from "../util/logger.js";
|
|
19
21
|
import { getHooksFor } from "./registry.js";
|
|
22
|
+
import type { HookFunction } from "./types.js";
|
|
20
23
|
|
|
21
24
|
// ─── Hook runner ────────────────────────────────────────────────────────────
|
|
22
25
|
|
|
26
|
+
const log = getLogger("plugin-pipeline");
|
|
27
|
+
|
|
28
|
+
function isPluginLogger(value: unknown): value is {
|
|
29
|
+
info: unknown;
|
|
30
|
+
warn: unknown;
|
|
31
|
+
error: unknown;
|
|
32
|
+
debug: unknown;
|
|
33
|
+
} {
|
|
34
|
+
return (
|
|
35
|
+
value !== null &&
|
|
36
|
+
typeof value === "object" &&
|
|
37
|
+
typeof (value as { info?: unknown }).info === "function" &&
|
|
38
|
+
typeof (value as { warn?: unknown }).warn === "function" &&
|
|
39
|
+
typeof (value as { error?: unknown }).error === "function" &&
|
|
40
|
+
typeof (value as { debug?: unknown }).debug === "function"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isPlainObject(value: object): boolean {
|
|
45
|
+
const prototype = Object.getPrototypeOf(value);
|
|
46
|
+
return prototype === Object.prototype || prototype === null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function cloneHookValue<T>(value: T, seen = new WeakMap<object, unknown>()): T {
|
|
50
|
+
if (value === null || typeof value !== "object") return value;
|
|
51
|
+
if (value instanceof Error || isPluginLogger(value)) return value;
|
|
52
|
+
|
|
53
|
+
const existing = seen.get(value);
|
|
54
|
+
if (existing !== undefined) return existing as T;
|
|
55
|
+
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
const copy: unknown[] = [];
|
|
58
|
+
seen.set(value, copy);
|
|
59
|
+
for (const item of value) {
|
|
60
|
+
copy.push(cloneHookValue(item, seen));
|
|
61
|
+
}
|
|
62
|
+
return copy as T;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (value instanceof Date) {
|
|
66
|
+
return new Date(value.getTime()) as T;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (value instanceof Map) {
|
|
70
|
+
const copy = new Map();
|
|
71
|
+
seen.set(value, copy);
|
|
72
|
+
for (const [key, mapValue] of value) {
|
|
73
|
+
copy.set(cloneHookValue(key, seen), cloneHookValue(mapValue, seen));
|
|
74
|
+
}
|
|
75
|
+
return copy as T;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (value instanceof Set) {
|
|
79
|
+
const copy = new Set();
|
|
80
|
+
seen.set(value, copy);
|
|
81
|
+
for (const item of value) {
|
|
82
|
+
copy.add(cloneHookValue(item, seen));
|
|
83
|
+
}
|
|
84
|
+
return copy as T;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!isPlainObject(value)) return value;
|
|
88
|
+
|
|
89
|
+
const copy: Record<PropertyKey, unknown> = {};
|
|
90
|
+
seen.set(value, copy);
|
|
91
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
92
|
+
copy[key] = cloneHookValue(
|
|
93
|
+
(value as Record<PropertyKey, unknown>)[key],
|
|
94
|
+
seen,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return copy as T;
|
|
98
|
+
}
|
|
99
|
+
|
|
23
100
|
/**
|
|
24
101
|
* Execute a hook chain: walk every registered plugin's hook for `name` in
|
|
25
102
|
* registration order, threading `initialCtx` through each. Hooks may either
|
|
26
|
-
* mutate
|
|
27
|
-
* whose fields are merged onto the
|
|
28
|
-
* overwrite the running context, every other field is preserved.
|
|
29
|
-
*
|
|
103
|
+
* mutate their draft context in place (returning `void`) or return a partial
|
|
104
|
+
* context whose fields are merged onto the draft — keys the hook returns
|
|
105
|
+
* overwrite the running context, every other field is preserved. If a hook
|
|
106
|
+
* throws, its draft is discarded and the next hook receives the last
|
|
107
|
+
* successfully committed context. The final context after the chain settles is
|
|
108
|
+
* returned.
|
|
30
109
|
*
|
|
31
110
|
* @param name The hook identifier — pick one from {@link HOOKS}.
|
|
32
111
|
* @param initialCtx Context the first hook receives.
|
|
33
112
|
* @returns The final context after the chain settles. Same reference as
|
|
34
|
-
* `initialCtx` when no plugin registers `name
|
|
35
|
-
* chained hook returns `void` (mutation-in-place style).
|
|
113
|
+
* `initialCtx` when no plugin registers `name`.
|
|
36
114
|
*/
|
|
37
115
|
export async function runHook<TCtx>(
|
|
38
116
|
name: HookName,
|
|
39
117
|
initialCtx: TCtx,
|
|
40
118
|
): Promise<TCtx> {
|
|
41
|
-
|
|
119
|
+
let hooks: HookFunction<TCtx>[];
|
|
120
|
+
try {
|
|
121
|
+
hooks = await getHooksFor<TCtx>(name);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
log.error(
|
|
124
|
+
{ err, hookName: name },
|
|
125
|
+
"plugin hook discovery failed — proceeding without hooks",
|
|
126
|
+
);
|
|
127
|
+
return initialCtx;
|
|
128
|
+
}
|
|
129
|
+
|
|
42
130
|
let active = initialCtx;
|
|
43
131
|
for (const hook of hooks) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
132
|
+
const draft = cloneHookValue(active);
|
|
133
|
+
try {
|
|
134
|
+
const result = await hook(draft);
|
|
135
|
+
if (result !== undefined) {
|
|
136
|
+
active = { ...draft, ...result };
|
|
137
|
+
} else {
|
|
138
|
+
active = draft;
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
log.error(
|
|
142
|
+
{ err, hookName: name },
|
|
143
|
+
"plugin hook failed — proceeding with current context",
|
|
144
|
+
);
|
|
47
145
|
}
|
|
48
146
|
}
|
|
49
147
|
return active;
|
package/src/plugins/registry.ts
CHANGED
|
@@ -19,11 +19,12 @@
|
|
|
19
19
|
* Design doc: `.private/plans/agent-plugin-system.md`.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { isPluginDisabled } from "./disabled-state.js";
|
|
22
23
|
import { getUserHooksFor } from "./mtime-cache.js";
|
|
23
24
|
import {
|
|
25
|
+
type HookFunction,
|
|
24
26
|
type Plugin,
|
|
25
27
|
PluginExecutionError,
|
|
26
|
-
type PluginHookFn,
|
|
27
28
|
} from "./types.js";
|
|
28
29
|
|
|
29
30
|
// ─── Internal state ──────────────────────────────────────────────────────────
|
|
@@ -35,6 +36,25 @@ import {
|
|
|
35
36
|
*/
|
|
36
37
|
const registeredPlugins = new Map<string, Plugin>();
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Hook registry — the per-surface registry for default plugin hooks. Each
|
|
41
|
+
* hook name maps to an ordered list of `{fn, pluginName}` entries, one per
|
|
42
|
+
* plugin that contributes that hook. The list order matches registration
|
|
43
|
+
* order (i.e. {@link getAllDefaultPlugins} array order), which fixes
|
|
44
|
+
* hook-chain ordering the same way the old `registeredPlugins` map did.
|
|
45
|
+
*
|
|
46
|
+
* Populated by {@link registerPlugin} alongside `registeredPlugins` and
|
|
47
|
+
* depleted by {@link unregisterPlugin}. {@link getHooksFor} reads from this
|
|
48
|
+
* map (not `registeredPlugins`) so it can filter disabled plugins at read
|
|
49
|
+
* time via {@link isPluginDisabled} — the key mechanism that makes
|
|
50
|
+
* `assistant plugins disable default-*` take effect immediately in a
|
|
51
|
+
* running assistant.
|
|
52
|
+
*/
|
|
53
|
+
const hookRegistry = new Map<
|
|
54
|
+
string,
|
|
55
|
+
Array<{ fn: HookFunction; pluginName: string }>
|
|
56
|
+
>();
|
|
57
|
+
|
|
38
58
|
/**
|
|
39
59
|
* Latch that closes the per-boot registration window. Flipped to `true` by
|
|
40
60
|
* {@link closeRegistration} once `loadUserPlugins()` has returned. After that,
|
|
@@ -126,6 +146,22 @@ export function registerPlugin(plugin: Plugin): void {
|
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
registeredPlugins.set(name, plugin);
|
|
149
|
+
|
|
150
|
+
// Register each hook into the per-surface hook registry. `getHooksFor`
|
|
151
|
+
// reads from this map (filtered by `isPluginDisabled`) rather than from
|
|
152
|
+
// `registeredPlugins`, so toggling the `.disabled` sentinel at runtime
|
|
153
|
+
// takes effect on the next turn without mutating the plugin registry.
|
|
154
|
+
if (plugin.hooks) {
|
|
155
|
+
for (const [hookName, fn] of Object.entries(plugin.hooks)) {
|
|
156
|
+
if (typeof fn !== "function") continue;
|
|
157
|
+
let list = hookRegistry.get(hookName);
|
|
158
|
+
if (!list) {
|
|
159
|
+
list = [];
|
|
160
|
+
hookRegistry.set(hookName, list);
|
|
161
|
+
}
|
|
162
|
+
list.push({ fn: fn as HookFunction, pluginName: name });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
129
165
|
}
|
|
130
166
|
|
|
131
167
|
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
@@ -151,20 +187,22 @@ export function getRegisteredPlugins(): Plugin[] {
|
|
|
151
187
|
* files. First-party default plugin hooks are read synchronously from the
|
|
152
188
|
* registry and prepended.
|
|
153
189
|
*
|
|
154
|
-
* The `TCtx` generic mirrors {@link
|
|
190
|
+
* The `TCtx` generic mirrors {@link HookFunction}'s — callers parameterize
|
|
155
191
|
* over the concrete context type their hook receives. Hooks that mutate
|
|
156
192
|
* the context in place return `void`; hooks that return a new context
|
|
157
193
|
* replace the threaded value for the next hook in the chain.
|
|
158
194
|
*/
|
|
159
195
|
export async function getHooksFor<TCtx = unknown>(
|
|
160
196
|
name: string,
|
|
161
|
-
): Promise<
|
|
162
|
-
// First-party defaults from the registry
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
197
|
+
): Promise<HookFunction<TCtx>[]> {
|
|
198
|
+
// First-party defaults from the hook registry, filtered by the `.disabled`
|
|
199
|
+
// sentinel at read time. This is what makes `assistant plugins disable
|
|
200
|
+
// default-*` take effect immediately in a running assistant: the hooks stay
|
|
201
|
+
// registered but are filtered out on the next turn.
|
|
202
|
+
const defaultHooks: HookFunction<TCtx>[] = [];
|
|
203
|
+
for (const entry of hookRegistry.get(name) ?? []) {
|
|
204
|
+
if (!isPluginDisabled(entry.pluginName)) {
|
|
205
|
+
defaultHooks.push(entry.fn as HookFunction<TCtx>);
|
|
168
206
|
}
|
|
169
207
|
}
|
|
170
208
|
|
|
@@ -199,14 +237,18 @@ export function closeRegistration(): void {
|
|
|
199
237
|
*/
|
|
200
238
|
export function unregisterPlugin(name: string): void {
|
|
201
239
|
registeredPlugins.delete(name);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getRegisteredPlugin(name: string): Plugin | undefined {
|
|
205
|
-
return registeredPlugins.get(name);
|
|
206
|
-
}
|
|
207
240
|
|
|
208
|
-
|
|
209
|
-
|
|
241
|
+
// Remove all hooks contributed by this plugin from the hook registry.
|
|
242
|
+
// Used by the bootstrap failure path (init threw) and the feature-flag
|
|
243
|
+
// skip path — both are boot-time decisions where the plugin's hooks should
|
|
244
|
+
// never participate in the turn lifecycle.
|
|
245
|
+
for (const [, list] of hookRegistry) {
|
|
246
|
+
for (let i = list.length - 1; i >= 0; i--) {
|
|
247
|
+
if (list[i]!.pluginName === name) {
|
|
248
|
+
list.splice(i, 1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
210
252
|
}
|
|
211
253
|
|
|
212
254
|
// ─── Test hooks ──────────────────────────────────────────────────────────────
|
|
@@ -228,6 +270,7 @@ export function resetPluginRegistryForTests(): void {
|
|
|
228
270
|
);
|
|
229
271
|
}
|
|
230
272
|
registeredPlugins.clear();
|
|
273
|
+
hookRegistry.clear();
|
|
231
274
|
// Re-open the registration window so subsequent tests can register plugins
|
|
232
275
|
// again. Without this, the latch set by a prior `closeRegistration()` call
|
|
233
276
|
// would leak across test cases and reject legitimate registrations.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared low-level import machinery for user-surface files (plugin tools,
|
|
3
|
+
* plugin hooks, and standalone workspace hooks).
|
|
4
|
+
*
|
|
5
|
+
* Both the plugin/tool cache (`mtime-cache.ts`) and the hook cache
|
|
6
|
+
* (`../hooks/hook-loader.ts`) re-import surface files keyed by mtime. This
|
|
7
|
+
* module owns the pieces they share — mtime stat, the per-process import
|
|
8
|
+
* timeout, and a timeout-guarded, concurrency-deduplicated dynamic import —
|
|
9
|
+
* so neither surface duplicates the logic and the import-timeout knob is
|
|
10
|
+
* configured in exactly one place.
|
|
11
|
+
*
|
|
12
|
+
* Kept dependency-light (only the logger and `importDefault`) so it can sit
|
|
13
|
+
* below both caches without introducing an import cycle.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { statSync } from "node:fs";
|
|
17
|
+
|
|
18
|
+
import { getLogger } from "../util/logger.js";
|
|
19
|
+
import { importDefault } from "./external-plugin-loader.js";
|
|
20
|
+
|
|
21
|
+
const log = getLogger("surface-import");
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Per-process upper bound on how long a single surface import may take.
|
|
25
|
+
* Set once at boot by `populateCacheAtBoot`; read by every re-import. A
|
|
26
|
+
* plugin/hook with a hanging top-level `await` is skipped rather than
|
|
27
|
+
* blocking the daemon.
|
|
28
|
+
*/
|
|
29
|
+
let importTimeoutMs = 10_000;
|
|
30
|
+
|
|
31
|
+
/** Override the surface import timeout (called once at boot). */
|
|
32
|
+
export function setSurfaceImportTimeout(ms: number): void {
|
|
33
|
+
importTimeoutMs = ms;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Current surface import timeout in milliseconds. */
|
|
37
|
+
export function getSurfaceImportTimeout(): number {
|
|
38
|
+
return importTimeoutMs;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the mtimeMs of a file, or 0 if the file doesn't exist or can't be
|
|
43
|
+
* stat'd. Callers treat 0 as "absent" (cache-evict / skip).
|
|
44
|
+
*/
|
|
45
|
+
export function getMtime(filePath: string): number {
|
|
46
|
+
try {
|
|
47
|
+
return statSync(filePath).mtimeMs;
|
|
48
|
+
} catch {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* In-flight import promises, keyed by file path. Prevents duplicate
|
|
55
|
+
* `import()` calls when multiple readers request the same surface
|
|
56
|
+
* concurrently.
|
|
57
|
+
*/
|
|
58
|
+
const inflight = new Map<string, Promise<unknown>>();
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Import a module's default export with a timeout. If the import doesn't
|
|
62
|
+
* resolve within `timeoutMs`, logs a warning and returns `undefined` so a
|
|
63
|
+
* hanging module doesn't block daemon startup indefinitely. Defaults to the
|
|
64
|
+
* module-level {@link getSurfaceImportTimeout}.
|
|
65
|
+
*/
|
|
66
|
+
export async function importWithTimeout<T>(
|
|
67
|
+
filePath: string,
|
|
68
|
+
timeoutMs: number = importTimeoutMs,
|
|
69
|
+
): Promise<T | undefined> {
|
|
70
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
71
|
+
try {
|
|
72
|
+
const timeoutSentinel = Symbol("import-timeout");
|
|
73
|
+
const importPromise = importWithDedup<T>(filePath);
|
|
74
|
+
const timeoutPromise = new Promise<typeof timeoutSentinel>((resolve) => {
|
|
75
|
+
timeoutHandle = setTimeout(() => resolve(timeoutSentinel), timeoutMs);
|
|
76
|
+
});
|
|
77
|
+
const result = await Promise.race([importPromise, timeoutPromise]);
|
|
78
|
+
if (result === timeoutSentinel) {
|
|
79
|
+
importPromise.catch(() => {
|
|
80
|
+
/* swallow — late rejection from abandoned import */
|
|
81
|
+
});
|
|
82
|
+
log.warn(
|
|
83
|
+
{ filePath, timeoutMs },
|
|
84
|
+
`Import timed out after ${timeoutMs}ms — skipping surface`,
|
|
85
|
+
);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
return result as T;
|
|
89
|
+
} finally {
|
|
90
|
+
if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Import a module's default export, deduplicating concurrent imports for
|
|
96
|
+
* the same file path. This prevents two readers from triggering duplicate
|
|
97
|
+
* `import()` calls when they request the same surface simultaneously.
|
|
98
|
+
*
|
|
99
|
+
* Note: Bun caches `import()` by resolved path within a process and does not
|
|
100
|
+
* bust on query-string or hash changes, so the dedup is about avoiding
|
|
101
|
+
* redundant async work, not cache-busting. A content edit to an existing
|
|
102
|
+
* file is only picked up after a process restart (added and removed files
|
|
103
|
+
* are picked up live, since discovery is by directory listing).
|
|
104
|
+
*/
|
|
105
|
+
async function importWithDedup<T>(filePath: string): Promise<T> {
|
|
106
|
+
let promise = inflight.get(filePath);
|
|
107
|
+
if (promise === undefined) {
|
|
108
|
+
promise = importDefault<T>(filePath);
|
|
109
|
+
inflight.set(filePath, promise);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
return (await promise) as T;
|
|
113
|
+
} finally {
|
|
114
|
+
inflight.delete(filePath);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Clear in-flight import state. Test-only. */
|
|
119
|
+
export function clearSurfaceImportInflight(): void {
|
|
120
|
+
inflight.clear();
|
|
121
|
+
}
|
package/src/plugins/types.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
} from "../daemon/conversation-runtime-assembly.js";
|
|
20
20
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
21
21
|
import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
22
|
-
import type {
|
|
22
|
+
import type { HookFunction } from "../plugin-api/types.js";
|
|
23
23
|
import type { Message } from "../providers/types.js";
|
|
24
24
|
import type { SkillRoute } from "../runtime/skill-route-registry.js";
|
|
25
25
|
import type { Tool } from "../tools/types.js";
|
|
@@ -47,8 +47,6 @@ export interface PluginManifest {
|
|
|
47
47
|
* own version at load time.
|
|
48
48
|
*/
|
|
49
49
|
version: string;
|
|
50
|
-
/** Credential keys the plugin needs resolved before `init()` runs. */
|
|
51
|
-
requiresCredential?: string[];
|
|
52
50
|
/**
|
|
53
51
|
* Assistant feature-flag keys that must all be enabled for this plugin to
|
|
54
52
|
* activate. Checked by `bootstrapPlugins` via `isAssistantFeatureFlagEnabled`
|
|
@@ -69,9 +67,9 @@ export interface PluginManifest {
|
|
|
69
67
|
// existing internal call sites keep working. Plugin authors import these from
|
|
70
68
|
// `@vellumai/plugin-api`.
|
|
71
69
|
export type {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
HookFunction,
|
|
71
|
+
InitContext,
|
|
72
|
+
ShutdownContext,
|
|
75
73
|
} from "../plugin-api/types.js";
|
|
76
74
|
|
|
77
75
|
// ─── Memory-graph result ─────────────────────────────────────────────────────
|
|
@@ -345,14 +343,14 @@ export type PluginRouteRegistration = SkillRoute;
|
|
|
345
343
|
* unknown keys are forward-compat scaffolding.
|
|
346
344
|
*
|
|
347
345
|
* See `assistant/src/daemon/external-plugins-bootstrap.ts` for the
|
|
348
|
-
* full lifecycle, and {@link
|
|
346
|
+
* full lifecycle, and {@link HookFunction} for the per-entry signature.
|
|
349
347
|
*/
|
|
350
348
|
// The map stores hooks for arbitrary keys with arbitrary context shapes.
|
|
351
349
|
// `any` (rather than `unknown`) is required so concrete plugin signatures
|
|
352
|
-
// like `(ctx:
|
|
350
|
+
// like `(ctx: InitContext) => Promise<void>` and `() => Promise<void>`
|
|
353
351
|
// both assign in/out of slot entries under strict-function-types contravariance.
|
|
354
352
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
355
|
-
export type PluginHooks = Record<string,
|
|
353
|
+
export type PluginHooks = Record<string, HookFunction<any>>;
|
|
356
354
|
|
|
357
355
|
/**
|
|
358
356
|
* A registered plugin. Every field besides `manifest` is optional — a plugin
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
3
|
|
|
4
|
+
import type { GuardianDelivery } from "@vellumai/gateway-client";
|
|
5
|
+
|
|
6
|
+
import { findContactByAddress } from "../contacts/contact-store.js";
|
|
4
7
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "../contacts/
|
|
8
|
+
anyGuardian,
|
|
9
|
+
guardianForChannel,
|
|
10
|
+
peekCachedGuardianDelivery,
|
|
11
|
+
} from "../contacts/guardian-delivery-reader.js";
|
|
9
12
|
import type { ChannelCapabilities } from "../daemon/conversation-runtime-assembly.js";
|
|
10
13
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
11
14
|
import { getLogger } from "../util/logger.js";
|
|
@@ -87,8 +90,38 @@ function resolveGuardianUserFile(trustContext: TrustContext): string | null {
|
|
|
87
90
|
return guardianContact.userFile ?? "guardian.md";
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
|
-
const guardian =
|
|
91
|
-
return guardian ? (guardian
|
|
93
|
+
const guardian = peekGuardianForChannel(trustContext.sourceChannel);
|
|
94
|
+
return guardian ? (guardianDeliveryUserFile(guardian) ?? "guardian.md") : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the local INFO `userFile` for a gateway guardian delivery. The
|
|
99
|
+
* gateway carries identity (channel + address) but not local INFO, so we join
|
|
100
|
+
* the local contact by the guardian's channel address. Returns `undefined` when
|
|
101
|
+
* no local contact matches.
|
|
102
|
+
*/
|
|
103
|
+
function guardianDeliveryUserFile(
|
|
104
|
+
guardian: GuardianDelivery,
|
|
105
|
+
): string | undefined {
|
|
106
|
+
const contact = findContactByAddress(
|
|
107
|
+
guardian.channelType,
|
|
108
|
+
guardian.address,
|
|
109
|
+
);
|
|
110
|
+
return contact?.userFile ?? undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Active guardian for a channel from the IO-free delivery cache. */
|
|
114
|
+
function peekGuardianForChannel(
|
|
115
|
+
channelType: string,
|
|
116
|
+
): GuardianDelivery | undefined {
|
|
117
|
+
const cached = peekCachedGuardianDelivery({ channelTypes: [channelType] });
|
|
118
|
+
return cached ? guardianForChannel(cached, channelType) : undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** First guardian across all channels from the IO-free delivery cache. */
|
|
122
|
+
function peekAnyGuardian(): GuardianDelivery | undefined {
|
|
123
|
+
const cached = peekCachedGuardianDelivery();
|
|
124
|
+
return cached ? anyGuardian(cached) : undefined;
|
|
92
125
|
}
|
|
93
126
|
|
|
94
127
|
/**
|
|
@@ -102,12 +135,11 @@ function resolveUserFilename(
|
|
|
102
135
|
|
|
103
136
|
try {
|
|
104
137
|
if (trustContext === undefined) {
|
|
105
|
-
// Desktop / native
|
|
106
|
-
// preferring the vellum-channel guardian
|
|
107
|
-
const
|
|
108
|
-
const guardian = vellumGuardian ?? listGuardianChannels();
|
|
138
|
+
// Desktop / native — resolve via the gateway guardian delivery cache,
|
|
139
|
+
// preferring the vellum-channel guardian, then any guardian.
|
|
140
|
+
const guardian = peekGuardianForChannel("vellum") ?? peekAnyGuardian();
|
|
109
141
|
if (guardian) {
|
|
110
|
-
filename = guardian
|
|
142
|
+
filename = guardianDeliveryUserFile(guardian) ?? "guardian.md";
|
|
111
143
|
}
|
|
112
144
|
} else if (trustContext.requesterExternalUserId) {
|
|
113
145
|
// Channel-routed request — look up contact by channel identity
|
|
@@ -786,6 +786,11 @@ export class AnthropicProvider implements Provider {
|
|
|
786
786
|
this.useNativeWebSearch = options.useNativeWebSearch ?? false;
|
|
787
787
|
}
|
|
788
788
|
|
|
789
|
+
/** See {@link Provider.supportsNativeWebSearch}. */
|
|
790
|
+
get supportsNativeWebSearch(): boolean {
|
|
791
|
+
return this.useNativeWebSearch;
|
|
792
|
+
}
|
|
793
|
+
|
|
789
794
|
async sendMessage(
|
|
790
795
|
messages: Message[],
|
|
791
796
|
options?: SendMessageOptions,
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
} from "./connection-resolution.js";
|
|
35
35
|
import { listConnections } from "./inference/connections.js";
|
|
36
36
|
import type { ProvidersConfig } from "./registry.js";
|
|
37
|
+
import { shouldUseNativeWebSearch } from "./registry.js";
|
|
37
38
|
import type {
|
|
38
39
|
Message,
|
|
39
40
|
Provider,
|
|
@@ -43,6 +44,9 @@ import type {
|
|
|
43
44
|
|
|
44
45
|
export class CallSiteRoutingProvider implements Provider {
|
|
45
46
|
public readonly tokenEstimationProvider?: string;
|
|
47
|
+
// Forward native web-search capability so it survives the wrapper chain
|
|
48
|
+
// (callers like the advisor consult gate on it). Fixed at construction.
|
|
49
|
+
public readonly supportsNativeWebSearch?: boolean;
|
|
46
50
|
|
|
47
51
|
// Per-call async context that tracks which provider is currently executing.
|
|
48
52
|
// Using AsyncLocalStorage instead of a plain instance field means concurrent
|
|
@@ -94,6 +98,7 @@ export class CallSiteRoutingProvider implements Provider {
|
|
|
94
98
|
) => Promise<Provider | null>,
|
|
95
99
|
) {
|
|
96
100
|
this.tokenEstimationProvider = defaultProvider.tokenEstimationProvider;
|
|
101
|
+
this.supportsNativeWebSearch = defaultProvider.supportsNativeWebSearch;
|
|
97
102
|
if (defaultProvider.countInputTokens) {
|
|
98
103
|
this.countInputTokens =
|
|
99
104
|
defaultProvider.countInputTokens.bind(defaultProvider);
|
|
@@ -126,6 +131,46 @@ export class CallSiteRoutingProvider implements Provider {
|
|
|
126
131
|
: doSend();
|
|
127
132
|
}
|
|
128
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Native web-search capability of the provider/model THIS call routes to.
|
|
136
|
+
*
|
|
137
|
+
* `selectProvider` picks the transport from the routed connection, but each
|
|
138
|
+
* leaf provider's static `supportsNativeWebSearch` was fixed to the DEFAULT
|
|
139
|
+
* (provider, model) at boot. Resolving the call-site here — same
|
|
140
|
+
* `resolveCallSiteConfig` inputs `selectProvider` uses — and recomputing
|
|
141
|
+
* `shouldUseNativeWebSearch(resolved.provider, resolved.model)` yields the
|
|
142
|
+
* capability of the routed target instead of the construction-time default.
|
|
143
|
+
*
|
|
144
|
+
* Falls back to the default provider's static flag when no `callSite` is set
|
|
145
|
+
* (the legacy short-circuit `selectProvider` also takes).
|
|
146
|
+
*
|
|
147
|
+
* Known limitation: this reports the *resolved* target's capability and does
|
|
148
|
+
* not replay `selectProvider`'s async soft-credential fallback. If the routed
|
|
149
|
+
* connection has a transient credential failure at send time, `selectProvider`
|
|
150
|
+
* falls back to the default provider while this probe still reports the routed
|
|
151
|
+
* target — so a non-native default + native routed target with a credential
|
|
152
|
+
* blip can attach `web_search` to the fallback non-native provider. The probe
|
|
153
|
+
* stays sync (the loop assembles tools synchronously) and the worst case is
|
|
154
|
+
* bounded: the advisor consult that hits it degrades benignly (the unhandled
|
|
155
|
+
* tool surfaces as a caught failure → "(advisor unavailable)"), not a crash.
|
|
156
|
+
*/
|
|
157
|
+
supportsNativeWebSearchFor(options?: SendMessageOptions): boolean {
|
|
158
|
+
const callSite = options?.config?.callSite;
|
|
159
|
+
if (!callSite) {
|
|
160
|
+
return this.defaultProvider.supportsNativeWebSearch === true;
|
|
161
|
+
}
|
|
162
|
+
const resolved = resolveCallSiteConfig(callSite, getConfig().llm, {
|
|
163
|
+
overrideProfile: options?.config?.overrideProfile,
|
|
164
|
+
forceOverrideProfile: options?.config?.forceOverrideProfile,
|
|
165
|
+
selectionSeed: options?.config?.selectionSeed,
|
|
166
|
+
});
|
|
167
|
+
return shouldUseNativeWebSearch(
|
|
168
|
+
getConfig(),
|
|
169
|
+
resolved.provider,
|
|
170
|
+
resolved.model,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
129
174
|
/**
|
|
130
175
|
* Pick the provider to route this call through.
|
|
131
176
|
*
|
|
@@ -760,6 +760,22 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
760
760
|
maxEffort: "max",
|
|
761
761
|
pricing: { inputPer1mTokens: 1.74, outputPer1mTokens: 3.48 },
|
|
762
762
|
},
|
|
763
|
+
{
|
|
764
|
+
id: "accounts/fireworks/models/deepseek-v4-flash",
|
|
765
|
+
displayName: "DeepSeek V4 Flash",
|
|
766
|
+
contextWindowTokens: 1040000,
|
|
767
|
+
maxOutputTokens: 131072,
|
|
768
|
+
supportsThinking: true,
|
|
769
|
+
supportsCaching: true,
|
|
770
|
+
supportsVision: false,
|
|
771
|
+
supportsToolUse: true,
|
|
772
|
+
maxEffort: "max",
|
|
773
|
+
pricing: {
|
|
774
|
+
inputPer1mTokens: 0.14,
|
|
775
|
+
outputPer1mTokens: 0.28,
|
|
776
|
+
cacheReadPer1mTokens: 0.03,
|
|
777
|
+
},
|
|
778
|
+
},
|
|
763
779
|
],
|
|
764
780
|
defaultModel: "accounts/fireworks/models/kimi-k2p5",
|
|
765
781
|
apiKeyUrl: "https://fireworks.ai/account/api-keys",
|