@vellumai/assistant 0.4.56 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +10 -10
- package/Dockerfile +3 -0
- package/README.md +11 -11
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/memory.md +3 -4
- package/docs/credential-execution-service.md +13 -20
- package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +7 -7
- package/src/__tests__/anthropic-provider.test.ts +172 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
- package/src/__tests__/approval-cascade.test.ts +2 -2
- package/src/__tests__/approval-routes-http.test.ts +3 -4
- package/src/__tests__/asset-materialize-tool.test.ts +5 -5
- package/src/__tests__/asset-search-tool.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +5 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
- package/src/__tests__/attachments-store.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +5 -3
- package/src/__tests__/browser-skill-endstate.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +2 -2
- package/src/__tests__/callback-handoff-copy.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +31 -32
- package/src/__tests__/chrome-cdp.test.ts +47 -18
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +9 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop.test.ts +11 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +33 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +23 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
- package/src/__tests__/conversation-seed-composer.test.ts +1 -1
- package/src/__tests__/conversation-slash-queue.test.ts +4 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
- package/src/__tests__/conversation-starter-routes.test.ts +291 -0
- package/src/__tests__/conversation-wipe.test.ts +438 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
- package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
- package/src/__tests__/credential-security-e2e.test.ts +20 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +227 -0
- package/src/__tests__/credentials-cli.test.ts +3 -0
- package/src/__tests__/date-context.test.ts +59 -377
- package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/encrypted-store.test.ts +249 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/file-read-tool.test.ts +40 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +4 -4
- package/src/__tests__/gemini-provider.test.ts +6 -9
- package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/host-file-read-tool.test.ts +87 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +209 -0
- package/src/__tests__/intent-routing.test.ts +51 -99
- package/src/__tests__/invite-routes-http.test.ts +5 -0
- package/src/__tests__/list-messages-attachments.test.ts +1 -1
- package/src/__tests__/managed-proxy-context.test.ts +2 -5
- package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
- package/src/__tests__/media-generate-image.test.ts +32 -15
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
- package/src/__tests__/memory-recall-quality.test.ts +4 -3
- package/src/__tests__/memory-regressions.test.ts +86 -90
- package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
- package/src/__tests__/migration-export-http.test.ts +26 -27
- package/src/__tests__/migration-import-commit-http.test.ts +165 -37
- package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
- package/src/__tests__/migration-validate-http.test.ts +16 -16
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +3 -3
- package/src/__tests__/notification-broadcaster.test.ts +1 -1
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-identity.test.ts +8 -9
- package/src/__tests__/notification-decision-strategy.test.ts +1 -1
- package/src/__tests__/notification-deep-link.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
- package/src/__tests__/onboarding-template-contract.test.ts +23 -59
- package/src/__tests__/provider-error-scenarios.test.ts +154 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
- package/src/__tests__/provider-registry-ollama.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +7 -7
- package/src/__tests__/ratelimit.test.ts +0 -74
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +46 -2
- package/src/__tests__/schema-transforms.test.ts +114 -54
- package/src/__tests__/secret-onetime-send.test.ts +20 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +63 -4
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/shell-credential-ref.test.ts +0 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
- package/src/__tests__/skill-memory.test.ts +549 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
- package/src/__tests__/slack-channel-config.test.ts +109 -94
- package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
- package/src/__tests__/swarm-recursion.test.ts +2 -2
- package/src/__tests__/swarm-tool.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +19 -66
- package/src/__tests__/telegram-config.test.ts +121 -0
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trace-emitter.test.ts +8 -1
- package/src/__tests__/trust-store.test.ts +7 -8
- package/src/__tests__/twilio-routes.test.ts +1 -18
- package/src/__tests__/user-reference.test.ts +82 -2
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -3
- package/src/avatar/ascii-renderer.ts +2 -2
- package/src/avatar/png-renderer.ts +2 -2
- package/src/avatar/resvg-lazy.ts +21 -0
- package/src/calls/guardian-dispatch.ts +1 -1
- package/src/calls/relay-access-wait.ts +2 -2
- package/src/calls/twilio-rest.ts +0 -248
- package/src/cli/AGENTS.md +5 -8
- package/src/cli/__tests__/notifications.test.ts +5 -5
- package/src/cli/commands/avatar.ts +64 -2
- package/src/cli/commands/conversations.ts +131 -1
- package/src/cli/commands/credentials.ts +2 -0
- package/src/cli/commands/notifications.ts +3 -3
- package/src/cli.ts +10 -0
- package/src/config/bundled-skills/acp/SKILL.md +5 -5
- package/src/config/bundled-skills/acp/TOOLS.json +6 -6
- package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
- package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
- package/src/config/bundled-skills/browser/SKILL.md +15 -15
- package/src/config/bundled-skills/browser/TOOLS.json +14 -14
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
- package/src/config/bundled-skills/contacts/SKILL.md +3 -3
- package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -4
- package/src/config/bundled-skills/document/TOOLS.json +2 -2
- package/src/config/bundled-skills/followups/TOOLS.json +3 -3
- package/src/config/bundled-skills/gmail/SKILL.md +32 -32
- package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
- package/src/config/bundled-skills/google-calendar/types.ts +1 -1
- package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
- package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
- package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +29 -25
- package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +3 -3
- package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
- package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
- package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
- package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
- package/src/config/bundled-skills/schedule/SKILL.md +26 -26
- package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
- package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
- package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
- package/src/config/bundled-skills/sequences/SKILL.md +2 -2
- package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
- package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
- package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
- package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
- package/src/config/bundled-skills/slack/SKILL.md +2 -2
- package/src/config/bundled-skills/slack/TOOLS.json +8 -8
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
- package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
- package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
- package/src/config/bundled-skills/watcher/SKILL.md +4 -4
- package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/schemas/sandbox.ts +1 -1
- package/src/config/schemas/services.ts +13 -3
- package/src/config/schemas/timeouts.ts +0 -10
- package/src/contacts/contact-store.ts +63 -0
- package/src/contacts/contacts-write.ts +1 -1
- package/src/daemon/assistant-attachments.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
- package/src/daemon/conversation-agent-loop.ts +7 -30
- package/src/daemon/conversation-error.ts +24 -0
- package/src/daemon/conversation-memory.ts +8 -7
- package/src/daemon/conversation-runtime-assembly.ts +141 -275
- package/src/daemon/conversation-slash.ts +7 -26
- package/src/daemon/conversation-surfaces.ts +14 -0
- package/src/daemon/conversation-tool-setup.ts +9 -8
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +10 -83
- package/src/daemon/handlers/config-channels.ts +12 -2
- package/src/daemon/handlers/config-slack-channel.ts +7 -1
- package/src/daemon/handlers/config-telegram.ts +6 -1
- package/src/daemon/handlers/conversations.ts +2 -2
- package/src/daemon/handlers/skills.ts +4 -0
- package/src/daemon/lifecycle.ts +28 -4
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +1 -5
- package/src/daemon/shutdown-handlers.ts +9 -3
- package/src/daemon/tool-side-effects.ts +40 -0
- package/src/daemon/trace-emitter.ts +26 -2
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-permission-telemetry-listener.ts +46 -0
- package/src/inbound/platform-callback-registration.ts +0 -18
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +15 -8
- package/src/media/gemini-image-service.ts +125 -21
- package/src/memory/attachments-store.ts +3 -3
- package/src/memory/channel-verification-sessions.ts +6 -6
- package/src/memory/conversation-crud.ts +196 -1
- package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
- package/src/memory/conversation-title-service.ts +2 -3
- package/src/memory/db-init.ts +25 -1
- package/src/memory/invite-store.ts +4 -4
- package/src/memory/items-extractor.ts +4 -4
- package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/jobs-worker.ts +7 -5
- package/src/memory/lifecycle-events-store.ts +63 -0
- package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
- package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
- package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
- package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
- package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
- package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +223 -96
- package/src/memory/retriever.ts +115 -138
- package/src/memory/schema/calls.ts +1 -1
- package/src/memory/schema/contacts.ts +1 -1
- package/src/memory/schema/infrastructure.ts +29 -0
- package/src/memory/schema/memory-core.ts +7 -17
- package/src/memory/schema/notifications.ts +1 -1
- package/src/memory/search/formatting.ts +23 -6
- package/src/memory/search/lexical.ts +2 -0
- package/src/memory/search/semantic.ts +2 -0
- package/src/memory/search/staleness.ts +5 -1
- package/src/memory/search/types.ts +4 -0
- package/src/memory/task-memory-cleanup.ts +96 -6
- package/src/memory/trace-event-store.ts +148 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/decision-engine.ts +45 -4
- package/src/notifications/emit-signal.ts +5 -4
- package/src/notifications/events-store.ts +4 -4
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/manual-token-connection.ts +49 -25
- package/src/permissions/checker.ts +6 -5
- package/src/permissions/defaults.ts +4 -4
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
- package/src/prompts/cache-boundary.ts +8 -0
- package/src/prompts/system-prompt.ts +105 -634
- package/src/prompts/templates/BOOTSTRAP.md +172 -33
- package/src/prompts/templates/IDENTITY.md +8 -24
- package/src/prompts/templates/SOUL.md +20 -41
- package/src/prompts/templates/USER.md +3 -19
- package/src/prompts/user-reference.ts +14 -16
- package/src/providers/anthropic/client.ts +51 -19
- package/src/providers/gemini/client.ts +6 -9
- package/src/providers/managed-proxy/constants.ts +1 -7
- package/src/providers/managed-proxy/context.ts +0 -1
- package/src/providers/model-intents.ts +5 -5
- package/src/providers/openai/client.ts +10 -1
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/ratelimit.ts +0 -35
- package/src/providers/registry.ts +3 -5
- package/src/providers/retry.ts +18 -1
- package/src/runtime/access-request-helper.ts +16 -2
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/channel-verification-service.ts +1 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/guardian-vellum-migration.ts +61 -1
- package/src/runtime/http-server.ts +8 -4
- package/src/runtime/migrations/vbundle-builder.ts +212 -32
- package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
- package/src/runtime/migrations/vbundle-importer.ts +66 -1
- package/src/runtime/migrations/vbundle-validator.ts +17 -3
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +93 -0
- package/src/runtime/routes/channel-verification-routes.ts +19 -2
- package/src/runtime/routes/conversation-management-routes.ts +55 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +49 -5
- package/src/runtime/routes/conversation-starter-routes.ts +207 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
- package/src/runtime/routes/identity-intro-cache.ts +105 -0
- package/src/runtime/routes/identity-routes.ts +51 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +25 -13
- package/src/runtime/routes/secret-routes.ts +18 -0
- package/src/runtime/routes/settings-routes.ts +9 -9
- package/src/runtime/routes/telemetry-routes.ts +53 -0
- package/src/runtime/routes/trace-event-routes.ts +62 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +47 -31
- package/src/security/encrypted-store.ts +262 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +222 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
- package/src/telemetry/usage-telemetry-reporter.ts +53 -4
- package/src/tools/AGENTS.md +11 -11
- package/src/tools/acp/spawn.ts +1 -1
- package/src/tools/apps/executors.ts +8 -8
- package/src/tools/apps/registry.ts +1 -1
- package/src/tools/assets/materialize.ts +6 -6
- package/src/tools/assets/search.ts +10 -10
- package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
- package/src/tools/browser/auth-detector.ts +6 -6
- package/src/tools/browser/browser-execution.ts +13 -13
- package/src/tools/browser/browser-manager.ts +3 -3
- package/src/tools/browser/chrome-cdp.ts +5 -5
- package/src/tools/browser/jit-auth.ts +2 -2
- package/src/tools/browser/network-recorder.test.ts +2 -2
- package/src/tools/browser/network-recorder.ts +3 -3
- package/src/tools/browser/runtime-check.ts +3 -3
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/computer-use/definitions.ts +18 -18
- package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
- package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
- package/src/tools/credentials/broker-types.ts +5 -5
- package/src/tools/credentials/broker.ts +15 -15
- package/src/tools/credentials/metadata-store.ts +2 -2
- package/src/tools/credentials/resolve.ts +1 -1
- package/src/tools/credentials/selection.ts +1 -1
- package/src/tools/credentials/tool-policy.ts +1 -1
- package/src/tools/credentials/vault.ts +115 -25
- package/src/tools/execution-target.ts +2 -2
- package/src/tools/executor.ts +7 -7
- package/src/tools/filesystem/edit.ts +2 -2
- package/src/tools/filesystem/read.ts +15 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +18 -1
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +9 -8
- package/src/tools/mcp/mcp-tool-factory.ts +7 -6
- package/src/tools/memory/definitions.ts +6 -5
- package/src/tools/memory/handlers.test.ts +1 -1
- package/src/tools/network/__tests__/web-search.test.ts +3 -3
- package/src/tools/network/domain-normalize.ts +2 -2
- package/src/tools/network/script-proxy/session-manager.ts +10 -10
- package/src/tools/network/web-fetch.ts +1 -1
- package/src/tools/network/web-search.ts +3 -3
- package/src/tools/permission-checker.ts +8 -8
- package/src/tools/registry.ts +7 -7
- package/src/tools/schedule/list.ts +2 -2
- package/src/tools/schema-transforms.ts +31 -21
- package/src/tools/secret-detection-handler.ts +1 -1
- package/src/tools/sensitive-output-placeholders.ts +1 -1
- package/src/tools/shared/filesystem/edit-engine.ts +1 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
- package/src/tools/shared/filesystem/image-read.ts +25 -5
- package/src/tools/shared/filesystem/path-policy.ts +2 -2
- package/src/tools/shared/shell-output.ts +1 -1
- package/src/tools/side-effects.ts +1 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/skills/sandbox-runner.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -2
- package/src/tools/swarm/delegate.ts +3 -3
- package/src/tools/system/request-permission.ts +5 -4
- package/src/tools/terminal/backends/native.ts +4 -4
- package/src/tools/terminal/parser.ts +6 -6
- package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
- package/src/tools/terminal/shell.ts +16 -16
- package/src/tools/tool-approval-handler.ts +21 -12
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +3 -3
- package/src/tools/ui-surface/definitions.ts +9 -37
- package/src/tools/watcher/list.ts +1 -1
- package/src/util/logger.ts +7 -2
- package/src/util/pricing.ts +4 -0
- package/src/util/retry.ts +29 -1
- package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
- package/src/cli/reference.ts +0 -38
- package/src/memory/job-handlers/capability-cards.ts +0 -420
- package/src/runtime/routes/thread-starter-routes.ts +0 -294
|
@@ -34,7 +34,7 @@ const CONTAINER_WORKSPACE_EXACT = "/workspace";
|
|
|
34
34
|
*
|
|
35
35
|
* For existing paths, symlinks are resolved via realpathSync so a symlink
|
|
36
36
|
* pointing outside the boundary is caught. For new paths (e.g. file_write),
|
|
37
|
-
* pass `mustExist: false`
|
|
37
|
+
* pass `mustExist: false` - the nearest existing ancestor directory is
|
|
38
38
|
* resolved via realpathSync to catch symlinks in parent dirs.
|
|
39
39
|
*
|
|
40
40
|
* Paths starting with `/workspace/` are treated as container-scoped and
|
|
@@ -71,7 +71,7 @@ export function sandboxPolicy(
|
|
|
71
71
|
try {
|
|
72
72
|
realResolved = realpathSync(resolved);
|
|
73
73
|
} catch {
|
|
74
|
-
// File doesn't exist
|
|
74
|
+
// File doesn't exist - will be caught by the tool's own existence check
|
|
75
75
|
realResolved = resolved;
|
|
76
76
|
}
|
|
77
77
|
} else {
|
|
@@ -9,7 +9,7 @@ export interface ShellOutputResult {
|
|
|
9
9
|
/**
|
|
10
10
|
* Format the raw stdout/stderr/exit-code from a spawned shell command into the
|
|
11
11
|
* final tool result. Both `shell.ts` (sandbox bash) and `host-shell.ts`
|
|
12
|
-
* (host_bash) must produce identical output formatting
|
|
12
|
+
* (host_bash) must produce identical output formatting - this shared function
|
|
13
13
|
* is the single source of truth for that logic.
|
|
14
14
|
*/
|
|
15
15
|
export function formatShellOutput(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Side-effect tool classification
|
|
1
|
+
// Side-effect tool classification - single source of truth.
|
|
2
2
|
// Tools that modify state outside the assistant (filesystem writes,
|
|
3
3
|
// shell commands, network requests that trigger actions, etc.).
|
|
4
4
|
// Used by private-conversation gating and permission simulation to decide
|
|
@@ -27,7 +27,7 @@ export class SkillExecuteTool implements Tool {
|
|
|
27
27
|
description:
|
|
28
28
|
"Tool-specific parameters as documented in the skill's instructions",
|
|
29
29
|
},
|
|
30
|
-
|
|
30
|
+
activity: {
|
|
31
31
|
type: "string",
|
|
32
32
|
description:
|
|
33
33
|
"Brief non-technical explanation of what you are doing and why, shown to the user as a status update.",
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -113,7 +113,7 @@ function formatToolSchemas(
|
|
|
113
113
|
export class SkillLoadTool implements Tool {
|
|
114
114
|
name = "skill_load";
|
|
115
115
|
description =
|
|
116
|
-
"Load full instructions for a
|
|
116
|
+
"Load full instructions for a skill. Works for both bundled skills (listed in the catalog) and workspace skills in ~/.vellum/workspace/skills.";
|
|
117
117
|
category = "skills";
|
|
118
118
|
defaultRiskLevel = RiskLevel.Low;
|
|
119
119
|
|
|
@@ -249,7 +249,7 @@ export class SkillLoadTool implements Tool {
|
|
|
249
249
|
catalogIndex = indexCatalogById(catalog);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
// Validate (fail-closed
|
|
252
|
+
// Validate (fail-closed - catches genuinely missing deps + cycles)
|
|
253
253
|
const validation = validateIncludes(skill.id, catalogIndex);
|
|
254
254
|
if (!validation.ok) {
|
|
255
255
|
if (validation.error === "missing") {
|
|
@@ -307,7 +307,7 @@ export class SkillLoadTool implements Tool {
|
|
|
307
307
|
continue;
|
|
308
308
|
|
|
309
309
|
childLines.push(
|
|
310
|
-
` - ${child.id}: ${child.displayName}
|
|
310
|
+
` - ${child.id}: ${child.displayName} - ${child.description} (${child.skillFilePath})`,
|
|
311
311
|
);
|
|
312
312
|
|
|
313
313
|
// Load the included skill's body content
|
|
@@ -204,7 +204,7 @@ function spawnRunner(
|
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
// No structured result
|
|
207
|
+
// No structured result - fall back to raw output
|
|
208
208
|
if (code !== 0) {
|
|
209
209
|
const truncatedStderr =
|
|
210
210
|
stderr.length > MAX_OUTPUT_CHARS
|
|
@@ -261,7 +261,7 @@ function parseSkillResult(
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
} catch {
|
|
264
|
-
// malformed line
|
|
264
|
+
// malformed line - keep scanning
|
|
265
265
|
}
|
|
266
266
|
searchFrom = lineStart;
|
|
267
267
|
}
|
|
@@ -285,7 +285,7 @@ function parseSkillResult(
|
|
|
285
285
|
};
|
|
286
286
|
}
|
|
287
287
|
} catch {
|
|
288
|
-
// malformed line
|
|
288
|
+
// malformed line - keep scanning
|
|
289
289
|
}
|
|
290
290
|
searchFrom = lineStart;
|
|
291
291
|
}
|
|
@@ -44,7 +44,7 @@ export async function executeSubagentRead(
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// Extract assistant messages only
|
|
47
|
+
// Extract assistant messages only - that's the subagent's output.
|
|
48
48
|
const output: string[] = [];
|
|
49
49
|
for (const msg of dbMessages) {
|
|
50
50
|
if (msg.role !== "assistant") continue;
|
|
@@ -23,7 +23,7 @@ export async function executeSubagentSpawn(
|
|
|
23
23
|
| undefined;
|
|
24
24
|
if (!sendToClient) {
|
|
25
25
|
return {
|
|
26
|
-
content: "No client connected
|
|
26
|
+
content: "No client connected - cannot spawn subagent.",
|
|
27
27
|
isError: true,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -45,7 +45,7 @@ export async function executeSubagentSpawn(
|
|
|
45
45
|
subagentId,
|
|
46
46
|
label,
|
|
47
47
|
status: "pending",
|
|
48
|
-
message: `Subagent "${label}" spawned. You will be notified automatically when it completes or fails
|
|
48
|
+
message: `Subagent "${label}" spawned. You will be notified automatically when it completes or fails - do NOT poll subagent_status. Continue the conversation normally.`,
|
|
49
49
|
}),
|
|
50
50
|
isError: false,
|
|
51
51
|
};
|
|
@@ -73,7 +73,7 @@ export const swarmDelegateTool: Tool = {
|
|
|
73
73
|
return { content: "Cancelled", isError: true };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// Recursion guard
|
|
76
|
+
// Recursion guard - scoped to conversation so independent conversations are not blocked
|
|
77
77
|
const conversationKey = context.conversationId;
|
|
78
78
|
if (activeConversations.has(conversationKey)) {
|
|
79
79
|
return {
|
|
@@ -129,7 +129,7 @@ export const swarmDelegateTool: Tool = {
|
|
|
129
129
|
config.providerOrder,
|
|
130
130
|
);
|
|
131
131
|
} catch {
|
|
132
|
-
// No provider available for synthesis
|
|
132
|
+
// No provider available for synthesis - will use fallback
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
const summary = await executeSwarm({
|
|
@@ -199,7 +199,7 @@ export const swarmDelegateTool: Tool = {
|
|
|
199
199
|
},
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
-
/** Clear all active conversations
|
|
202
|
+
/** Clear all active conversations - only for testing. */
|
|
203
203
|
export function _resetSwarmActive(): void {
|
|
204
204
|
activeConversations.clear();
|
|
205
205
|
}
|
|
@@ -53,8 +53,9 @@ const FRIENDLY_NAMES: Record<PermissionType, string> = {
|
|
|
53
53
|
class RequestSystemPermissionTool implements Tool {
|
|
54
54
|
name = "request_system_permission";
|
|
55
55
|
description =
|
|
56
|
-
"Ask the user to grant a macOS system permission
|
|
57
|
-
"Use
|
|
56
|
+
"Ask the user to grant a macOS system permission via System Settings. " +
|
|
57
|
+
"Use when a tool fails with a permission/access error (e.g. 'Operation not permitted', 'EACCES', sandbox denial). " +
|
|
58
|
+
"Do not explain how to open System Settings manually - this tool handles it with a clickable button.";
|
|
58
59
|
category = "system";
|
|
59
60
|
defaultRiskLevel = RiskLevel.High;
|
|
60
61
|
|
|
@@ -70,13 +71,13 @@ class RequestSystemPermissionTool implements Tool {
|
|
|
70
71
|
enum: [...PERMISSION_TYPES],
|
|
71
72
|
description: "The macOS system permission to request",
|
|
72
73
|
},
|
|
73
|
-
|
|
74
|
+
activity: {
|
|
74
75
|
type: "string",
|
|
75
76
|
description:
|
|
76
77
|
"Short explanation of why this permission is needed (shown to the user)",
|
|
77
78
|
},
|
|
78
79
|
},
|
|
79
|
-
required: ["permission_type", "
|
|
80
|
+
required: ["permission_type", "activity"],
|
|
80
81
|
},
|
|
81
82
|
};
|
|
82
83
|
}
|
|
@@ -31,12 +31,12 @@ function buildSandboxProfile(
|
|
|
31
31
|
denyReadPaths?: string[],
|
|
32
32
|
): string {
|
|
33
33
|
const networkRule = allowNetwork
|
|
34
|
-
? ";; Allow network access (proxied mode
|
|
34
|
+
? ";; Allow network access (proxied mode - needed to reach the credential proxy)\n(allow network*)"
|
|
35
35
|
: ";; Block network access\n(deny network*)";
|
|
36
36
|
|
|
37
37
|
// Build deny-read rules for protected paths (CES shell lockdown).
|
|
38
38
|
// These are placed AFTER the allow file-read* rule because SBPL uses
|
|
39
|
-
// last-match-wins semantics
|
|
39
|
+
// last-match-wins semantics - the more specific deny overrides the
|
|
40
40
|
// general allow.
|
|
41
41
|
const denyReadRules =
|
|
42
42
|
denyReadPaths && denyReadPaths.length > 0
|
|
@@ -149,13 +149,13 @@ let bwrapAvailable = false;
|
|
|
149
149
|
/**
|
|
150
150
|
* Check whether bwrap is installed AND functional (can create namespaces).
|
|
151
151
|
*
|
|
152
|
-
* Just testing `bwrap --version` is not enough
|
|
152
|
+
* Just testing `bwrap --version` is not enough - the binary may exist but
|
|
153
153
|
* namespace creation can be blocked by the kernel (e.g. inside containers
|
|
154
154
|
* or when user namespaces are disabled). We run a minimal sandbox that
|
|
155
155
|
* exercises all namespace types used by buildBwrapArgs() (mount, network,
|
|
156
156
|
* PID) to verify end-to-end functionality.
|
|
157
157
|
*
|
|
158
|
-
* Only positive results are cached
|
|
158
|
+
* Only positive results are cached - if bwrap is unavailable, we re-check
|
|
159
159
|
* on every call so that a mid-session install is picked up immediately.
|
|
160
160
|
*/
|
|
161
161
|
function isBwrapAvailable(): boolean {
|
|
@@ -38,7 +38,7 @@ export interface ParsedCommand {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const SHELL_PROGRAMS = new Set(["sh", "bash", "zsh", "dash", "ksh", "fish"]);
|
|
41
|
-
// Script interpreters that can execute arbitrary code from stdin
|
|
41
|
+
// Script interpreters that can execute arbitrary code from stdin - piping
|
|
42
42
|
// untrusted data into these is as dangerous as piping into a shell.
|
|
43
43
|
const SCRIPT_INTERPRETERS = new Set([
|
|
44
44
|
"python",
|
|
@@ -55,7 +55,7 @@ const STDIN_EXEC_FLAGS = new Set(["-c", "-e", "-"]);
|
|
|
55
55
|
// Per-interpreter flags that consume the next argument as a value (not a filename).
|
|
56
56
|
// Mapped by interpreter name since flags differ across interpreters
|
|
57
57
|
// (e.g. -I is standalone in Python but takes a value in Ruby).
|
|
58
|
-
// Note: `-m` is intentionally excluded
|
|
58
|
+
// Note: `-m` is intentionally excluded - it means "run module", so the next arg
|
|
59
59
|
// is a module name and the interpreter is NOT in stdin-exec mode.
|
|
60
60
|
const INTERPRETER_VALUE_FLAGS: ReadonlyMap<
|
|
61
61
|
string,
|
|
@@ -128,7 +128,7 @@ const initGuard = new PromiseGuard<void>();
|
|
|
128
128
|
* In development / `bunx` the file lives under `node_modules/` relative
|
|
129
129
|
* to the source tree. In compiled Bun binaries `import.meta.dirname`
|
|
130
130
|
* points into the virtual `/$bunfs/` filesystem where binary assets
|
|
131
|
-
* don't exist
|
|
131
|
+
* don't exist - fall back to:
|
|
132
132
|
* 1. `../Resources/<file>` (macOS .app bundle layout)
|
|
133
133
|
* 2. Next to the compiled binary (process.execPath)
|
|
134
134
|
* This matches the pattern used for compiled Bun binary asset resolution.
|
|
@@ -352,7 +352,7 @@ function extractSegments(node: TSNode): CommandSegment[] {
|
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
/**
|
|
355
|
-
* Returns true when the interpreter args indicate stdin-exec mode
|
|
355
|
+
* Returns true when the interpreter args indicate stdin-exec mode - i.e. the
|
|
356
356
|
* interpreter will read code from stdin (or from an inline -c/-e argument)
|
|
357
357
|
* rather than from a file. Concretely:
|
|
358
358
|
* - Any STDIN_EXEC_FLAGS present → stdin-exec
|
|
@@ -367,7 +367,7 @@ function isStdinExecMode(interpreter: string, args: string[]): boolean {
|
|
|
367
367
|
if (STDIN_EXEC_FLAGS.has(arg)) return true;
|
|
368
368
|
// First non-flag argument is a filename/module → file mode
|
|
369
369
|
if (!arg.startsWith("-")) return false;
|
|
370
|
-
// Flags like -W, -X consume the next token as their value
|
|
370
|
+
// Flags like -W, -X consume the next token as their value - skip it
|
|
371
371
|
if (valueFlags.has(arg)) i++;
|
|
372
372
|
}
|
|
373
373
|
// No positional arguments at all → interpreter reads from stdin
|
|
@@ -581,7 +581,7 @@ export async function parse(command: string): Promise<ParsedCommand> {
|
|
|
581
581
|
const parser = await ensureParser();
|
|
582
582
|
const tree = parser.parse(command);
|
|
583
583
|
if (!tree) {
|
|
584
|
-
// Parser couldn't parse
|
|
584
|
+
// Parser couldn't parse - treat as opaque
|
|
585
585
|
return { segments: [], dangerousPatterns: [], hasOpaqueConstructs: true };
|
|
586
586
|
}
|
|
587
587
|
const rootNode = tree.rootNode;
|
|
@@ -39,13 +39,13 @@ function buildCredentialRefTrace(
|
|
|
39
39
|
* inside the sandbox when CES shell lockdown is active.
|
|
40
40
|
*
|
|
41
41
|
* Protected paths include:
|
|
42
|
-
* - ~/.vellum/protected/
|
|
42
|
+
* - ~/.vellum/protected/ - credential store secrets (also covers local-mode
|
|
43
43
|
* CES data root at ~/.vellum/protected/credential-executor/)
|
|
44
|
-
* - ~/.vellum/workspace/data/db/
|
|
45
|
-
* - CES bootstrap socket directory (/run/ces-bootstrap/ or CES_BOOTSTRAP_SOCKET_DIR)
|
|
44
|
+
* - ~/.vellum/workspace/data/db/ - database files that may contain credential metadata
|
|
45
|
+
* - CES bootstrap socket directory (/run/ces-bootstrap/ or CES_BOOTSTRAP_SOCKET_DIR) -
|
|
46
46
|
* prevents untrusted shells from connecting to the CES sidecar directly
|
|
47
47
|
* - CES managed-mode data root (CES_DATA_DIR, or /ces-data when
|
|
48
|
-
* CES_MANAGED_MODE is set)
|
|
48
|
+
* CES_MANAGED_MODE is set) - prevents access to CES-private state in
|
|
49
49
|
* managed deployments (local-mode is already covered by the protected/
|
|
50
50
|
* entry)
|
|
51
51
|
*/
|
|
@@ -53,7 +53,7 @@ function buildCesProtectedPaths(): string[] {
|
|
|
53
53
|
const root = getRootDir();
|
|
54
54
|
const paths = [`${root}/protected`, `${root}/workspace/data/db`];
|
|
55
55
|
|
|
56
|
-
// CES bootstrap socket directory
|
|
56
|
+
// CES bootstrap socket directory - block access to the Unix socket that
|
|
57
57
|
// accepts RPC commands from the assistant process.
|
|
58
58
|
const bootstrapSocketDir =
|
|
59
59
|
process.env["CES_BOOTSTRAP_SOCKET_DIR"] || "/run/ces-bootstrap";
|
|
@@ -68,7 +68,7 @@ function buildCesProtectedPaths(): string[] {
|
|
|
68
68
|
paths.push(dirname(process.env["CES_BOOTSTRAP_SOCKET"]));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// CES managed-mode private data root
|
|
71
|
+
// CES managed-mode private data root - in managed deployments the CES
|
|
72
72
|
// data lives outside the Vellum root, so it isn't covered by the
|
|
73
73
|
// `protected/` entry above.
|
|
74
74
|
const cesDataDir = process.env["CES_DATA_DIR"];
|
|
@@ -100,7 +100,7 @@ class ShellTool implements Tool {
|
|
|
100
100
|
type: "string",
|
|
101
101
|
description: "The shell command to execute",
|
|
102
102
|
},
|
|
103
|
-
|
|
103
|
+
activity: {
|
|
104
104
|
type: "string",
|
|
105
105
|
description:
|
|
106
106
|
'Brief non-technical explanation of what this command does and why, shown to a non-technical user in the permission prompt. Avoid jargon and technical terms. Good: "to check if a required program is installed on your computer". Bad: "to check if gcloud CLI is installed". Good: "to download a helper program". Bad: "to run npm install".',
|
|
@@ -123,7 +123,7 @@ class ShellTool implements Tool {
|
|
|
123
123
|
'Optional list of credential IDs to inject via the proxy when network_mode is "proxied".',
|
|
124
124
|
},
|
|
125
125
|
},
|
|
126
|
-
required: ["command", "
|
|
126
|
+
required: ["command", "activity"],
|
|
127
127
|
},
|
|
128
128
|
};
|
|
129
129
|
}
|
|
@@ -140,7 +140,7 @@ class ShellTool implements Tool {
|
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
// Reject commands containing null bytes
|
|
143
|
+
// Reject commands containing null bytes - they cause truncation at the
|
|
144
144
|
// OS level while the parser sees the full string, enabling bypass.
|
|
145
145
|
if (command.includes("\0")) {
|
|
146
146
|
return { content: "Error: command contains null bytes", isError: true };
|
|
@@ -155,7 +155,7 @@ class ShellTool implements Tool {
|
|
|
155
155
|
input.network_mode === "proxied" ? "proxied" : "off";
|
|
156
156
|
|
|
157
157
|
// -----------------------------------------------------------------------
|
|
158
|
-
// CES shell lockdown
|
|
158
|
+
// CES shell lockdown - reject proxied credential sessions for untrusted
|
|
159
159
|
// actors when the lockdown flag is active. Proxied sessions grant the
|
|
160
160
|
// subprocess access to credentials through the egress proxy, which
|
|
161
161
|
// violates the secrecy guarantee.
|
|
@@ -183,7 +183,7 @@ class ShellTool implements Tool {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// -----------------------------------------------------------------------
|
|
186
|
-
// CES shell lockdown
|
|
186
|
+
// CES shell lockdown - reject non-empty credential-ref mode for untrusted
|
|
187
187
|
// actors. Even when network_mode is "off", passing credential_ids could
|
|
188
188
|
// allow the model to probe stored credential metadata.
|
|
189
189
|
// -----------------------------------------------------------------------
|
|
@@ -201,7 +201,7 @@ class ShellTool implements Tool {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
// Resolve credential refs (UUID or service/field) to canonical UUIDs.
|
|
204
|
-
// Fail fast if any ref is unresolvable
|
|
204
|
+
// Fail fast if any ref is unresolvable - partial execution with missing
|
|
205
205
|
// credentials is worse than a clear error.
|
|
206
206
|
const credentialIds: string[] = [];
|
|
207
207
|
if (networkMode === "proxied" && rawCredentialRefs.length > 0) {
|
|
@@ -264,7 +264,7 @@ class ShellTool implements Tool {
|
|
|
264
264
|
"Executing shell command",
|
|
265
265
|
);
|
|
266
266
|
|
|
267
|
-
// Resolve sandbox config early
|
|
267
|
+
// Resolve sandbox config early - needed both for proxy env and command wrapping.
|
|
268
268
|
const sandboxConfig =
|
|
269
269
|
context.sandboxOverride != null
|
|
270
270
|
? { ...config.sandbox, enabled: context.sandboxOverride }
|
|
@@ -273,7 +273,7 @@ class ShellTool implements Tool {
|
|
|
273
273
|
// Acquire proxy session if proxied mode is requested.
|
|
274
274
|
// `getOrStartSession` serializes per-conversation so concurrent proxied
|
|
275
275
|
// commands share a single session instead of each creating one.
|
|
276
|
-
// Sessions are NOT stopped here
|
|
276
|
+
// Sessions are NOT stopped here - the session manager's idle timer handles
|
|
277
277
|
// cleanup after all commands finish (see resetIdleTimer / stopAllSessions).
|
|
278
278
|
let proxyEnv: ProxyEnvVars | null = null;
|
|
279
279
|
|
|
@@ -291,7 +291,7 @@ class ShellTool implements Tool {
|
|
|
291
291
|
} catch (err) {
|
|
292
292
|
log.error({ err }, "Failed to start proxy session");
|
|
293
293
|
return {
|
|
294
|
-
content: `Error: failed to start proxy session
|
|
294
|
+
content: `Error: failed to start proxy session - ${
|
|
295
295
|
err instanceof Error ? err.message : String(err)
|
|
296
296
|
}`,
|
|
297
297
|
isError: true,
|
|
@@ -385,7 +385,7 @@ class ShellTool implements Tool {
|
|
|
385
385
|
resolve({
|
|
386
386
|
content: `Error spawning command: ${err.message}${
|
|
387
387
|
(err as NodeJS.ErrnoException).code === "ENOENT"
|
|
388
|
-
? ". The command was not found
|
|
388
|
+
? ". The command was not found - check that it is installed and in PATH."
|
|
389
389
|
: ""
|
|
390
390
|
}`,
|
|
391
391
|
isError: true,
|
|
@@ -82,7 +82,7 @@ export async function waitForInlineGrant(
|
|
|
82
82
|
return { outcome: "aborted" };
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// Check if the canonical request was rejected
|
|
85
|
+
// Check if the canonical request was rejected - exit early without
|
|
86
86
|
// waiting for the full timeout.
|
|
87
87
|
const request = getCanonicalGuardianRequest(escalationRequestId);
|
|
88
88
|
if (request && request.status === "denied") {
|
|
@@ -98,7 +98,7 @@ export async function waitForInlineGrant(
|
|
|
98
98
|
return { outcome: "denied", requestId: escalationRequestId };
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
// Try to consume the grant
|
|
101
|
+
// Try to consume the grant - if the guardian approved, the canonical
|
|
102
102
|
// decision primitive will have minted a scoped grant by now.
|
|
103
103
|
const grantResult = await consumeGrantForInvocation(consumeParams, {
|
|
104
104
|
maxWaitMs: 0,
|
|
@@ -112,7 +112,7 @@ export async function waitForInlineGrant(
|
|
|
112
112
|
grantId: grantResult.grant.id,
|
|
113
113
|
elapsedMs: maxWait - (deadline - Date.now()),
|
|
114
114
|
},
|
|
115
|
-
"Grant found during inline wait
|
|
115
|
+
"Grant found during inline wait - tool execution proceeding",
|
|
116
116
|
);
|
|
117
117
|
return { outcome: "granted", grant: { id: grantResult.grant.id } };
|
|
118
118
|
}
|
|
@@ -125,16 +125,25 @@ export async function waitForInlineGrant(
|
|
|
125
125
|
toolName: consumeParams.toolName,
|
|
126
126
|
maxWaitMs: maxWait,
|
|
127
127
|
},
|
|
128
|
-
"Inline grant wait timed out
|
|
128
|
+
"Inline grant wait timed out - no guardian decision within budget",
|
|
129
129
|
);
|
|
130
130
|
return { outcome: "timeout", requestId: escalationRequestId };
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
const UI_SURFACE_TOOLS = new Set(["ui_show", "ui_update", "ui_dismiss"]);
|
|
134
|
+
|
|
133
135
|
function requiresGuardianApprovalForActor(
|
|
134
136
|
toolName: string,
|
|
135
137
|
input: Record<string, unknown>,
|
|
136
138
|
executionTarget: ExecutionTarget,
|
|
137
139
|
): boolean {
|
|
140
|
+
// UI surface tools are passive, user-visible operations (cards, forms,
|
|
141
|
+
// tables). User input is voluntary and user-controlled — skip the guardian
|
|
142
|
+
// gate so they work during fresh onboarding before trust is established.
|
|
143
|
+
if (UI_SURFACE_TOOLS.has(toolName)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
138
147
|
// Side-effect tools always require guardian approval for untrusted actors.
|
|
139
148
|
// Read-only host execution is also blocked because it can leak sensitive
|
|
140
149
|
// local information (e.g. shell/file reads).
|
|
@@ -425,13 +434,13 @@ export class ToolApprovalHandler {
|
|
|
425
434
|
executionTarget,
|
|
426
435
|
grantId: grantResult.grant.id,
|
|
427
436
|
},
|
|
428
|
-
"Scoped grant consumed
|
|
437
|
+
"Scoped grant consumed - allowing untrusted actor tool invocation",
|
|
429
438
|
);
|
|
430
439
|
|
|
431
440
|
return { allowed: true, tool, grantConsumed: true };
|
|
432
441
|
}
|
|
433
442
|
|
|
434
|
-
// Treat abort as a cancellation
|
|
443
|
+
// Treat abort as a cancellation - not a grant denial. This matches
|
|
435
444
|
// the abort check at the top of checkPreExecutionGates so the caller
|
|
436
445
|
// sees a consistent "Cancelled" result instead of a spurious
|
|
437
446
|
// guardian_approval_required denial during voice barge-in.
|
|
@@ -458,12 +467,12 @@ export class ToolApprovalHandler {
|
|
|
458
467
|
};
|
|
459
468
|
}
|
|
460
469
|
|
|
461
|
-
// No matching grant or race condition
|
|
470
|
+
// No matching grant or race condition - deny or wait inline.
|
|
462
471
|
//
|
|
463
472
|
// For verified non-guardian actors (trusted_contact) with sufficient
|
|
464
473
|
// context, escalate to the guardian by creating a canonical
|
|
465
474
|
// tool_grant_request. Then wait bounded for the grant to become
|
|
466
|
-
// available
|
|
475
|
+
// available - this lets the tool call succeed inline after guardian
|
|
467
476
|
// approval without the requester having to retry manually.
|
|
468
477
|
//
|
|
469
478
|
// Unverified actors remain fail-closed with no escalation or wait.
|
|
@@ -524,7 +533,7 @@ export class ToolApprovalHandler {
|
|
|
524
533
|
grantId: waitResult.grant.id,
|
|
525
534
|
escalationRequestId: escalation.requestId,
|
|
526
535
|
},
|
|
527
|
-
"Inline grant wait succeeded
|
|
536
|
+
"Inline grant wait succeeded - allowing trusted contact tool invocation",
|
|
528
537
|
);
|
|
529
538
|
return { allowed: true, tool, grantConsumed: true };
|
|
530
539
|
}
|
|
@@ -589,7 +598,7 @@ export class ToolApprovalHandler {
|
|
|
589
598
|
waitOutcome: waitResult.outcome,
|
|
590
599
|
escalationRequestId: escalation.requestId,
|
|
591
600
|
},
|
|
592
|
-
"Inline grant wait ended without approval
|
|
601
|
+
"Inline grant wait ended without approval - denying trusted contact tool invocation",
|
|
593
602
|
);
|
|
594
603
|
const durationMs = Date.now() - startTime;
|
|
595
604
|
emitLifecycleEvent({
|
|
@@ -610,10 +619,10 @@ export class ToolApprovalHandler {
|
|
|
610
619
|
result: { content: escalationMessage, isError: true },
|
|
611
620
|
};
|
|
612
621
|
}
|
|
613
|
-
// escalation.failed
|
|
622
|
+
// escalation.failed - fall through to generic denial.
|
|
614
623
|
}
|
|
615
624
|
|
|
616
|
-
// Unknown/unverified actors or escalation failures
|
|
625
|
+
// Unknown/unverified actors or escalation failures - generic denial.
|
|
617
626
|
const reason = guardianApprovalDeniedMessage(context.trustClass, name);
|
|
618
627
|
log.warn(
|
|
619
628
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Declarative tool manifest
|
|
2
|
+
* Declarative tool manifest - single place to inspect what gets registered.
|
|
3
3
|
*
|
|
4
4
|
* Each entry describes HOW a tool (or group of tools) gets loaded and
|
|
5
5
|
* registered. `initializeTools()` in `registry.ts` iterates this list
|
|
@@ -73,7 +73,7 @@ export const eagerModuleToolNames: string[] = [
|
|
|
73
73
|
// a test registry reset) and tools that have always been explicit.
|
|
74
74
|
|
|
75
75
|
export const explicitTools: Tool[] = [
|
|
76
|
-
// Previously-eager tools
|
|
76
|
+
// Previously-eager tools - kept here so initializeTools() can re-register
|
|
77
77
|
// them after __resetRegistryForTesting() clears the registry (ESM caching
|
|
78
78
|
// prevents their side-effect registrations from re-running).
|
|
79
79
|
shellTool,
|
|
@@ -99,7 +99,7 @@ export const explicitTools: Tool[] = [
|
|
|
99
99
|
// This list is intentionally separate from `explicitTools` so that
|
|
100
100
|
// initializeTools() in registry.ts can conditionally include them.
|
|
101
101
|
|
|
102
|
-
/** All CES tools
|
|
102
|
+
/** All CES tools - stable references for the manifest snapshot. */
|
|
103
103
|
export const cesTools: Tool[] = [
|
|
104
104
|
makeAuthenticatedRequestTool,
|
|
105
105
|
runAuthenticatedCommandTool,
|
|
@@ -123,7 +123,7 @@ export function getCesToolsIfEnabled(): Tool[] {
|
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
125
|
} catch {
|
|
126
|
-
// Config not yet loaded (e.g. during test setup)
|
|
126
|
+
// Config not yet loaded (e.g. during test setup) - CES tools stay off.
|
|
127
127
|
}
|
|
128
128
|
return [];
|
|
129
129
|
}
|
package/src/tools/types.ts
CHANGED
|
@@ -114,7 +114,7 @@ export interface ToolContext {
|
|
|
114
114
|
sandboxOverride?: boolean;
|
|
115
115
|
/** Optional callback for tool lifecycle events (start/prompt/deny/execute/error/secret_detected). */
|
|
116
116
|
onToolLifecycleEvent?: ToolLifecycleEventHandler;
|
|
117
|
-
/** Optional resolver for proxy tools
|
|
117
|
+
/** Optional resolver for proxy tools - delegates execution to an external client. */
|
|
118
118
|
proxyToolResolver?: ProxyToolResolver;
|
|
119
119
|
/** When set, only tools in this set may execute. Tools outside the set are blocked with an error. */
|
|
120
120
|
allowedToolNames?: Set<string>;
|
|
@@ -147,7 +147,7 @@ export interface ToolContext {
|
|
|
147
147
|
forcePromptSideEffects?: boolean;
|
|
148
148
|
/**
|
|
149
149
|
* When true, the tool requires a fresh interactive approval for every
|
|
150
|
-
* invocation
|
|
150
|
+
* invocation - no cached grants, temporary overrides, persistent
|
|
151
151
|
* "Always Allow" rules, or non-interactive auto-approve shortcuts may
|
|
152
152
|
* bypass the prompt. This flag is independently sufficient: it
|
|
153
153
|
* promotes allow → prompt decisions on its own and suppresses
|
|
@@ -231,7 +231,7 @@ export interface ToolExecutionResult {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
// ---------------------------------------------------------------------------
|
|
234
|
-
// Proxy approval types
|
|
234
|
+
// Proxy approval types - local definitions for the outbound-proxy contract.
|
|
235
235
|
// The proxy service owns the canonical shapes; these are the assistant's
|
|
236
236
|
// minimal view of the approval callback interface.
|
|
237
237
|
// ---------------------------------------------------------------------------
|
|
@@ -28,43 +28,15 @@ function proxyExecute(): Promise<ToolExecutionResult> {
|
|
|
28
28
|
export const uiShowTool: Tool = {
|
|
29
29
|
name: "ui_show",
|
|
30
30
|
description:
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"- card:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
' Template "task_progress": renders a live-updating task progress widget showing structured step-by-step progress. ' +
|
|
41
|
-
'templateData shape: { title: string, status: "in_progress"|"completed"|"failed", ' +
|
|
42
|
-
'steps: Array<{ label: string, status: "pending"|"in_progress"|"completed"|"failed", detail?: string }> }\n' +
|
|
43
|
-
"- table: Data table with columns, selectable rows, and action buttons. " +
|
|
44
|
-
'data shape: { columns: Array<{ id: string, label: string, width?: number }>, rows: Array<{ id: string, cells: Record<string, string | { text: string, icon?: string, iconColor?: "success"|"warning"|"error"|"muted" }>, selectable?: boolean, selected?: boolean }>, selectionMode?: "none"|"single"|"multiple", caption?: string }. ' +
|
|
45
|
-
"Cell values can be plain strings or rich objects with icon (SF Symbol name) and iconColor. " +
|
|
46
|
-
"Column width is in points — use it for narrow columns (e.g. counts, short labels) so flexible columns get more space. Omit width for columns that should expand.\n" +
|
|
47
|
-
"- form: Input form with typed fields. " +
|
|
48
|
-
'data shape: { description?: string, fields: Array<{ id: string, type: "text"|"textarea"|"select"|"toggle"|"number"|"password", label: string, placeholder?: string, required?: boolean, defaultValue?: string|number|boolean, options?: Array<{ label: string, value: string }> }>, submitLabel?: string }. ' +
|
|
49
|
-
"For multi-page forms, use pages array instead of top-level fields: { pages: [{ id: string, title: string, description?: string, fields: [...] }], pageLabels?: { next?: string, back?: string, submit?: string }, submitLabel?: string }\n" +
|
|
50
|
-
"- list: Selectable list of items. " +
|
|
51
|
-
'data shape: { items: Array<{ id: string, title: string, subtitle?: string, icon?: string, selected?: boolean }>, selectionMode: "single"|"multiple"|"none" }\n' +
|
|
52
|
-
"- confirmation: Yes/no confirmation dialog. " +
|
|
53
|
-
"data shape: { message: string, detail?: string, confirmLabel?: string, confirmedLabel?: string, cancelLabel?: string, destructive?: boolean }\n" +
|
|
54
|
-
"- dynamic_page: Custom HTML page rendered in a sandboxed container. " +
|
|
55
|
-
"data shape: { html: string, width?: number, height?: number, preview?: { title: string, subtitle?: string, description?: string, icon?: string (emoji), metrics?: Array<{ label: string, value: string }> } }. " +
|
|
56
|
-
'When preview is provided, a compact preview card is shown inline in chat with the title, subtitle, description, metric pills, and a "View Output" button that opens the full page.\n' +
|
|
57
|
-
"- file_upload: File upload dialog where the user can drag-and-drop or browse for files. " +
|
|
58
|
-
"data shape: { prompt: string, acceptedTypes?: string[], maxFiles?: number }\n\n" +
|
|
59
|
-
"Action payload conventions:\n" +
|
|
60
|
-
"- Multi-select tables: use `window.vellum.sendAction(actionId, { selectedIds: [...] })` to send selected row IDs\n" +
|
|
61
|
-
"- Bulk actions: include `selectedRows` array with full row data for context\n\n" +
|
|
62
|
-
"Presenting choices: When the user needs to make a choice or provide structured input, prefer interactive surfaces over plain text. " +
|
|
63
|
-
"Use list (2-8 options, single select), form (structured input with typed fields), confirmation (destructive/important actions), or table (data review with selectable rows).\n\n" +
|
|
64
|
-
"Tool chaining: After gathering data via tools (web search, browser, APIs), synthesize results into a visual output.\n\n" +
|
|
65
|
-
'Task progress for multi-step workflows: Create a card with template "task_progress" and templateData containing steps. ' +
|
|
66
|
-
"As each step completes, call ui_update to patch data.templateData (not top-level fields). " +
|
|
67
|
-
'Set templateData.status to "completed" or "failed" when done.',
|
|
31
|
+
"Show structured data or UI to the user. For long-form writing use the document skill; for interactive apps use the app-builder skill.\n\n" +
|
|
32
|
+
"Surface types (data shapes):\n" +
|
|
33
|
+
"- card: { title, subtitle?, body, metadata?: [{ label, value }], template?, templateData? }. Templates: \"weather_forecast\" (native weather widget), \"task_progress\" (live step tracker - update via ui_update on data.templateData; shape: { title, status: \"in_progress\"|\"completed\"|\"failed\", steps: [{ label, status: \"pending\"|\"in_progress\"|\"completed\"|\"failed\", detail? }] })\n" +
|
|
34
|
+
'- table: { columns: [{ id, label, width? }], rows: [{ id, cells: Record<id, string | { text, icon?, iconColor?: "success"|"warning"|"error"|"muted" }>, selectable?, selected? }], selectionMode?: "none"|"single"|"multiple", caption? }\n' +
|
|
35
|
+
'- form: { description?, fields: [{ id, type: "text"|"textarea"|"select"|"toggle"|"number"|"password", label, placeholder?, required?, defaultValue?, options?: [{ label, value }] }], submitLabel? }. Multi-page: { pages: [{ id, title, description?, fields }], pageLabels?: { next?, back?, submit? }, submitLabel? }\n' +
|
|
36
|
+
'- list: { items: [{ id, title, subtitle?, icon?, selected? }], selectionMode: "single"|"multiple"|"none" }\n' +
|
|
37
|
+
"- confirmation: { message, detail?, confirmLabel?, confirmedLabel?, cancelLabel?, destructive? }\n" +
|
|
38
|
+
"- dynamic_page: { html, width?, height?, preview?: { title, subtitle?, description?, icon?, metrics?: [{ label, value }] } }\n" +
|
|
39
|
+
"- file_upload: { prompt, acceptedTypes?, maxFiles? }",
|
|
68
40
|
category: "ui-surface",
|
|
69
41
|
defaultRiskLevel: RiskLevel.Low,
|
|
70
42
|
executionMode: "proxy",
|