@vellumai/assistant 0.11.4 → 0.11.5-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/ARCHITECTURE.md +29 -4
- package/README.md +1 -1
- package/docs/architecture/memory.md +17 -5
- package/docs/architecture/security.md +96 -152
- package/docs/guardian-request-flow.md +13 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +7 -14
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +29 -31
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +193 -3
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +10 -3
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +4 -0
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -6
- package/src/__tests__/channel-reply-delivery.test.ts +26 -13
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/client-os-metadata-persistence.test.ts +16 -0
- package/src/__tests__/compactor-retained-image-validation.test.ts +142 -0
- package/src/__tests__/container-cpu-sampler.test.ts +153 -0
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +17 -0
- package/src/__tests__/conversation-lifecycle.test.ts +20 -26
- package/src/__tests__/conversation-pairing.test.ts +186 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
- package/src/__tests__/credential-broker-server-use.test.ts +24 -5
- package/src/__tests__/credential-routes.test.ts +22 -3
- package/src/__tests__/credential-security-invariants.test.ts +2 -1
- package/src/__tests__/daemon-credential-client.test.ts +88 -0
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/dm-backfill.test.ts +63 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -4
- package/src/__tests__/events-client-registration.test.ts +28 -0
- package/src/__tests__/file-write-tool.test.ts +4 -2
- package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/host-proxy-interface.test.ts +11 -1
- package/src/__tests__/host-shell-tool.test.ts +23 -4
- package/src/__tests__/image-conversion.test.ts +143 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/input-repairs.test.ts +207 -0
- package/src/__tests__/live-workspace-guard.test.ts +75 -0
- package/src/__tests__/mcp-abort-signal.test.ts +1 -1
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
- package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
- package/src/__tests__/mtime-cache.test.ts +2 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
- package/src/__tests__/openai-provider.test.ts +22 -0
- package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/platform.test.ts +16 -1
- package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
- package/src/__tests__/plugin-api-shim.test.ts +5 -0
- package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
- package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/resource-pressure-guard.test.ts +428 -0
- package/src/__tests__/resource-pressure-routes.test.ts +113 -0
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
- package/src/__tests__/skill-tool-factory.test.ts +161 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +63 -38
- package/src/__tests__/tool-policy.test.ts +97 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
- package/src/__tests__/user-plugin-loader.test.ts +2 -0
- package/src/__tests__/validate-input.test.ts +243 -7
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
- package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
- package/src/acp/acp-claude-oauth.ts +38 -21
- package/src/acp/prepare-agent-env.ts +146 -55
- package/src/agent/loop-tool-dedup.test.ts +161 -0
- package/src/agent/loop.ts +68 -22
- package/src/api/constants/app-tools.ts +34 -0
- package/src/api/events/resource-pressure-status-changed.ts +53 -0
- package/src/api/index.ts +19 -0
- package/src/api/responses/resource-pressure-status.ts +25 -0
- package/src/approvals/guardian-channel-delivery.ts +70 -6
- package/src/approvals/guardian-request-resolvers.ts +32 -66
- package/src/channels/__tests__/message-audience.test.ts +49 -0
- package/src/channels/__tests__/types.test.ts +17 -3
- package/src/channels/message-audience.ts +40 -0
- package/src/channels/types.ts +16 -12
- package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
- package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
- package/src/cli/commands/__tests__/keys.test.ts +89 -8
- package/src/cli/commands/__tests__/plugins.test.ts +57 -1
- package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
- package/src/cli/commands/channel-verification-sessions.ts +11 -21
- package/src/cli/commands/conversations.help.ts +34 -0
- package/src/cli/commands/conversations.ts +125 -0
- package/src/cli/commands/inference-providers.ts +9 -4
- package/src/cli/commands/inference.help.ts +9 -4
- package/src/cli/commands/keys.help.ts +13 -1
- package/src/cli/commands/keys.ts +26 -15
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/index.help.ts +41 -27
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/monitoring.ts +1 -0
- package/src/cli/commands/plugins.help.ts +28 -31
- package/src/cli/commands/plugins.ts +10 -0
- package/src/cli/commands/skills.help.ts +13 -16
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
- package/src/cli/lib/bundled-marketplace.json +13 -0
- package/src/cli/lib/daemon-credential-client.ts +25 -3
- package/src/cli/lib/install-from-github.ts +35 -24
- package/src/cli/lib/merge-plugin-tree.ts +22 -4
- package/src/cli/lib/plugin-surfaces.ts +27 -0
- package/src/config/feature-flag-registry.json +35 -19
- package/src/config/webhook-routing.ts +8 -0
- package/src/context/compactor.ts +31 -2
- package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
- package/src/daemon/conversation-error.ts +13 -0
- package/src/daemon/conversation-messaging.ts +22 -2
- package/src/daemon/conversation-process.ts +11 -0
- package/src/daemon/conversation-store.ts +10 -0
- package/src/daemon/conversation-surfaces.ts +21 -8
- package/src/daemon/conversation.ts +12 -10
- package/src/daemon/lifecycle.ts +6 -2
- package/src/daemon/message-types/conversations.ts +5 -7
- package/src/daemon/provider-rejection-log-fields.ts +124 -0
- package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
- package/src/daemon/resource-pressure-guard.ts +387 -0
- package/src/daemon/shutdown-handlers.ts +2 -0
- package/src/daemon/startup-error.ts +16 -0
- package/src/daemon/trust-context.ts +14 -10
- package/src/daemon/unsendable-image-notice.ts +76 -0
- package/src/hooks/registry.ts +65 -51
- package/src/ipc/__tests__/socket-path.test.ts +15 -7
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/socket-cleanup.ts +2 -11
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
- package/src/messaging/provider-message-metadata.ts +128 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
- package/src/messaging/providers/channel-transport.ts +90 -13
- package/src/messaging/providers/discord/send.ts +16 -0
- package/src/messaging/providers/discord/transport.ts +11 -1
- package/src/messaging/providers/index.ts +109 -16
- package/src/messaging/providers/slack/message-metadata.ts +45 -0
- package/src/messaging/providers/slack/render-transcript.ts +1 -4
- package/src/messaging/providers/slack/send.test.ts +6 -9
- package/src/messaging/providers/slack/send.ts +40 -28
- package/src/messaging/providers/slack/transport.ts +22 -26
- package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
- package/src/messaging/providers/telegram-bot/transport.ts +3 -6
- package/src/messaging/read-provider-metadata.test.ts +157 -0
- package/src/messaging/read-provider-metadata.ts +51 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
- package/src/notifications/__tests__/edit-notification.test.ts +174 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
- package/src/notifications/adapters/macos.ts +55 -0
- package/src/notifications/adapters/slack.ts +10 -5
- package/src/notifications/assistant-reply-producer.ts +37 -4
- package/src/notifications/conversation-pairing.ts +111 -21
- package/src/notifications/edit-notification.ts +38 -8
- package/src/notifications/emit-signal.ts +12 -14
- package/src/notifications/home-feed-side-effect.ts +218 -15
- package/src/notifications/types.ts +5 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +28 -3
- package/src/permissions/confirmation-guardian-request.ts +5 -1
- package/src/persistence/conversation-crud.ts +23 -20
- package/src/persistence/conversation-queries.ts +14 -1
- package/src/persistence/conversation-types.ts +22 -0
- package/src/persistence/delivery-crud.ts +122 -15
- package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
- package/src/plugin-api/conversation-turn.ts +27 -0
- package/src/plugin-api/credential-scope.test.ts +15 -0
- package/src/plugin-api/credential-scope.ts +14 -0
- package/src/plugin-api/index.ts +19 -1
- package/src/plugin-api/resolve-credential.ts +15 -10
- package/src/plugin-api/store-credential.ts +148 -0
- package/src/plugin-api/system-card.ts +36 -0
- package/src/plugin-api/vision-support.test.ts +82 -0
- package/src/plugin-api/vision-support.ts +14 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
- package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
- package/src/plugins/defaults/image-recovery/detect.ts +24 -1
- package/src/plugins/defaults/main.ts +15 -0
- package/src/plugins/defaults/memory/AGENTS.md +11 -3
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/mtime-cache.ts +1 -1
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/plugin-tree-walk.ts +63 -4
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/connection-resolution.ts +2 -1
- package/src/providers/content-blocks.ts +22 -0
- package/src/providers/gemini/client.ts +5 -2
- package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
- package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
- package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
- package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
- package/src/providers/inference/adapter-factory.ts +33 -2
- package/src/providers/inference/auth.ts +13 -2
- package/src/providers/inference/credential-usage.ts +37 -0
- package/src/providers/inference/missing-credential-guard.ts +110 -0
- package/src/providers/inference/resolve-auth.ts +7 -7
- package/src/providers/media-resolve.ts +176 -15
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +322 -42
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +31 -10
- package/src/runtime/AGENTS.md +35 -0
- package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
- package/src/runtime/__tests__/web-presence.test.ts +234 -0
- package/src/runtime/assistant-event-hub.ts +38 -0
- package/src/runtime/channel-reply-delivery.ts +54 -31
- package/src/runtime/channel-retry-sweep.ts +6 -4
- package/src/runtime/effective-capabilities.test.ts +19 -0
- package/src/runtime/effective-capabilities.ts +25 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/http-errors.ts +1 -0
- package/src/runtime/http-server.ts +20 -5
- package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
- package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
- package/src/runtime/routes/approval-routes.ts +37 -4
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
- package/src/runtime/routes/canned-message-complete.ts +68 -29
- package/src/runtime/routes/client-routes.ts +113 -0
- package/src/runtime/routes/conversation-list-routes.ts +22 -7
- package/src/runtime/routes/conversation-management-routes.ts +15 -9
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-in-use.ts +85 -0
- package/src/runtime/routes/credential-routes.ts +55 -85
- package/src/runtime/routes/guardian-approval-interception.ts +22 -22
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
- package/src/runtime/routes/identity-routes.ts +5 -121
- package/src/runtime/routes/inbound-message-handler.ts +71 -27
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
- package/src/runtime/routes/monitoring-routes.ts +9 -1
- package/src/runtime/routes/plugins-routes.ts +17 -5
- package/src/runtime/routes/resource-pressure-routes.ts +22 -0
- package/src/runtime/routes/secret-routes.ts +39 -8
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/user-route-dispatcher.ts +31 -2
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/slack-reply-session.test.ts +23 -13
- package/src/runtime/slack-reply-session.ts +38 -55
- package/src/runtime/web-presence.ts +90 -0
- package/src/skills/validate-input.ts +177 -40
- package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
- package/src/subagent/consult-context.ts +7 -23
- package/src/tools/credentials/broker.ts +24 -79
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/credentials/tool-policy.ts +67 -0
- package/src/tools/executor.ts +53 -15
- package/src/tools/network/__tests__/web-search.test.ts +41 -1
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/network/web-search.ts +21 -3
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/schema-transforms.ts +40 -5
- package/src/tools/shared/input-repairs.ts +160 -0
- package/src/tools/skills/skill-tool-factory.ts +18 -4
- package/src/tools/subagent/spawn.ts +0 -1
- package/src/tools/tool-approval-handler.ts +16 -10
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/util/__tests__/cgroup-memory.test.ts +3 -0
- package/src/util/cgroup-memory.ts +3 -0
- package/src/util/container-cpu-sampler.ts +250 -0
- package/src/util/image-conversion.ts +178 -14
- package/src/util/platform.ts +93 -10
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
|
@@ -9,18 +9,20 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ## Plugin scoping
|
|
11
11
|
*
|
|
12
|
-
* When a plugin is in context
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* the plugin
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* When a plugin is in context (its hook, tool, or one of its own
|
|
13
|
+
* `/x/plugins/<name>/` routes is executing, tracked by
|
|
14
|
+
* {@link ../plugins/plugin-execution-context.getCurrentPluginName}), resolution
|
|
15
|
+
* is restricted: the plugin may only resolve credentials whose `service`
|
|
16
|
+
* equals its manifest name (`imessage/api_key` for plugin `imessage`). It
|
|
17
|
+
* cannot read another service (`openai/api_key`, `openai/imessage`). Outside
|
|
18
|
+
* any plugin context (host-internal callers, CLI, tests) the resolver is
|
|
19
|
+
* unscoped and behaves like a direct reveal.
|
|
19
20
|
*/
|
|
20
21
|
|
|
21
22
|
import { getCurrentPluginName } from "../plugins/plugin-execution-context.js";
|
|
22
23
|
import { getSecureKeyResultAsync } from "../security/secure-keys.js";
|
|
23
24
|
import { resolveCredentialRef } from "../tools/credentials/resolve.js";
|
|
25
|
+
import { credentialInPluginScope } from "./credential-scope.js";
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* Raised when a credential cannot be resolved: the reference does not match a
|
|
@@ -48,13 +50,16 @@ export async function resolveCredential(ref: string): Promise<string> {
|
|
|
48
50
|
throw new CredentialResolutionError(`Credential not found: ${ref}`);
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
// Scope the resolution to the plugin in context, if any. The
|
|
53
|
+
// Scope the resolution to the plugin in context, if any. The ownership gate
|
|
52
54
|
// is enforced before the plaintext is read so an out-of-scope plugin never
|
|
53
55
|
// touches the secure backend.
|
|
54
56
|
const pluginName = getCurrentPluginName();
|
|
55
|
-
if (
|
|
57
|
+
if (
|
|
58
|
+
pluginName !== undefined &&
|
|
59
|
+
!credentialInPluginScope(pluginName, resolved.service)
|
|
60
|
+
) {
|
|
56
61
|
throw new CredentialResolutionError(
|
|
57
|
-
`Plugin "${pluginName}" may only resolve credentials
|
|
62
|
+
`Plugin "${pluginName}" may only resolve credentials under its own service; ` +
|
|
58
63
|
`"${resolved.service}/${resolved.field}" is out of scope.`,
|
|
59
64
|
);
|
|
60
65
|
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin-facing credential storage.
|
|
3
|
+
*
|
|
4
|
+
* {@link storeCredential} writes a credential's plaintext to the secure store,
|
|
5
|
+
* the same write `assistant credentials set` performs, naming it either by an
|
|
6
|
+
* existing credential's UUID or by a `"service/field"` string, the same
|
|
7
|
+
* vocabulary {@link ./resolve-credential.resolveCredential} reads back. A
|
|
8
|
+
* plugin that obtains a token for itself (an OAuth exchange it drives, a key a
|
|
9
|
+
* user hands it through its own route) persists it here instead of inventing
|
|
10
|
+
* its own on-disk secret file.
|
|
11
|
+
*
|
|
12
|
+
* ## Plugin scoping
|
|
13
|
+
*
|
|
14
|
+
* A plugin may only write credentials whose `service` equals its manifest
|
|
15
|
+
* name (`imessage/api_key` for plugin `imessage`). It cannot write another
|
|
16
|
+
* service (`openai/api_key`, `openai/imessage`). The name comes from the
|
|
17
|
+
* execution context
|
|
18
|
+
* ({@link ../plugins/plugin-execution-context.getCurrentPluginName}), which the
|
|
19
|
+
* host establishes around a plugin's hook, tool, and route invocations.
|
|
20
|
+
*
|
|
21
|
+
* Unlike the read path, this **fails closed**: with no plugin in context there
|
|
22
|
+
* is nobody to scope the write to, so it is refused rather than treated as an
|
|
23
|
+
* unscoped host write. A plugin's module body is evaluated by the loader
|
|
24
|
+
* outside any context, and an unscoped branch there would let top-level code
|
|
25
|
+
* overwrite the user's own credentials. Host-internal callers that legitimately
|
|
26
|
+
* write unscoped (the `credentials/set` route, the CLI behind it) compose
|
|
27
|
+
* {@link ../tools/credentials/store.storeCredentialValue} directly. This
|
|
28
|
+
* matches the plugin-owned index (`indexDocument`), which likewise requires a
|
|
29
|
+
* context because a write with no owner has nothing to attribute.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { getCurrentPluginName } from "../plugins/plugin-execution-context.js";
|
|
33
|
+
import { parseServiceFieldRef } from "../tools/credentials/ref-parse.js";
|
|
34
|
+
import { resolveCredentialRef } from "../tools/credentials/resolve.js";
|
|
35
|
+
import { storeCredentialValue } from "../tools/credentials/store.js";
|
|
36
|
+
import { credentialInPluginScope } from "./credential-scope.js";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Raised when a credential cannot be stored: the reference is malformed, the
|
|
40
|
+
* value is empty or invalid for its service, the secure backend rejected the
|
|
41
|
+
* write, or the calling plugin is not permitted to write the credential.
|
|
42
|
+
*/
|
|
43
|
+
export class CredentialStoreError extends Error {
|
|
44
|
+
constructor(message: string) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "CredentialStoreError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface StoreCredentialOptions {
|
|
51
|
+
/** Human-friendly alias shown in credential listings. */
|
|
52
|
+
label?: string;
|
|
53
|
+
/** What the credential is for, surfaced to the agent. */
|
|
54
|
+
description?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Skip the retroactive sweep that removes the value from recent transcripts.
|
|
57
|
+
* The sweep exists because a secret is often pasted into chat before it is
|
|
58
|
+
* stored; pass `true` only for a value that provably never transited a
|
|
59
|
+
* conversation, such as a token minted by an OAuth refresh.
|
|
60
|
+
*/
|
|
61
|
+
skipTranscriptScrub?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Identity of the credential that was written. */
|
|
65
|
+
export interface StoredCredentialRef {
|
|
66
|
+
credentialId: string;
|
|
67
|
+
service: string;
|
|
68
|
+
field: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Store a credential's plaintext value, creating it or replacing the value of
|
|
73
|
+
* an existing one.
|
|
74
|
+
*
|
|
75
|
+
* @param ref A credential UUID (an existing credential) or a `"service/field"`
|
|
76
|
+
* string (created when no such credential exists).
|
|
77
|
+
* @param value The plaintext value. Edge whitespace is trimmed.
|
|
78
|
+
* @returns The identity of the stored credential, which
|
|
79
|
+
* {@link ./resolve-credential.resolveCredential} accepts as a ref.
|
|
80
|
+
* @throws {CredentialStoreError} when no plugin is in context, the ref is
|
|
81
|
+
* malformed or names no credential, the value is empty or invalid for its
|
|
82
|
+
* service, the store rejects the write, or the calling plugin is not scoped
|
|
83
|
+
* to the credential.
|
|
84
|
+
*/
|
|
85
|
+
export async function storeCredential(
|
|
86
|
+
ref: string,
|
|
87
|
+
value: string,
|
|
88
|
+
options: StoreCredentialOptions = {},
|
|
89
|
+
): Promise<StoredCredentialRef> {
|
|
90
|
+
// Both gates run before anything is written, so a refused write never
|
|
91
|
+
// touches the secure backend. Fail closed when there is no plugin to scope
|
|
92
|
+
// to: a plugin's module body is evaluated outside any context, and an
|
|
93
|
+
// unscoped branch there would be a way to overwrite the user's credentials.
|
|
94
|
+
const pluginName = getCurrentPluginName();
|
|
95
|
+
if (pluginName === undefined) {
|
|
96
|
+
throw new CredentialStoreError(
|
|
97
|
+
"storeCredential requires an active plugin execution context (no calling plugin found). " +
|
|
98
|
+
"Call it from a hook, tool, or route handler rather than at module scope.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const target = resolveStoreTarget(ref);
|
|
103
|
+
if (!credentialInPluginScope(pluginName, target.service)) {
|
|
104
|
+
throw new CredentialStoreError(
|
|
105
|
+
`Plugin "${pluginName}" may only store credentials under its own service; ` +
|
|
106
|
+
`"${target.service}/${target.field}" is out of scope.`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
return await storeCredentialValue({
|
|
112
|
+
service: target.service,
|
|
113
|
+
field: target.field,
|
|
114
|
+
value,
|
|
115
|
+
alias: options.label,
|
|
116
|
+
usageDescription: options.description,
|
|
117
|
+
skipTranscriptScrub: options.skipTranscriptScrub,
|
|
118
|
+
});
|
|
119
|
+
} catch (err) {
|
|
120
|
+
throw new CredentialStoreError(
|
|
121
|
+
err instanceof Error ? err.message : String(err),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolve the `ref` a write targets. An existing credential (by UUID or by
|
|
128
|
+
* `"service/field"`) keeps its identity; otherwise the ref must name the
|
|
129
|
+
* service and field of the credential to create, which a bare UUID cannot.
|
|
130
|
+
*/
|
|
131
|
+
function resolveStoreTarget(ref: string): { service: string; field: string } {
|
|
132
|
+
if (!ref || ref.trim().length === 0) {
|
|
133
|
+
throw new CredentialStoreError("Credential reference is required");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const existing = resolveCredentialRef(ref);
|
|
137
|
+
if (existing) {
|
|
138
|
+
return { service: existing.service, field: existing.field };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const parsed = parseServiceFieldRef(ref);
|
|
142
|
+
if (!parsed) {
|
|
143
|
+
throw new CredentialStoreError(
|
|
144
|
+
`Cannot store credential: "${ref}" matches no stored credential and is not a "service/field" reference`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return parsed;
|
|
148
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin-facing facade over the host's system-card writer: a daemon-authored
|
|
3
|
+
* transcript notice, persisted as an assistant row stamped
|
|
4
|
+
* `messageKind: "system_card"` so clients render it as a standalone system
|
|
5
|
+
* notice rather than assistant-persona speech. Plugins use it to tell the user
|
|
6
|
+
* about something the turn did to their input that the model's own reply
|
|
7
|
+
* cannot explain (e.g. an attachment the turn could not send).
|
|
8
|
+
*
|
|
9
|
+
* The writer is loaded through a dynamic `import()` inside the wrapper, for the
|
|
10
|
+
* same reason `persistence/conversation-plugin-facade.ts` does: it carries the
|
|
11
|
+
* DB/drizzle import graph, whose named exports must not be forced to resolve
|
|
12
|
+
* merely because a plugin imported `@vellumai/plugin-api`. Suites that
|
|
13
|
+
* partial-mock a module in that graph would otherwise fail to instantiate.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Persist a system card in a conversation's transcript and announce it to
|
|
18
|
+
* connected clients through the sync invalidation that drives a refetch.
|
|
19
|
+
* Returns the persisted message id.
|
|
20
|
+
*
|
|
21
|
+
* A plugin card is non-terminal: it never emits `message_complete`, so a card
|
|
22
|
+
* written from a hook that runs inside a turn leaves that turn's streaming and
|
|
23
|
+
* processing state untouched. It is also not appended to the conversation's
|
|
24
|
+
* in-memory working history, so it cannot leave a trailing assistant message
|
|
25
|
+
* for the turn's next provider call to continue from.
|
|
26
|
+
*/
|
|
27
|
+
export async function persistSystemCard(opts: {
|
|
28
|
+
conversationId: string;
|
|
29
|
+
text: string;
|
|
30
|
+
metadata: Record<string, unknown>;
|
|
31
|
+
}): Promise<string> {
|
|
32
|
+
const { persistSystemCard: persistHostSystemCard } =
|
|
33
|
+
await import("../runtime/routes/canned-message-complete.js");
|
|
34
|
+
const { id } = await persistHostSystemCard({ ...opts, endsTurn: false });
|
|
35
|
+
return id;
|
|
36
|
+
}
|
|
@@ -2,8 +2,14 @@ import { beforeEach, describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import { setConfig } from "../__tests__/helpers/set-config.js";
|
|
4
4
|
import { getConfig } from "../config/loader.js";
|
|
5
|
+
import { getDb } from "../persistence/db-connection.js";
|
|
6
|
+
import { initializeDb } from "../persistence/db-init.js";
|
|
7
|
+
import { providerConnections } from "../persistence/schema/inference.js";
|
|
5
8
|
import type { ModelProfileInfo } from "./types.js";
|
|
6
9
|
|
|
10
|
+
// Entry-name translation reads provider_connections rows through the real DB.
|
|
11
|
+
await initializeDb();
|
|
12
|
+
|
|
7
13
|
// ─── Fixture config ─────────────────────────────────────────────────────────
|
|
8
14
|
|
|
9
15
|
interface MockProfileEntry {
|
|
@@ -211,6 +217,82 @@ describe("doesSupportVision with a BYO default provider", () => {
|
|
|
211
217
|
});
|
|
212
218
|
});
|
|
213
219
|
|
|
220
|
+
describe("doesSupportVision with connection entry-name providers", () => {
|
|
221
|
+
function seedConnection(opts: { name: string; provider: string }): void {
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
getDb()
|
|
224
|
+
.insert(providerConnections)
|
|
225
|
+
.values({
|
|
226
|
+
name: opts.name,
|
|
227
|
+
provider: opts.provider,
|
|
228
|
+
auth: JSON.stringify({
|
|
229
|
+
type: "api_key",
|
|
230
|
+
credential: `${opts.provider}/api_key`,
|
|
231
|
+
}),
|
|
232
|
+
createdAt: now,
|
|
233
|
+
updatedAt: now,
|
|
234
|
+
})
|
|
235
|
+
.run();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
beforeEach(() => {
|
|
239
|
+
getDb().delete(providerConnections).run();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test("judges an entry-name profile by its row's vendor (vision-capable)", () => {
|
|
243
|
+
seedConnection({ name: "openrouter-personal", provider: "openrouter" });
|
|
244
|
+
setMockConfig({
|
|
245
|
+
"personal-opus": {
|
|
246
|
+
provider: "openrouter-personal",
|
|
247
|
+
model: "anthropic/claude-opus-4.6",
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
expect(doesSupportVision(profile("personal-opus"))).toBe(true);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("judges an entry-name profile by its row's vendor (text-only)", () => {
|
|
254
|
+
seedConnection({ name: "openrouter-personal", provider: "openrouter" });
|
|
255
|
+
setMockConfig({
|
|
256
|
+
"personal-deepseek": {
|
|
257
|
+
provider: "openrouter-personal",
|
|
258
|
+
model: "deepseek/deepseek-v4-pro",
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
expect(doesSupportVision(profile("personal-deepseek"))).toBe(false);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("an entry name naming no row fails safe to false", () => {
|
|
265
|
+
setMockConfig({
|
|
266
|
+
dangling: {
|
|
267
|
+
provider: "ghost-connection",
|
|
268
|
+
model: "anthropic/claude-opus-4.6",
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
expect(doesSupportVision(profile("dangling"))).toBe(false);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test("mix arms with entry-name providers translate the same way", () => {
|
|
275
|
+
seedConnection({ name: "openrouter-personal", provider: "openrouter" });
|
|
276
|
+
setMockConfig({
|
|
277
|
+
"mix-profile": {
|
|
278
|
+
mix: [
|
|
279
|
+
{ profile: "personal-deepseek", weight: 0.5 },
|
|
280
|
+
{ profile: "personal-opus", weight: 0.5 },
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
"personal-deepseek": {
|
|
284
|
+
provider: "openrouter-personal",
|
|
285
|
+
model: "deepseek/deepseek-v4-pro",
|
|
286
|
+
},
|
|
287
|
+
"personal-opus": {
|
|
288
|
+
provider: "openrouter-personal",
|
|
289
|
+
model: "anthropic/claude-opus-4.6",
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
expect(doesSupportVision(profile("mix-profile"))).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
214
296
|
describe("doesSupportVision with a bare string", () => {
|
|
215
297
|
test("returns true for a known vision-capable model id", () => {
|
|
216
298
|
expect(doesSupportVision("claude-opus-4-6")).toBe(true);
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* resolved through `llm.profiles` to an effective `(provider, model)`.
|
|
11
11
|
* Default profile keys resolve through `llm.defaultProvider`'s column of the
|
|
12
12
|
* intent × provider matrix, so the judged model is the one that actually
|
|
13
|
-
* runs on a BYO install.
|
|
13
|
+
* runs on a BYO install. A profile whose provider names a connection entry
|
|
14
|
+
* row (e.g. a `<vendor>-personal` binding) is judged by the row's
|
|
15
|
+
* dispatchable vendor, sharing dispatch's entry-name translation.
|
|
14
16
|
*
|
|
15
17
|
* A bare string is tried as a model id first and then as a profile key, so the
|
|
16
18
|
* two callers share one function. Resolution returns `false` when nothing
|
|
@@ -21,6 +23,7 @@
|
|
|
21
23
|
|
|
22
24
|
import { resolveDefaultProfileForProvider } from "../config/default-profile-catalog.js";
|
|
23
25
|
import { getConfig } from "../config/loader.js";
|
|
26
|
+
import { resolveEntryProviderKind } from "../providers/connection-resolution.js";
|
|
24
27
|
import { ROUTING_IDENTITY_PROVIDERS } from "../providers/inference/auth.js";
|
|
25
28
|
import {
|
|
26
29
|
getCatalogProviderForModel,
|
|
@@ -117,12 +120,21 @@ function resolveEntryVision(entry: {
|
|
|
117
120
|
}): boolean | undefined {
|
|
118
121
|
// Routing identities ("vellum"/"chatgpt") are not catalog providers; the
|
|
119
122
|
// model's catalog owner is the capability source for them.
|
|
120
|
-
const
|
|
123
|
+
const declared =
|
|
121
124
|
entry.provider != null && ROUTING_IDENTITY_PROVIDERS.has(entry.provider)
|
|
122
125
|
? undefined
|
|
123
126
|
: entry.provider;
|
|
124
127
|
const model = entry.model;
|
|
125
128
|
|
|
129
|
+
// A provider naming a connection entry row (e.g. a "<vendor>-personal"
|
|
130
|
+
// binding) translates to the row's dispatchable kind, the same translation
|
|
131
|
+
// dispatch uses, so the catalog judges the vendor actually serving the
|
|
132
|
+
// profile. Vendor ids pass through untranslated.
|
|
133
|
+
const provider =
|
|
134
|
+
declared != null
|
|
135
|
+
? (resolveEntryProviderKind(declared, model) ?? declared)
|
|
136
|
+
: undefined;
|
|
137
|
+
|
|
126
138
|
// Infer provider from model when missing (mirrors the resolver's catalog
|
|
127
139
|
// provider implication).
|
|
128
140
|
const effectiveProvider =
|