@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
|
@@ -52,13 +52,13 @@ export interface BrowserFillRequest {
|
|
|
52
52
|
toolName: string;
|
|
53
53
|
domain?: string;
|
|
54
54
|
/**
|
|
55
|
-
* Opaque fill callback
|
|
55
|
+
* Opaque fill callback - the broker calls this with the plaintext value internally.
|
|
56
56
|
* The caller provides the fill function but never receives the secret value.
|
|
57
57
|
*/
|
|
58
58
|
fill: (value: string) => Promise<void>;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/** Result of a broker-mediated browser fill
|
|
61
|
+
/** Result of a broker-mediated browser fill - contains only metadata, never plaintext. */
|
|
62
62
|
export interface BrowserFillResult {
|
|
63
63
|
success: boolean;
|
|
64
64
|
reason?: string;
|
|
@@ -70,13 +70,13 @@ export interface ServerUseRequest<T> {
|
|
|
70
70
|
field: string;
|
|
71
71
|
toolName: string;
|
|
72
72
|
/**
|
|
73
|
-
* Opaque callback
|
|
73
|
+
* Opaque callback - the broker calls this with the plaintext value internally.
|
|
74
74
|
* The caller provides the function but never receives the secret value directly.
|
|
75
75
|
*/
|
|
76
76
|
execute: (value: string) => Promise<T>;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/** Result of a broker-mediated server-side credential use
|
|
79
|
+
/** Result of a broker-mediated server-side credential use - contains the callback result, never plaintext. */
|
|
80
80
|
export interface ServerUseResult<T> {
|
|
81
81
|
success: boolean;
|
|
82
82
|
result?: T;
|
|
@@ -89,7 +89,7 @@ export interface ServerUseByIdRequest {
|
|
|
89
89
|
requestingTool: string;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
/** Successful by-id lookup result
|
|
92
|
+
/** Successful by-id lookup result - metadata + injection templates, never plaintext. */
|
|
93
93
|
export interface ServerUseByIdSuccess {
|
|
94
94
|
success: true;
|
|
95
95
|
credentialId: string;
|
|
@@ -68,7 +68,7 @@ export class CredentialBroker {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Tool policy enforcement
|
|
71
|
+
// Tool policy enforcement - deny if tool is not in the credential's allowed list
|
|
72
72
|
if (!isToolAllowed(request.toolName, metadata.allowedTools)) {
|
|
73
73
|
const tools = metadata.allowedTools ?? [];
|
|
74
74
|
return {
|
|
@@ -76,7 +76,7 @@ export class CredentialBroker {
|
|
|
76
76
|
reason:
|
|
77
77
|
`Tool "${request.toolName}" is not allowed to use credential ${request.service}/${request.field}. ` +
|
|
78
78
|
(tools.length === 0
|
|
79
|
-
? "No tools are currently allowed
|
|
79
|
+
? "No tools are currently allowed - update the credential with allowed_tools via credential_store."
|
|
80
80
|
: `Allowed tools: ${tools.join(", ")}.`),
|
|
81
81
|
};
|
|
82
82
|
}
|
|
@@ -125,7 +125,7 @@ export class CredentialBroker {
|
|
|
125
125
|
|
|
126
126
|
token.consumed = true;
|
|
127
127
|
const storageKey = credentialKey(token.service, token.field);
|
|
128
|
-
// Check for transient value first (one-time send)
|
|
128
|
+
// Check for transient value first (one-time send) - consume and return the value
|
|
129
129
|
// directly since transient values are never persisted to secure storage.
|
|
130
130
|
const transient = this.transientValues.get(storageKey);
|
|
131
131
|
if (transient !== undefined) {
|
|
@@ -166,7 +166,7 @@ export class CredentialBroker {
|
|
|
166
166
|
* Fill a browser field using a credential without exposing plaintext to the caller.
|
|
167
167
|
*
|
|
168
168
|
* The broker resolves the credential, reads the secret internally, and passes it
|
|
169
|
-
* to the provided fill callback. The return value contains only metadata
|
|
169
|
+
* to the provided fill callback. The return value contains only metadata - the
|
|
170
170
|
* plaintext never leaves this method's scope.
|
|
171
171
|
*/
|
|
172
172
|
async browserFill(request: BrowserFillRequest): Promise<BrowserFillResult> {
|
|
@@ -178,7 +178,7 @@ export class CredentialBroker {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
// Tool policy enforcement
|
|
181
|
+
// Tool policy enforcement - deny if tool is not in the credential's allowed list
|
|
182
182
|
if (!isToolAllowed(request.toolName, metadata.allowedTools)) {
|
|
183
183
|
const tools = metadata.allowedTools ?? [];
|
|
184
184
|
return {
|
|
@@ -186,12 +186,12 @@ export class CredentialBroker {
|
|
|
186
186
|
reason:
|
|
187
187
|
`Tool "${request.toolName}" is not allowed to use credential ${request.service}/${request.field}. ` +
|
|
188
188
|
(tools.length === 0
|
|
189
|
-
? "No tools are currently allowed
|
|
189
|
+
? "No tools are currently allowed - update the credential with allowed_tools via credential_store."
|
|
190
190
|
: `Allowed tools: ${tools.join(", ")}.`),
|
|
191
191
|
};
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
// Domain policy enforcement
|
|
194
|
+
// Domain policy enforcement - deny if the page domain is not in the credential's allowed list
|
|
195
195
|
const browserDomains = metadata.allowedDomains ?? [];
|
|
196
196
|
if (browserDomains.length > 0) {
|
|
197
197
|
if (!request.domain) {
|
|
@@ -228,7 +228,7 @@ export class CredentialBroker {
|
|
|
228
228
|
try {
|
|
229
229
|
await request.fill(value);
|
|
230
230
|
// Only discard the transient value after a successful fill, and only if
|
|
231
|
-
// the map still holds the same reference
|
|
231
|
+
// the map still holds the same reference - a concurrent injectTransient()
|
|
232
232
|
// call during the async fill could have replaced it with a new value.
|
|
233
233
|
if (
|
|
234
234
|
transient !== undefined &&
|
|
@@ -246,7 +246,7 @@ export class CredentialBroker {
|
|
|
246
246
|
);
|
|
247
247
|
return { success: true };
|
|
248
248
|
} catch (err) {
|
|
249
|
-
// Log the raw error for debugging but never return it
|
|
249
|
+
// Log the raw error for debugging but never return it - the callback
|
|
250
250
|
// error text may embed the credential value, leaking plaintext outside
|
|
251
251
|
// the broker's trust boundary.
|
|
252
252
|
log.error(
|
|
@@ -262,7 +262,7 @@ export class CredentialBroker {
|
|
|
262
262
|
*
|
|
263
263
|
* Like browserFill, the broker reads the secret internally and passes it
|
|
264
264
|
* to the provided callback. The return value contains only the callback's
|
|
265
|
-
* result
|
|
265
|
+
* result - the plaintext never leaves this method's scope.
|
|
266
266
|
*/
|
|
267
267
|
async serverUse<T>(
|
|
268
268
|
request: ServerUseRequest<T>,
|
|
@@ -282,12 +282,12 @@ export class CredentialBroker {
|
|
|
282
282
|
reason:
|
|
283
283
|
`Tool "${request.toolName}" is not allowed to use credential ${request.service}/${request.field}. ` +
|
|
284
284
|
(tools.length === 0
|
|
285
|
-
? "No tools are currently allowed
|
|
285
|
+
? "No tools are currently allowed - update the credential with allowed_tools via credential_store."
|
|
286
286
|
: `Allowed tools: ${tools.join(", ")}.`),
|
|
287
287
|
};
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
// Domain policy enforcement
|
|
290
|
+
// Domain policy enforcement - credentials with domain restrictions are
|
|
291
291
|
// scoped to browser use on those domains and cannot be used server-side.
|
|
292
292
|
const serverDomains = metadata.allowedDomains ?? [];
|
|
293
293
|
if (serverDomains.length > 0) {
|
|
@@ -341,7 +341,7 @@ export class CredentialBroker {
|
|
|
341
341
|
*
|
|
342
342
|
* Returns metadata and injection templates so the proxy knows how to
|
|
343
343
|
* inject the credential into outbound requests. The secret value is
|
|
344
|
-
* never included in the result
|
|
344
|
+
* never included in the result - the proxy reads it separately via
|
|
345
345
|
* the secure key backend at injection time.
|
|
346
346
|
*/
|
|
347
347
|
async serverUseById(
|
|
@@ -365,12 +365,12 @@ export class CredentialBroker {
|
|
|
365
365
|
reason:
|
|
366
366
|
`Tool "${request.requestingTool}" is not allowed to use credential ${metadata.service}/${metadata.field}. ` +
|
|
367
367
|
(tools.length === 0
|
|
368
|
-
? "No tools are currently allowed
|
|
368
|
+
? "No tools are currently allowed - update the credential with allowed_tools via credential_store."
|
|
369
369
|
: `Allowed tools: ${tools.join(", ")}.`),
|
|
370
370
|
};
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
// Domain policy enforcement
|
|
373
|
+
// Domain policy enforcement - credentials with domain restrictions are
|
|
374
374
|
// scoped to browser use on those domains and cannot be used server-side.
|
|
375
375
|
const domains = metadata.allowedDomains ?? [];
|
|
376
376
|
if (domains.length > 0) {
|
|
@@ -22,7 +22,7 @@ import type { CredentialInjectionTemplate } from "./policy-types.js";
|
|
|
22
22
|
/**
|
|
23
23
|
* CredentialMetadata extends the shared StaticCredentialRecord with
|
|
24
24
|
* assistant-specific injection template fields (composeWith, valueTransform).
|
|
25
|
-
* Structurally compatible
|
|
25
|
+
* Structurally compatible - the shared store persists all fields as-is.
|
|
26
26
|
*/
|
|
27
27
|
export interface CredentialMetadata {
|
|
28
28
|
credentialId: string;
|
|
@@ -60,7 +60,7 @@ function getStore(): StaticCredentialMetadataStore {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// ---------------------------------------------------------------------------
|
|
63
|
-
// Public API
|
|
63
|
+
// Public API - unchanged signatures, delegates to shared store
|
|
64
64
|
// ---------------------------------------------------------------------------
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -27,7 +27,7 @@ export interface CredentialSelectionResult {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Tier scores
|
|
30
|
+
* Tier scores - higher-priority criteria use larger values so they
|
|
31
31
|
* dominate over lower-priority ones regardless of accumulation.
|
|
32
32
|
*/
|
|
33
33
|
const SCORE_EXACT_HOST = 100;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* @returns true if the tool is explicitly listed in allowedTools
|
|
14
14
|
*
|
|
15
15
|
* Semantics:
|
|
16
|
-
* 1. Explicit allowlist
|
|
16
|
+
* 1. Explicit allowlist - tool must be listed by exact name
|
|
17
17
|
* 2. No wildcard support in v1
|
|
18
18
|
* 3. Fail-closed on empty or missing list
|
|
19
19
|
*/
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { getConfig } from "../../config/loader.js";
|
|
2
|
+
import {
|
|
3
|
+
setSlackChannelConfig,
|
|
4
|
+
type SlackChannelConfigResult,
|
|
5
|
+
} from "../../daemon/handlers/config-slack-channel.js";
|
|
2
6
|
import { orchestrateOAuthConnect } from "../../oauth/connect-orchestrator.js";
|
|
7
|
+
import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
|
|
3
8
|
import {
|
|
4
9
|
disconnectOAuthProvider,
|
|
5
10
|
getAppByProviderAndClientId,
|
|
@@ -42,6 +47,39 @@ import { toPolicyFromInput, validatePolicyInput } from "./policy-validate.js";
|
|
|
42
47
|
|
|
43
48
|
const log = getLogger("credential-vault");
|
|
44
49
|
|
|
50
|
+
function isSlackChannelCredential(
|
|
51
|
+
service: string,
|
|
52
|
+
field: string,
|
|
53
|
+
): field is "bot_token" | "app_token" {
|
|
54
|
+
return (
|
|
55
|
+
service === "slack_channel" &&
|
|
56
|
+
(field === "bot_token" || field === "app_token")
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function storeSlackChannelCredential(
|
|
61
|
+
field: "bot_token" | "app_token",
|
|
62
|
+
value: string,
|
|
63
|
+
): Promise<SlackChannelConfigResult> {
|
|
64
|
+
return field === "bot_token"
|
|
65
|
+
? setSlackChannelConfig(value, undefined)
|
|
66
|
+
: setSlackChannelConfig(undefined, value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function formatSlackChannelStatus(
|
|
70
|
+
result: SlackChannelConfigResult,
|
|
71
|
+
): string {
|
|
72
|
+
if (result.connected) {
|
|
73
|
+
const teamLabel = result.teamName ?? "Slack";
|
|
74
|
+
const botLabel = result.botUsername ? ` (@${result.botUsername})` : "";
|
|
75
|
+
return ` Slack channel connected to ${teamLabel}${botLabel}.`;
|
|
76
|
+
}
|
|
77
|
+
if (result.warning) {
|
|
78
|
+
return ` ${result.warning}`;
|
|
79
|
+
}
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
|
|
45
83
|
class CredentialStoreTool implements Tool {
|
|
46
84
|
name = "credential_store";
|
|
47
85
|
description =
|
|
@@ -67,7 +105,7 @@ class CredentialStoreTool implements Tool {
|
|
|
67
105
|
"describe",
|
|
68
106
|
],
|
|
69
107
|
description:
|
|
70
|
-
'The operation to perform. Use "prompt" to ask the user for a secret via secure UI
|
|
108
|
+
'The operation to perform. Use "prompt" to ask the user for a secret via secure UI - the value never enters the conversation. Use "oauth2_connect" to connect an OAuth2 service via browser authorization. Use "describe" to get setup metadata for a well-known OAuth service (dashboard URL, scopes, redirect URI, etc.). For well-known services (gmail, slack), only the service name is required - endpoints, scopes, and stored client credentials are resolved automatically.',
|
|
71
109
|
},
|
|
72
110
|
service: {
|
|
73
111
|
type: "string",
|
|
@@ -322,13 +360,27 @@ class CredentialStoreTool implements Tool {
|
|
|
322
360
|
};
|
|
323
361
|
}
|
|
324
362
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
363
|
+
let slackChannelResult: SlackChannelConfigResult | undefined;
|
|
364
|
+
if (isSlackChannelCredential(service, field)) {
|
|
365
|
+
slackChannelResult = await storeSlackChannelCredential(field, value);
|
|
366
|
+
if (!slackChannelResult.success) {
|
|
367
|
+
return {
|
|
368
|
+
content: `Error: ${
|
|
369
|
+
slackChannelResult.error ??
|
|
370
|
+
"failed to configure Slack channel"
|
|
371
|
+
}`,
|
|
372
|
+
isError: true,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
const key = credentialKey(service, field);
|
|
377
|
+
const ok = await setSecureKeyAsync(key, value);
|
|
378
|
+
if (!ok) {
|
|
379
|
+
return {
|
|
380
|
+
content: "Error: failed to store credential",
|
|
381
|
+
isError: true,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
332
384
|
}
|
|
333
385
|
try {
|
|
334
386
|
upsertCredentialMetadata(service, field, {
|
|
@@ -344,12 +396,19 @@ class CredentialStoreTool implements Tool {
|
|
|
344
396
|
"metadata write failed after storing credential",
|
|
345
397
|
);
|
|
346
398
|
}
|
|
399
|
+
if (!isSlackChannelCredential(service, field)) {
|
|
400
|
+
await syncManualTokenConnection(service);
|
|
401
|
+
}
|
|
347
402
|
const metadata = getCredentialMetadata(service, field);
|
|
348
403
|
const credIdSuffix = metadata
|
|
349
404
|
? ` (credential_id: ${metadata.credentialId})`
|
|
350
405
|
: "";
|
|
351
406
|
return {
|
|
352
|
-
content: `Stored credential for ${service}/${field}.${credIdSuffix}
|
|
407
|
+
content: `Stored credential for ${service}/${field}.${credIdSuffix}${
|
|
408
|
+
slackChannelResult
|
|
409
|
+
? formatSlackChannelStatus(slackChannelResult)
|
|
410
|
+
: ""
|
|
411
|
+
}`,
|
|
353
412
|
isError: false,
|
|
354
413
|
};
|
|
355
414
|
}
|
|
@@ -477,7 +536,7 @@ class CredentialStoreTool implements Tool {
|
|
|
477
536
|
if (oauthResult === "error") {
|
|
478
537
|
log.warn(
|
|
479
538
|
{ service },
|
|
480
|
-
"OAuth disconnect failed after removing credential
|
|
539
|
+
"OAuth disconnect failed after removing credential - secure key deletion error",
|
|
481
540
|
);
|
|
482
541
|
}
|
|
483
542
|
} catch (err) {
|
|
@@ -653,6 +712,13 @@ class CredentialStoreTool implements Tool {
|
|
|
653
712
|
|
|
654
713
|
// Handle one-time send delivery: inject into context without persisting
|
|
655
714
|
if (result.delivery === "transient_send") {
|
|
715
|
+
if (isSlackChannelCredential(service, field)) {
|
|
716
|
+
return {
|
|
717
|
+
content:
|
|
718
|
+
"Error: Slack channel credentials must be saved to secure storage. Re-run the secure prompt and choose to store the token.",
|
|
719
|
+
isError: true,
|
|
720
|
+
};
|
|
721
|
+
}
|
|
656
722
|
const config = getConfig();
|
|
657
723
|
if (!config.secretDetection.allowOneTimeSend) {
|
|
658
724
|
log.warn(
|
|
@@ -666,7 +732,7 @@ class CredentialStoreTool implements Tool {
|
|
|
666
732
|
};
|
|
667
733
|
}
|
|
668
734
|
// Ensure metadata exists so broker policy checks work, but don't
|
|
669
|
-
// overwrite an existing record
|
|
735
|
+
// overwrite an existing record - a stored credential's policy should
|
|
670
736
|
// not be silently replaced by the transient prompt's policy.
|
|
671
737
|
// Metadata must be written before injecting the transient value so
|
|
672
738
|
// we never leave a dangling value that fails policy checks.
|
|
@@ -703,14 +769,31 @@ class CredentialStoreTool implements Tool {
|
|
|
703
769
|
};
|
|
704
770
|
}
|
|
705
771
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
772
|
+
let slackChannelResult: SlackChannelConfigResult | undefined;
|
|
773
|
+
if (isSlackChannelCredential(service, field)) {
|
|
774
|
+
slackChannelResult = await storeSlackChannelCredential(
|
|
775
|
+
field,
|
|
776
|
+
result.value,
|
|
777
|
+
);
|
|
778
|
+
if (!slackChannelResult.success) {
|
|
779
|
+
return {
|
|
780
|
+
content: `Error: ${
|
|
781
|
+
slackChannelResult.error ??
|
|
782
|
+
"failed to configure Slack channel"
|
|
783
|
+
}`,
|
|
784
|
+
isError: true,
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
// Default: persist to keychain
|
|
789
|
+
const key = credentialKey(service, field);
|
|
790
|
+
const ok = await setSecureKeyAsync(key, result.value);
|
|
791
|
+
if (!ok) {
|
|
792
|
+
return {
|
|
793
|
+
content: "Error: failed to store credential",
|
|
794
|
+
isError: true,
|
|
795
|
+
};
|
|
796
|
+
}
|
|
714
797
|
}
|
|
715
798
|
try {
|
|
716
799
|
upsertCredentialMetadata(service, field, {
|
|
@@ -725,12 +808,19 @@ class CredentialStoreTool implements Tool {
|
|
|
725
808
|
"metadata write failed after storing credential",
|
|
726
809
|
);
|
|
727
810
|
}
|
|
811
|
+
if (!isSlackChannelCredential(service, field)) {
|
|
812
|
+
await syncManualTokenConnection(service);
|
|
813
|
+
}
|
|
728
814
|
const promptMeta = getCredentialMetadata(service, field);
|
|
729
815
|
const promptCredIdSuffix = promptMeta
|
|
730
816
|
? ` (credential_id: ${promptMeta.credentialId})`
|
|
731
817
|
: "";
|
|
732
818
|
return {
|
|
733
|
-
content: `Credential stored for ${service}/${field}.${promptCredIdSuffix}
|
|
819
|
+
content: `Credential stored for ${service}/${field}.${promptCredIdSuffix}${
|
|
820
|
+
slackChannelResult
|
|
821
|
+
? formatSlackChannelStatus(slackChannelResult)
|
|
822
|
+
: ""
|
|
823
|
+
}`,
|
|
734
824
|
isError: false,
|
|
735
825
|
};
|
|
736
826
|
}
|
|
@@ -754,7 +844,7 @@ class CredentialStoreTool implements Tool {
|
|
|
754
844
|
// Resolve client_id and client_secret.
|
|
755
845
|
// Priority:
|
|
756
846
|
// 1. Explicit input from the caller
|
|
757
|
-
// 2. oauth-store DB
|
|
847
|
+
// 2. oauth-store DB - when clientId is already known, look up the
|
|
758
848
|
// matching app so the secret comes from the same app. Only fall
|
|
759
849
|
// back to the most-recent-app heuristic when clientId is unknown.
|
|
760
850
|
let clientId = input.client_id as string | undefined;
|
|
@@ -791,7 +881,7 @@ class CredentialStoreTool implements Tool {
|
|
|
791
881
|
isError: true,
|
|
792
882
|
};
|
|
793
883
|
|
|
794
|
-
// Fail early when client_secret is required but missing
|
|
884
|
+
// Fail early when client_secret is required but missing - guide the
|
|
795
885
|
// agent to collect it from the user rather than letting it improvise
|
|
796
886
|
// browser-automation workarounds that inevitably fail.
|
|
797
887
|
const requiresSecret =
|
|
@@ -808,7 +898,7 @@ class CredentialStoreTool implements Tool {
|
|
|
808
898
|
};
|
|
809
899
|
}
|
|
810
900
|
|
|
811
|
-
// Delegate to the shared orchestrator
|
|
901
|
+
// Delegate to the shared orchestrator - it resolves authUrl, tokenUrl,
|
|
812
902
|
// extraParams, userinfoUrl, and tokenEndpointAuthMethod from the DB.
|
|
813
903
|
const result = await orchestrateOAuthConnect({
|
|
814
904
|
service: rawService,
|
|
@@ -909,7 +999,7 @@ class CredentialStoreTool implements Tool {
|
|
|
909
999
|
redirectUri = `http://localhost:${loopbackPort}/oauth/callback`;
|
|
910
1000
|
} else if (transport === "loopback") {
|
|
911
1001
|
redirectUri =
|
|
912
|
-
"(automatic
|
|
1002
|
+
"(automatic - no redirect URI needed, uses random localhost port)";
|
|
913
1003
|
} else {
|
|
914
1004
|
// Try to compute the actual URL from config/env
|
|
915
1005
|
try {
|
|
@@ -920,7 +1010,7 @@ class CredentialStoreTool implements Tool {
|
|
|
920
1010
|
redirectUri = `${baseUrl}/webhooks/oauth/callback`;
|
|
921
1011
|
} catch {
|
|
922
1012
|
redirectUri =
|
|
923
|
-
"(requires ingress.publicBaseUrl
|
|
1013
|
+
"(requires ingress.publicBaseUrl - not currently configured)";
|
|
924
1014
|
}
|
|
925
1015
|
}
|
|
926
1016
|
|
|
@@ -11,12 +11,12 @@ export function resolveExecutionTarget(
|
|
|
11
11
|
manifestOverride?: ManifestOverride,
|
|
12
12
|
): ExecutionTarget {
|
|
13
13
|
const tool = getTool(toolName);
|
|
14
|
-
// Manifest-declared execution target is authoritative
|
|
14
|
+
// Manifest-declared execution target is authoritative - check it first so
|
|
15
15
|
// skill tools with host_/computer_use_ prefixes aren't mis-classified.
|
|
16
16
|
if (tool?.executionTarget) {
|
|
17
17
|
return tool.executionTarget;
|
|
18
18
|
}
|
|
19
|
-
// Check the tool's executionMode metadata
|
|
19
|
+
// Check the tool's executionMode metadata - proxy tools run on the connected
|
|
20
20
|
// client (host), not inside the sandbox.
|
|
21
21
|
if (tool?.executionMode === "proxy") {
|
|
22
22
|
return "host";
|
package/src/tools/executor.ts
CHANGED
|
@@ -88,7 +88,7 @@ export class ToolExecutor {
|
|
|
88
88
|
// whether a scoped grant was consumed. Previously this was nested
|
|
89
89
|
// inside the `!grantConsumed` block, meaning untrusted host_bash
|
|
90
90
|
// calls that arrived with a consumed guardian-approval grant would
|
|
91
|
-
// skip this assignment entirely
|
|
91
|
+
// skip this assignment entirely - defeating the lockdown.
|
|
92
92
|
if (
|
|
93
93
|
name === "host_bash" &&
|
|
94
94
|
isCesShellLockdownEnabled(getConfig()) &&
|
|
@@ -98,7 +98,7 @@ export class ToolExecutor {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// Secure command tool installation always requires fresh per-invocation
|
|
101
|
-
// approval
|
|
101
|
+
// approval - no persistent grants. This is unconditional (not gated on
|
|
102
102
|
// CES lockdown or trust class) because installing secure tools is
|
|
103
103
|
// inherently high-impact.
|
|
104
104
|
if (name === "manage_secure_command_tool") {
|
|
@@ -106,11 +106,11 @@ export class ToolExecutor {
|
|
|
106
106
|
context.requireFreshApproval = true;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// A consumed scoped grant is a complete authorization
|
|
109
|
+
// A consumed scoped grant is a complete authorization - skip the
|
|
110
110
|
// interactive permission/prompt flow so non-interactive sessions
|
|
111
111
|
// don't auto-deny prompt-gated tools and burn the one-time grant.
|
|
112
112
|
// Exception: requireFreshApproval tools always go through the
|
|
113
|
-
// permission check even when a grant was consumed
|
|
113
|
+
// permission check even when a grant was consumed - the grant does
|
|
114
114
|
// not substitute for an interactive human review.
|
|
115
115
|
if (!gateResult.grantConsumed || context.requireFreshApproval) {
|
|
116
116
|
// Check permissions via the extracted PermissionChecker
|
|
@@ -164,7 +164,7 @@ export class ToolExecutor {
|
|
|
164
164
|
return { content: msg, isError: true };
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// Execute the tool
|
|
167
|
+
// Execute the tool - proxy tools delegate to an external resolver
|
|
168
168
|
let execResult: ToolExecutionResult;
|
|
169
169
|
let toolTimeoutMs: number;
|
|
170
170
|
if (name === "bash" || name === "host_bash") {
|
|
@@ -276,7 +276,7 @@ export class ToolExecutor {
|
|
|
276
276
|
grantId: bridgeResult.grantId,
|
|
277
277
|
conversationId: context.conversationId,
|
|
278
278
|
},
|
|
279
|
-
"CES approval granted
|
|
279
|
+
"CES approval granted - retrying tool invocation with grantId",
|
|
280
280
|
);
|
|
281
281
|
|
|
282
282
|
if (tool.executionMode === "proxy") {
|
|
@@ -579,7 +579,7 @@ function computePreviewDiff(
|
|
|
579
579
|
};
|
|
580
580
|
}
|
|
581
581
|
} catch {
|
|
582
|
-
// Preview is best-effort
|
|
582
|
+
// Preview is best-effort - don't block the prompt on errors
|
|
583
583
|
}
|
|
584
584
|
return undefined;
|
|
585
585
|
}
|
|
@@ -9,9 +9,9 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
9
9
|
class FileEditTool implements Tool {
|
|
10
10
|
name = "file_edit";
|
|
11
11
|
description =
|
|
12
|
-
"Replace an exact string in a file with a new string. Use this for surgical edits instead of rewriting entire files.";
|
|
12
|
+
"Replace an exact string in a file with a new string. Use this for surgical edits instead of rewriting entire files. To delete a file, use bash with rm instead.";
|
|
13
13
|
category = "filesystem";
|
|
14
|
-
defaultRiskLevel = RiskLevel.
|
|
14
|
+
defaultRiskLevel = RiskLevel.Low;
|
|
15
15
|
|
|
16
16
|
getDefinition(): ToolDefinition {
|
|
17
17
|
return {
|
|
@@ -14,7 +14,7 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
14
14
|
class FileReadTool implements Tool {
|
|
15
15
|
name = "file_read";
|
|
16
16
|
description =
|
|
17
|
-
"Read the contents of a file. For image files (JPEG, PNG, GIF, WebP), returns the image for visual analysis.";
|
|
17
|
+
"Read the contents of a file. For image files (JPEG, PNG, GIF, WebP), returns the image for visual analysis. Always use this tool (not host_file_read) for workspace files under .vellum.";
|
|
18
18
|
category = "filesystem";
|
|
19
19
|
defaultRiskLevel = RiskLevel.Low;
|
|
20
20
|
|
|
@@ -61,7 +61,10 @@ class FileReadTool implements Tool {
|
|
|
61
61
|
if (IMAGE_EXTENSIONS.has(ext)) {
|
|
62
62
|
const pathCheck = sandboxPolicy(rawPath, context.workingDir);
|
|
63
63
|
if (!pathCheck.ok) {
|
|
64
|
-
return {
|
|
64
|
+
return {
|
|
65
|
+
content: `Error: ${pathCheck.error}. To read files outside the workspace, use the host_file_read tool instead.`,
|
|
66
|
+
isError: true,
|
|
67
|
+
};
|
|
65
68
|
}
|
|
66
69
|
return readImageFile(pathCheck.resolved);
|
|
67
70
|
}
|
|
@@ -89,8 +92,16 @@ class FileReadTool implements Tool {
|
|
|
89
92
|
content: `Error reading file "${rawPath}": ${error.message}`,
|
|
90
93
|
isError: true,
|
|
91
94
|
};
|
|
92
|
-
default:
|
|
93
|
-
|
|
95
|
+
default: {
|
|
96
|
+
const hint =
|
|
97
|
+
error.code === "PATH_OUT_OF_BOUNDS"
|
|
98
|
+
? ". To read files outside the workspace, use the host_file_read tool instead."
|
|
99
|
+
: "";
|
|
100
|
+
return {
|
|
101
|
+
content: `Error: ${error.message}${hint}`,
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
|
|
@@ -10,7 +10,7 @@ class FileWriteTool implements Tool {
|
|
|
10
10
|
name = "file_write";
|
|
11
11
|
description = "Write content to a file, creating it if it does not exist";
|
|
12
12
|
category = "filesystem";
|
|
13
|
-
defaultRiskLevel = RiskLevel.
|
|
13
|
+
defaultRiskLevel = RiskLevel.Low;
|
|
14
14
|
|
|
15
15
|
getDefinition(): ToolDefinition {
|
|
16
16
|
return {
|
|
@@ -7,7 +7,8 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
7
7
|
|
|
8
8
|
class HostFileEditTool implements Tool {
|
|
9
9
|
name = "host_file_edit";
|
|
10
|
-
description =
|
|
10
|
+
description =
|
|
11
|
+
"Replace exact text in a host filesystem file with new text. Not for workspace files under .vellum (use file_edit instead).";
|
|
11
12
|
category = "host-filesystem";
|
|
12
13
|
defaultRiskLevel = RiskLevel.Medium;
|
|
13
14
|
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
|
|
1
3
|
import { RiskLevel } from "../../permissions/types.js";
|
|
2
4
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
3
5
|
import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
|
|
6
|
+
import {
|
|
7
|
+
IMAGE_EXTENSIONS,
|
|
8
|
+
readImageFile,
|
|
9
|
+
} from "../shared/filesystem/image-read.js";
|
|
4
10
|
import { hostPolicy } from "../shared/filesystem/path-policy.js";
|
|
5
11
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
6
12
|
|
|
7
13
|
class HostFileReadTool implements Tool {
|
|
8
14
|
name = "host_file_read";
|
|
9
|
-
description =
|
|
15
|
+
description =
|
|
16
|
+
"Read the contents of a file on the host filesystem, including images (JPEG, PNG, GIF, WebP). Not for workspace files under .vellum (use file_read instead).";
|
|
10
17
|
category = "host-filesystem";
|
|
11
18
|
defaultRiskLevel = RiskLevel.Medium;
|
|
12
19
|
|
|
@@ -62,6 +69,16 @@ class HostFileReadTool implements Tool {
|
|
|
62
69
|
);
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
// For image files, delegate to the shared image reader.
|
|
73
|
+
const ext = extname(rawPath).toLowerCase();
|
|
74
|
+
if (IMAGE_EXTENSIONS.has(ext)) {
|
|
75
|
+
const pathCheck = hostPolicy(rawPath);
|
|
76
|
+
if (!pathCheck.ok) {
|
|
77
|
+
return { content: `Error: ${pathCheck.error}`, isError: true };
|
|
78
|
+
}
|
|
79
|
+
return readImageFile(pathCheck.resolved);
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
const ops = new FileSystemOps(hostPolicy);
|
|
66
83
|
|
|
67
84
|
const result = ops.readFileSafe({
|
|
@@ -8,7 +8,7 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
8
8
|
class HostFileWriteTool implements Tool {
|
|
9
9
|
name = "host_file_write";
|
|
10
10
|
description =
|
|
11
|
-
"Write content to a file on the host filesystem, creating it if it does not exist";
|
|
11
|
+
"Write content to a file on the host filesystem, creating it if it does not exist. Not for workspace files under .vellum (use file_write instead).";
|
|
12
12
|
category = "host-filesystem";
|
|
13
13
|
defaultRiskLevel = RiskLevel.Medium;
|
|
14
14
|
|