@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
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RiskAllowlistOption,
|
|
3
|
+
RiskDirectoryScopeOption,
|
|
4
|
+
RiskPatternScopeOption,
|
|
5
|
+
} from "@vellumai/gateway-client";
|
|
6
|
+
|
|
1
7
|
import { getIsContainerized } from "../config/env-registry.js";
|
|
2
8
|
import { mapApprovalProvenance } from "../permissions/approval-provenance.js";
|
|
3
9
|
import { buildChannelPermissionCellQuery } from "../permissions/channel-permission-query.js";
|
|
4
10
|
import {
|
|
5
11
|
check,
|
|
6
12
|
classifyRisk,
|
|
7
|
-
generateAllowlistOptions,
|
|
8
13
|
generateScopeOptions,
|
|
9
|
-
getCachedAssessment,
|
|
10
14
|
isDynamicSkillLoadInvocation,
|
|
15
|
+
type RiskClassificationWithMeta,
|
|
11
16
|
} from "../permissions/checker.js";
|
|
12
17
|
import { getAutoApproveThreshold } from "../permissions/gateway-threshold-reader.js";
|
|
13
18
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
@@ -37,19 +42,15 @@ export type PermissionDecision =
|
|
|
37
42
|
decision: string;
|
|
38
43
|
riskLevel: string;
|
|
39
44
|
wasPrompted?: boolean;
|
|
40
|
-
/** ID of the trust rule that matched this invocation (if any).
|
|
45
|
+
/** ID of the trust rule that matched this invocation (if any). */
|
|
41
46
|
matchedTrustRuleId?: string;
|
|
42
|
-
/** Risk metadata from the
|
|
43
|
-
riskMeta
|
|
47
|
+
/** Risk metadata from the invocation's classification. */
|
|
48
|
+
riskMeta: {
|
|
44
49
|
riskLevel: string;
|
|
45
50
|
riskReason: string;
|
|
46
|
-
riskScopeOptions:
|
|
47
|
-
riskAllowlistOptions?:
|
|
48
|
-
|
|
49
|
-
description: string;
|
|
50
|
-
pattern: string;
|
|
51
|
-
}>;
|
|
52
|
-
riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
|
|
51
|
+
riskScopeOptions: RiskPatternScopeOption[];
|
|
52
|
+
riskAllowlistOptions?: RiskAllowlistOption[];
|
|
53
|
+
riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
|
|
53
54
|
isContainerized?: boolean;
|
|
54
55
|
};
|
|
55
56
|
approvalMode?: ApprovalMode;
|
|
@@ -61,19 +62,15 @@ export type PermissionDecision =
|
|
|
61
62
|
decision: string;
|
|
62
63
|
riskLevel: string;
|
|
63
64
|
content: string;
|
|
64
|
-
/** ID of the trust rule that matched this invocation (if any).
|
|
65
|
+
/** ID of the trust rule that matched this invocation (if any). */
|
|
65
66
|
matchedTrustRuleId?: string;
|
|
66
|
-
/** Risk metadata from the
|
|
67
|
-
riskMeta
|
|
67
|
+
/** Risk metadata from the invocation's classification. */
|
|
68
|
+
riskMeta: {
|
|
68
69
|
riskLevel: string;
|
|
69
70
|
riskReason: string;
|
|
70
|
-
riskScopeOptions:
|
|
71
|
-
riskAllowlistOptions?:
|
|
72
|
-
|
|
73
|
-
description: string;
|
|
74
|
-
pattern: string;
|
|
75
|
-
}>;
|
|
76
|
-
riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
|
|
71
|
+
riskScopeOptions: RiskPatternScopeOption[];
|
|
72
|
+
riskAllowlistOptions?: RiskAllowlistOption[];
|
|
73
|
+
riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
|
|
77
74
|
isContainerized?: boolean;
|
|
78
75
|
};
|
|
79
76
|
approvalMode?: ApprovalMode;
|
|
@@ -89,10 +86,13 @@ export class PermissionChecker {
|
|
|
89
86
|
}
|
|
90
87
|
|
|
91
88
|
/**
|
|
92
|
-
* Run
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
89
|
+
* Run trust rule evaluation and (if needed) user prompting for a tool
|
|
90
|
+
* invocation. Returns whether the tool is allowed to execute, along with
|
|
91
|
+
* the decision string and risk level for lifecycle event reporting.
|
|
92
|
+
*
|
|
93
|
+
* `classification` is the invocation's gateway classification when the
|
|
94
|
+
* executor already holds it (it classifies once, before its gates); absent
|
|
95
|
+
* that, the same input is classified here.
|
|
96
96
|
*/
|
|
97
97
|
async checkPermission(
|
|
98
98
|
name: string,
|
|
@@ -113,10 +113,11 @@ export class PermissionChecker {
|
|
|
113
113
|
}
|
|
114
114
|
| undefined
|
|
115
115
|
>,
|
|
116
|
+
classification?: RiskClassificationWithMeta,
|
|
116
117
|
): Promise<PermissionDecision> {
|
|
117
118
|
// Sandbox/host routing for the prompt comes from the tool's manifest.
|
|
118
119
|
const executionTarget = resolveExecutionTarget(tool);
|
|
119
|
-
|
|
120
|
+
classification ??= await classifyRisk(
|
|
120
121
|
name,
|
|
121
122
|
input,
|
|
122
123
|
context.workingDir,
|
|
@@ -124,26 +125,19 @@ export class PermissionChecker {
|
|
|
124
125
|
undefined,
|
|
125
126
|
context.signal,
|
|
126
127
|
);
|
|
128
|
+
const { level: risk, reason: riskReason } = classification;
|
|
127
129
|
const riskLevel: string = risk;
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// Save ladder (Minimatch globs — what the gateway matches against).
|
|
140
|
-
// Populated for classifiers that produce allowlist options
|
|
141
|
-
// (bash, file, skill); undefined otherwise.
|
|
142
|
-
riskAllowlistOptions: cachedAssessment.allowlistOptions,
|
|
143
|
-
riskDirectoryScopeOptions: cachedAssessment.directoryScopeOptions,
|
|
144
|
-
isContainerized: getIsContainerized(),
|
|
145
|
-
}
|
|
146
|
-
: undefined;
|
|
131
|
+
const riskMeta = {
|
|
132
|
+
riskLevel: classification.level,
|
|
133
|
+
riskReason: classification.reason,
|
|
134
|
+
// Display ladder: bash only, internal, never persisted as a rule.
|
|
135
|
+
riskScopeOptions: classification.scopeOptions,
|
|
136
|
+
// Save ladder: the patterns the gateway matches a rule by, exactly.
|
|
137
|
+
riskAllowlistOptions: classification.allowlistOptions,
|
|
138
|
+
riskDirectoryScopeOptions: classification.directoryScopeOptions,
|
|
139
|
+
isContainerized: getIsContainerized(),
|
|
140
|
+
};
|
|
147
141
|
|
|
148
142
|
// Wrap the rest of permission evaluation so that any exception
|
|
149
143
|
// carries the classified risk level back to the caller. Without
|
|
@@ -158,6 +152,7 @@ export class PermissionChecker {
|
|
|
158
152
|
policyContext,
|
|
159
153
|
undefined,
|
|
160
154
|
context.signal,
|
|
155
|
+
classification,
|
|
161
156
|
);
|
|
162
157
|
|
|
163
158
|
// Every threshold read for this invocation must consult the same
|
|
@@ -240,7 +235,7 @@ export class PermissionChecker {
|
|
|
240
235
|
if (
|
|
241
236
|
context.isInteractive === false &&
|
|
242
237
|
isDynamicSkillLoadInvocation(name, input) &&
|
|
243
|
-
|
|
238
|
+
classification.matchType !== "user_rule"
|
|
244
239
|
) {
|
|
245
240
|
log.info(
|
|
246
241
|
{ toolName: name, riskLevel },
|
|
@@ -385,11 +380,7 @@ export class PermissionChecker {
|
|
|
385
380
|
context.workingDir,
|
|
386
381
|
);
|
|
387
382
|
const promptOptions = {
|
|
388
|
-
allowlistOptions:
|
|
389
|
-
name,
|
|
390
|
-
input,
|
|
391
|
-
context.signal,
|
|
392
|
-
),
|
|
383
|
+
allowlistOptions: classification.allowlistOptions ?? [],
|
|
393
384
|
scopeOptions: generateScopeOptions(context.workingDir, name),
|
|
394
385
|
persistentDecisionsAllowed: !context.requireFreshApproval,
|
|
395
386
|
};
|
|
@@ -410,7 +401,7 @@ export class PermissionChecker {
|
|
|
410
401
|
context.toolUseId,
|
|
411
402
|
riskReason,
|
|
412
403
|
getIsContainerized(),
|
|
413
|
-
|
|
404
|
+
classification.directoryScopeOptions,
|
|
414
405
|
);
|
|
415
406
|
|
|
416
407
|
const decision = response.decision;
|
|
@@ -6,6 +6,45 @@ import type { ToolDefinition } from "../providers/types.js";
|
|
|
6
6
|
*/
|
|
7
7
|
export const ACTIVITY_SKIP_SET = new Set<string>();
|
|
8
8
|
|
|
9
|
+
/** The status field injected into every advertised tool input schema. */
|
|
10
|
+
export const ACTIVITY_FIELD = "activity";
|
|
11
|
+
|
|
12
|
+
const ACTIVITY_PROPERTY = {
|
|
13
|
+
type: "string",
|
|
14
|
+
description:
|
|
15
|
+
"Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Add the injected `activity` property to a schema, so a validator checking a
|
|
20
|
+
* call against the tool's own schema accepts the field the advertised schema
|
|
21
|
+
* asked the model to send.
|
|
22
|
+
*
|
|
23
|
+
* `injectActivityField` rewrites the definitions the model sees, not the
|
|
24
|
+
* manifest a skill tool validates against, so without this the model is
|
|
25
|
+
* offered a field its own tool then rejects as unknown. The property is added
|
|
26
|
+
* but never the `required` entry: the advertised copy asks for it, and a call
|
|
27
|
+
* that leaves it out is still a call the tool can serve.
|
|
28
|
+
*/
|
|
29
|
+
export function withActivityProperty(
|
|
30
|
+
schema: Record<string, unknown> | undefined,
|
|
31
|
+
): Record<string, unknown> | undefined {
|
|
32
|
+
if (!schema || schema.type !== "object") {
|
|
33
|
+
return schema;
|
|
34
|
+
}
|
|
35
|
+
const properties = schema.properties;
|
|
36
|
+
if (typeof properties !== "object" || properties === null) {
|
|
37
|
+
return schema;
|
|
38
|
+
}
|
|
39
|
+
if (schemaDefinesProperty(schema, ACTIVITY_FIELD)) {
|
|
40
|
+
return schema;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...schema,
|
|
44
|
+
properties: { ...properties, [ACTIVITY_FIELD]: ACTIVITY_PROPERTY },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
9
48
|
/**
|
|
10
49
|
* Injects an `activity` string property into each tool definition's input
|
|
11
50
|
* schema, unless the tool is in the skip set, already has an activity field,
|
|
@@ -46,11 +85,7 @@ export function injectActivityField(
|
|
|
46
85
|
// Deep clone to avoid mutating shared refs
|
|
47
86
|
const newProperties = {
|
|
48
87
|
...properties,
|
|
49
|
-
|
|
50
|
-
type: "string",
|
|
51
|
-
description:
|
|
52
|
-
"Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
|
|
53
|
-
},
|
|
88
|
+
[ACTIVITY_FIELD]: ACTIVITY_PROPERTY,
|
|
54
89
|
};
|
|
55
90
|
const existingRequired = Array.isArray(schema.required)
|
|
56
91
|
? [...schema.required, "activity"]
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-validation repairs for bundled tool calls whose arguments arrive in a
|
|
3
|
+
* shape the tool did not declare but whose intent is unambiguous.
|
|
4
|
+
*
|
|
5
|
+
* The sibling module `input-misuse.ts` answers a misused parameter shape with
|
|
6
|
+
* a better error message. This one answers the shapes we can act on instead:
|
|
7
|
+
* the call carries what the tool needs, spelled the way the surrounding prose
|
|
8
|
+
* asks for it rather than the way the schema declares it, so rewriting it is
|
|
9
|
+
* closer to the caller's intent than rejecting it. Repairs run before
|
|
10
|
+
* `validateInputAgainstSchema`, so a repaired call validates on its merits and
|
|
11
|
+
* anything left unrepaired keeps its normal error.
|
|
12
|
+
*
|
|
13
|
+
* Generic, schema-derivable coercions (a string holding a JSON array, one
|
|
14
|
+
* element where a list was expected) belong in `skills/validate-input.ts`.
|
|
15
|
+
* What lives here is knowledge of a specific tool's contract that no schema
|
|
16
|
+
* states.
|
|
17
|
+
*
|
|
18
|
+
* Rules describe the first-party tools that ship in `bundled-skills/`, and
|
|
19
|
+
* tool names are not reserved: a managed, workspace, extra, or plugin skill
|
|
20
|
+
* may define its own `scaffold_managed_skill` with a different contract. The
|
|
21
|
+
* `bundled` prefix on the export is the reminder that callers must establish
|
|
22
|
+
* bundled provenance before applying a repair.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { isPlainObject } from "../../util/object.js";
|
|
26
|
+
|
|
27
|
+
interface ToolInputRepairRules {
|
|
28
|
+
/**
|
|
29
|
+
* Parameter spellings the tool accepts as another parameter's name.
|
|
30
|
+
*
|
|
31
|
+
* Each entry is a name the prose around the tool uses for a parameter the
|
|
32
|
+
* schema declares under a different one, and models follow prose over
|
|
33
|
+
* schema. `scaffold_managed_skill` declares `body_markdown` while the
|
|
34
|
+
* skill-authoring prose talks throughout about writing "the body"; the
|
|
35
|
+
* retrospective prompt tells the model to call `find_similar_skills` with a
|
|
36
|
+
* short description, which the schema declares as `goal`.
|
|
37
|
+
*
|
|
38
|
+
* An alias applies only when the canonical parameter is absent, so a call
|
|
39
|
+
* that spells the parameter correctly is never overwritten.
|
|
40
|
+
*/
|
|
41
|
+
aliases?: Readonly<Record<string, string>>;
|
|
42
|
+
/** Whether the tool's `files` parameter also reads a path-keyed map. */
|
|
43
|
+
filesMap?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const REPAIR_RULES: Readonly<Record<string, ToolInputRepairRules>> = {
|
|
47
|
+
scaffold_managed_skill: {
|
|
48
|
+
aliases: {
|
|
49
|
+
body: "body_markdown",
|
|
50
|
+
content: "body_markdown",
|
|
51
|
+
title: "name",
|
|
52
|
+
summary: "description",
|
|
53
|
+
},
|
|
54
|
+
filesMap: true,
|
|
55
|
+
},
|
|
56
|
+
find_similar_skills: {
|
|
57
|
+
aliases: { description: "goal", query: "goal" },
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** The properties one `files` entry declares. */
|
|
62
|
+
const FILE_ENTRY_KEYS: ReadonlySet<string> = new Set([
|
|
63
|
+
"path",
|
|
64
|
+
"content",
|
|
65
|
+
"copy_from",
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
/** The properties a `files` entry may carry besides its path. */
|
|
69
|
+
const FILE_BYTES_KEYS: ReadonlySet<string> = new Set(["content", "copy_from"]);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Read a `files` object written as a map from path to contents, the shape
|
|
73
|
+
* models reach for when asked for companion files keyed by where they go:
|
|
74
|
+
* `{"references/failure-modes.md": "..."}`, or with the entry spelled out as
|
|
75
|
+
* `{"scripts/run.sh": {"copy_from": "/abs/path"}}`.
|
|
76
|
+
*
|
|
77
|
+
* Returns the declared array shape, or `undefined` when any entry is not
|
|
78
|
+
* readable as one file, in which case the whole value is left alone: a partial
|
|
79
|
+
* reading would drop files the caller asked for without saying so. Guessing
|
|
80
|
+
* which path wins for an entry that names its own is a guess about intent
|
|
81
|
+
* rather than a repair, so those are left too.
|
|
82
|
+
*/
|
|
83
|
+
function filesMapToEntries(
|
|
84
|
+
map: Record<string, unknown>,
|
|
85
|
+
): unknown[] | undefined {
|
|
86
|
+
const entries = Object.entries(map);
|
|
87
|
+
// An object spelling out one entry's own fields is a single file, not a map
|
|
88
|
+
// of them. Reading it as a map would turn its field names into paths.
|
|
89
|
+
if (
|
|
90
|
+
entries.length === 0 ||
|
|
91
|
+
entries.every(([key]) => FILE_ENTRY_KEYS.has(key))
|
|
92
|
+
) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const files: Record<string, unknown>[] = [];
|
|
96
|
+
for (const [path, entry] of entries) {
|
|
97
|
+
if (!path.trim()) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (typeof entry === "string") {
|
|
101
|
+
files.push({ path, content: entry });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (!isPlainObject(entry)) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const keys = Object.keys(entry);
|
|
108
|
+
if (keys.length === 0 || !keys.every((key) => FILE_BYTES_KEYS.has(key))) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
files.push({ path, ...entry });
|
|
112
|
+
}
|
|
113
|
+
return files;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Rewrite a bundled tool's input into the shape its schema declares, when the
|
|
118
|
+
* arguments say what was meant unambiguously.
|
|
119
|
+
*
|
|
120
|
+
* Only call this for a tool that came from a bundled skill. `toolName` alone
|
|
121
|
+
* does not establish that.
|
|
122
|
+
*
|
|
123
|
+
* Pure: returns a new object when a repair applies, otherwise returns `input`
|
|
124
|
+
* unchanged. Never mutates `input`.
|
|
125
|
+
*/
|
|
126
|
+
export function bundledToolInputRepairs(
|
|
127
|
+
toolName: string,
|
|
128
|
+
input: Record<string, unknown>,
|
|
129
|
+
): Record<string, unknown> {
|
|
130
|
+
const rules = REPAIR_RULES[toolName];
|
|
131
|
+
if (!rules) {
|
|
132
|
+
return input;
|
|
133
|
+
}
|
|
134
|
+
let repaired: Record<string, unknown> | undefined;
|
|
135
|
+
|
|
136
|
+
for (const [alias, canonical] of Object.entries(rules.aliases ?? {})) {
|
|
137
|
+
if (!(alias in input) || canonical in input) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
repaired ??= { ...input };
|
|
141
|
+
repaired[canonical] = repaired[alias];
|
|
142
|
+
delete repaired[alias];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const files = input.files;
|
|
146
|
+
if (rules.filesMap && isPlainObject(files)) {
|
|
147
|
+
const entries = filesMapToEntries(files);
|
|
148
|
+
if (entries) {
|
|
149
|
+
repaired ??= { ...input };
|
|
150
|
+
repaired.files = entries;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return repaired ?? input;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Every alias a bundled `toolName` accepts, for drift guards. */
|
|
158
|
+
export function bundledToolInputAliases(toolName: string): string[] {
|
|
159
|
+
return Object.keys(REPAIR_RULES[toolName]?.aliases ?? {});
|
|
160
|
+
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { SkillToolEntry } from "../../config/skills.js";
|
|
2
2
|
import { RiskLevel } from "../../permissions/types.js";
|
|
3
3
|
import {
|
|
4
|
+
coerceArrayShapes,
|
|
4
5
|
coerceStringBooleans,
|
|
5
6
|
coerceStringNumbers,
|
|
6
7
|
validateInputAgainstSchema,
|
|
7
8
|
} from "../../skills/validate-input.js";
|
|
9
|
+
import { withActivityProperty } from "../schema-transforms.js";
|
|
8
10
|
import { bundledToolInputMisuseMessage } from "../shared/input-misuse.js";
|
|
11
|
+
import { bundledToolInputRepairs } from "../shared/input-repairs.js";
|
|
9
12
|
import type { ExecutionTarget } from "../tool-types.js";
|
|
10
13
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
11
14
|
import { runSkillToolScript } from "./skill-script-runner.js";
|
|
@@ -43,11 +46,22 @@ export function createSkillTool(
|
|
|
43
46
|
input: Record<string, unknown>,
|
|
44
47
|
context: ToolContext,
|
|
45
48
|
): Promise<ToolExecutionResult> {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
// Validate against the schema the model was actually shown: tool
|
|
50
|
+
// definitions carry an injected `activity` field the manifest does not
|
|
51
|
+
// declare, and a call that fills it must not be rejected as unknown.
|
|
52
|
+
const schema = withActivityProperty(
|
|
53
|
+
entry.input_schema as Record<string, unknown> | undefined,
|
|
50
54
|
);
|
|
55
|
+
// Tool-specific repairs first: they rewrite keys and shapes the schema
|
|
56
|
+
// does not describe, and the generic coercions below then see the
|
|
57
|
+
// declared parameter names. Repairs describe first-party tools, so only
|
|
58
|
+
// bundled skills consult them.
|
|
59
|
+
const repairedInput = bundled
|
|
60
|
+
? bundledToolInputRepairs(entry.name, input)
|
|
61
|
+
: input;
|
|
62
|
+
const withBooleans = coerceStringBooleans(repairedInput, schema);
|
|
63
|
+
const withNumbers = coerceStringNumbers(withBooleans, schema);
|
|
64
|
+
const coercedInput = coerceArrayShapes(withNumbers, schema);
|
|
51
65
|
const validation = validateInputAgainstSchema(
|
|
52
66
|
entry.name,
|
|
53
67
|
coercedInput,
|
|
@@ -595,7 +595,6 @@ async function runAdvisorConsult(args: {
|
|
|
595
595
|
workingDir: context.workingDir,
|
|
596
596
|
allowedToolNames: context.allowedToolNames,
|
|
597
597
|
trustClass: context.trustClass,
|
|
598
|
-
sourceChannel: context.executionChannel,
|
|
599
598
|
enabledPluginSet: context.enabledPluginSet,
|
|
600
599
|
// The parent's warm per-turn catalog keeps the synchronous on-disk
|
|
601
600
|
// catalog scan out of the consult path.
|
|
@@ -136,23 +136,29 @@ const TC_GRANT_WAIT_INTERVAL_MS = 500;
|
|
|
136
136
|
export const TC_GRANT_WAIT_MAX_MS = 60_000;
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
|
-
* Resolve
|
|
139
|
+
* Resolve how long one approval decision stays open, in milliseconds.
|
|
140
140
|
*
|
|
141
|
-
*
|
|
142
|
-
* local user answering a permission prompt, so
|
|
141
|
+
* Every actor deciding a gated tool call is making the same decision as a
|
|
142
|
+
* local user answering a permission prompt, so every path spends the same
|
|
143
143
|
* budget: `timeouts.permissionTimeoutSec` (read by `permissions/prompter.ts`).
|
|
144
|
-
* If anything,
|
|
145
|
-
* already has the prompt on screen, while
|
|
146
|
-
* out-of-band and has to context-switch before deciding.
|
|
144
|
+
* If anything, an off-channel path needs the larger share of it: the
|
|
145
|
+
* prompter's user already has the prompt on screen, while a guardian is
|
|
146
|
+
* notified out-of-band and has to context-switch before deciding.
|
|
147
147
|
*
|
|
148
148
|
* Falls back to {@link TC_GRANT_WAIT_MAX_MS} rather than the tool-execution
|
|
149
149
|
* default on a non-positive value, so a bad config can never collapse the
|
|
150
150
|
* window to zero and auto-deny every escalation.
|
|
151
151
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
152
|
+
* This is the one owner of that budget, and every clock measuring the same
|
|
153
|
+
* window reads it here rather than restating the number:
|
|
154
|
+
*
|
|
155
|
+
* - the inline grant wait, which spends it directly;
|
|
156
|
+
* - the grant resolver's `inline_wait_active` staleness threshold, because if
|
|
157
|
+
* the two drift, an approval arriving while a waiter is still live gets
|
|
158
|
+
* misread as a dead waiter and the requester is told to retry a call that is
|
|
159
|
+
* about to resume on its own;
|
|
160
|
+
* - the `tool_approval` row deadline, so the card stops offering a decision at
|
|
161
|
+
* the same moment the prompt stops waiting for one.
|
|
156
162
|
*/
|
|
157
163
|
export function resolveInlineGrantWaitMs(): number {
|
|
158
164
|
return safeTimeoutMs(
|
package/src/tools/tool-types.ts
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Pure type-level declarations only (+ the `RiskLevel` enum, which is a
|
|
6
6
|
* value). No runtime helpers live here — the assistant keeps all behavior
|
|
7
7
|
* functions in `assistant/src/tools/` and re-exports the types from this
|
|
8
|
-
* file. This module imports nothing
|
|
9
|
-
*
|
|
10
|
-
* and `
|
|
8
|
+
* file. This module imports nothing from `assistant/src` (only type-only
|
|
9
|
+
* wire shapes from `@vellumai/gateway-client`), so it can sit at the bottom
|
|
10
|
+
* of the import graph and be consumed by `tools/types.ts`,
|
|
11
|
+
* `providers/types.ts`, and `permissions/types.ts` without creating cycles.
|
|
11
12
|
*
|
|
12
13
|
* Heavy daemon-internal references (CES client, host-proxy classes, trust
|
|
13
14
|
* classifications, interface IDs, content blocks, CES `ApprovalRequired`)
|
|
@@ -25,6 +26,12 @@
|
|
|
25
26
|
// Simple type-level declarations — moved in full
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
27
28
|
|
|
29
|
+
import type {
|
|
30
|
+
RiskAllowlistOption,
|
|
31
|
+
RiskDirectoryScopeOption,
|
|
32
|
+
RiskPatternScopeOption,
|
|
33
|
+
} from "@vellumai/gateway-client";
|
|
34
|
+
|
|
28
35
|
export type ExecutionTarget = "sandbox" | "host";
|
|
29
36
|
|
|
30
37
|
/** The kind of extension that owns a tool. Core tools have no owner. */
|
|
@@ -49,6 +56,14 @@ export enum RiskLevel {
|
|
|
49
56
|
High = "high",
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
/**
|
|
60
|
+
* `riskLevel` recorded on a `tool_invocations` audit row when the call's risk
|
|
61
|
+
* was never classified (classification aborted, or the gateway was
|
|
62
|
+
* unreachable, before any decision was reached). Distinct from every
|
|
63
|
+
* {@link RiskLevel} so a reader can tell "not assessed" from "assessed as low".
|
|
64
|
+
*/
|
|
65
|
+
export const RISK_LEVEL_UNCLASSIFIED = "unclassified";
|
|
66
|
+
|
|
52
67
|
export interface ToolDefinition {
|
|
53
68
|
name: string;
|
|
54
69
|
description: string;
|
|
@@ -162,7 +177,7 @@ export interface ToolExecutionResult {
|
|
|
162
177
|
/** Whether the daemon is running in a containerized (Docker) environment. */
|
|
163
178
|
isContainerized?: boolean;
|
|
164
179
|
/** Scope options ladder for the rule editor (narrowest to broadest). */
|
|
165
|
-
riskScopeOptions?:
|
|
180
|
+
riskScopeOptions?: RiskPatternScopeOption[];
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
export type ProxyToolResolver = (
|
|
@@ -174,16 +189,14 @@ export type ProxyToolResolver = (
|
|
|
174
189
|
// Permission prompt option ladders
|
|
175
190
|
// ---------------------------------------------------------------------------
|
|
176
191
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
description: string;
|
|
180
|
-
pattern: string;
|
|
181
|
-
}
|
|
192
|
+
/** The prompt's "always allow" ladder entry: the gateway's wire shape. */
|
|
193
|
+
export type AllowlistOption = RiskAllowlistOption;
|
|
182
194
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
/**
|
|
196
|
+
* A directory-scope ladder entry (`scope` is a path glob or `everywhere`);
|
|
197
|
+
* the same wire shape the gateway emits as `directoryScopeOptions`.
|
|
198
|
+
*/
|
|
199
|
+
export type ScopeOption = RiskDirectoryScopeOption;
|
|
187
200
|
|
|
188
201
|
// ---------------------------------------------------------------------------
|
|
189
202
|
// Tool context
|
package/src/tools/types.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RiskAllowlistOption,
|
|
3
|
+
RiskDirectoryScopeOption,
|
|
4
|
+
} from "@vellumai/gateway-client";
|
|
1
5
|
import { z } from "zod";
|
|
2
6
|
|
|
3
7
|
import type { AnsweredQuestion } from "../api/events/question-answered.js";
|
|
@@ -124,13 +128,9 @@ export interface ToolExecutionResult {
|
|
|
124
128
|
* wildcards) — what the gateway actually matches against. Mirrors
|
|
125
129
|
* the `allowlistOptions` field on `ConfirmationRequest` SSE events.
|
|
126
130
|
*/
|
|
127
|
-
riskAllowlistOptions?:
|
|
128
|
-
label: string;
|
|
129
|
-
description: string;
|
|
130
|
-
pattern: string;
|
|
131
|
-
}>;
|
|
131
|
+
riskAllowlistOptions?: RiskAllowlistOption[];
|
|
132
132
|
/** Directory scope ladder for the rule editor (narrowest to broadest). */
|
|
133
|
-
riskDirectoryScopeOptions?:
|
|
133
|
+
riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
|
|
134
134
|
/** Structured activity metadata for client rendering (web search, web fetch, etc).
|
|
135
135
|
* Populated by daemon-internal tools; plugins must not set this. */
|
|
136
136
|
activityMetadata?: ToolActivityMetadata;
|
|
@@ -19,6 +19,7 @@ vmalloc 0
|
|
|
19
19
|
shmem 8192
|
|
20
20
|
zswap 0
|
|
21
21
|
zswapped 0
|
|
22
|
+
inactive_file 1073741824
|
|
22
23
|
file_mapped 209715200
|
|
23
24
|
file_dirty 135168
|
|
24
25
|
file_writeback 0
|
|
@@ -38,6 +39,7 @@ describe("parseMemoryStat", () => {
|
|
|
38
39
|
expect(stat).toEqual({
|
|
39
40
|
anonBytes: 2147483648,
|
|
40
41
|
fileBytes: 1610612736,
|
|
42
|
+
inactiveFileBytes: 1073741824,
|
|
41
43
|
kernelBytes: 943718400,
|
|
42
44
|
slabReclaimableBytes: 838860800,
|
|
43
45
|
slabUnreclaimableBytes: 104857600,
|
|
@@ -72,6 +74,7 @@ describe("parseMemoryStat", () => {
|
|
|
72
74
|
expect(parseMemoryStat("")).toEqual({
|
|
73
75
|
anonBytes: null,
|
|
74
76
|
fileBytes: null,
|
|
77
|
+
inactiveFileBytes: null,
|
|
75
78
|
kernelBytes: null,
|
|
76
79
|
slabReclaimableBytes: null,
|
|
77
80
|
slabUnreclaimableBytes: null,
|
|
@@ -134,6 +134,8 @@ export interface ContainerMemoryStat {
|
|
|
134
134
|
fileBytes: number | null;
|
|
135
135
|
/** Total kernel memory charged to the cgroup (includes slab). */
|
|
136
136
|
kernelBytes: number | null;
|
|
137
|
+
/** File-backed pages on the inactive LRU: readily reclaimable cache. */
|
|
138
|
+
inactiveFileBytes: number | null;
|
|
137
139
|
/** Slab memory the kernel can reclaim under pressure (dentries, inodes). */
|
|
138
140
|
slabReclaimableBytes: number | null;
|
|
139
141
|
/** Slab memory pinned until explicitly freed. */
|
|
@@ -172,6 +174,7 @@ export function parseMemoryStat(raw: string): ContainerMemoryStat {
|
|
|
172
174
|
return {
|
|
173
175
|
anonBytes,
|
|
174
176
|
fileBytes,
|
|
177
|
+
inactiveFileBytes: counts.inactive_file ?? null,
|
|
175
178
|
kernelBytes: counts.kernel ?? null,
|
|
176
179
|
slabReclaimableBytes,
|
|
177
180
|
slabUnreclaimableBytes,
|