@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
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
-
import { CLI_HELP_REFERENCE } from "../cli/reference.js";
|
|
5
4
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
5
|
import { getBaseDataDir, getIsContainerized } from "../config/env-registry.js";
|
|
7
6
|
import { getConfig } from "../config/loader.js";
|
|
8
7
|
import { skillFlagKey } from "../config/skill-state.js";
|
|
9
8
|
import { loadSkillCatalog, type SkillSummary } from "../config/skills.js";
|
|
10
|
-
import { isPlatformManaged } from "../inbound/platform-callback-registration.js";
|
|
11
9
|
import { listConnections } from "../oauth/oauth-store.js";
|
|
12
10
|
import { resolveBundledDir } from "../util/bundled-asset.js";
|
|
13
11
|
import { getLogger } from "../util/logger.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "../util/platform.js";
|
|
19
|
-
import { resolveUserPronouns, resolveUserReference } from "./user-reference.js";
|
|
12
|
+
import { getWorkspacePromptPath, isMacOS } from "../util/platform.js";
|
|
13
|
+
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "./cache-boundary.js";
|
|
14
|
+
|
|
15
|
+
export { SYSTEM_PROMPT_CACHE_BOUNDARY };
|
|
20
16
|
|
|
21
17
|
const log = getLogger("system-prompt");
|
|
22
18
|
|
|
23
19
|
const PROMPT_FILES = ["SOUL.md", "IDENTITY.md", "USER.md"] as const;
|
|
24
20
|
|
|
25
|
-
let cachedCliHelp: string | undefined;
|
|
26
|
-
|
|
27
|
-
/** @internal Reset the CLI help cache — exposed for testing only. */
|
|
28
|
-
export function _resetCliHelpCache(): void {
|
|
29
|
-
cachedCliHelp = undefined;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
21
|
/**
|
|
33
22
|
* Copy template prompt files into the data directory if they don't already exist.
|
|
34
23
|
* Called once during daemon startup so users always have discoverable files to edit.
|
|
@@ -91,15 +80,6 @@ export function ensurePromptFiles(): void {
|
|
|
91
80
|
}
|
|
92
81
|
}
|
|
93
82
|
|
|
94
|
-
/**
|
|
95
|
-
* Returns true when BOOTSTRAP.md has been deleted from the workspace,
|
|
96
|
-
* signalling the first-run ritual is complete.
|
|
97
|
-
*/
|
|
98
|
-
export function isOnboardingComplete(): boolean {
|
|
99
|
-
const bootstrapPath = getWorkspacePromptPath("BOOTSTRAP.md");
|
|
100
|
-
return !existsSync(bootstrapPath);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
83
|
/**
|
|
104
84
|
* Build the system prompt from ~/.vellum prompt files,
|
|
105
85
|
* then append a generated skills catalog (if any skills are available).
|
|
@@ -123,9 +103,6 @@ export interface BuildSystemPromptOptions {
|
|
|
123
103
|
* cache blocks so that static instructions stay cached even when workspace
|
|
124
104
|
* files change between turns.
|
|
125
105
|
*/
|
|
126
|
-
export const SYSTEM_PROMPT_CACHE_BOUNDARY =
|
|
127
|
-
"\n<!-- SYSTEM_PROMPT_CACHE_BOUNDARY -->\n";
|
|
128
|
-
|
|
129
106
|
export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
130
107
|
const hasNoClient = options?.hasNoClient ?? false;
|
|
131
108
|
|
|
@@ -134,27 +111,19 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
134
111
|
// the first cache block so they remain cached even when workspace files
|
|
135
112
|
// (IDENTITY.md, SOUL.md, USER.md, etc.) are edited between turns.
|
|
136
113
|
const staticParts: string[] = [];
|
|
137
|
-
staticParts.push(
|
|
138
|
-
"IMPORTANT: Never use em dashes (—) in your messages. Use commas, periods, or just start a new sentence instead.",
|
|
139
|
-
);
|
|
114
|
+
staticParts.push(buildParallelToolCallsSection());
|
|
140
115
|
if (getIsContainerized()) staticParts.push(buildContainerizedSection());
|
|
141
116
|
staticParts.push(buildCliReferenceSection());
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (!hasNoClient) staticParts.push(buildToolPermissionSection());
|
|
145
|
-
staticParts.push(buildTaskScheduleReminderRoutingSection());
|
|
117
|
+
// Tool Permissions section removed — guidance lives in tool descriptions.
|
|
118
|
+
// Tool Routing section removed — guidance lives in tool descriptions.
|
|
146
119
|
staticParts.push(buildAttachmentSection());
|
|
147
120
|
staticParts.push(buildInChatConfigurationSection());
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
if (!hasNoClient) staticParts.push(buildSystemPermissionSection());
|
|
152
|
-
staticParts.push(buildSwarmGuidanceSection());
|
|
121
|
+
// System Permissions section removed — guidance lives in request_system_permission tool description.
|
|
122
|
+
// Parallel Task Orchestration section removed — orchestration skill description + hints cover this.
|
|
153
123
|
staticParts.push(buildAccessPreferenceSection(hasNoClient));
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
staticParts.push(buildLearningMemorySection());
|
|
124
|
+
// Memory Persistence, Memory Recall, Workspace Reflection, Learning from Mistakes
|
|
125
|
+
// sections removed — guidance lives in memory_manage/memory_recall tool descriptions
|
|
126
|
+
// and the Proactive Workspace Editing subsection in Configuration.
|
|
158
127
|
|
|
159
128
|
// ── Dynamic sections (may change between turns) ──
|
|
160
129
|
// Workspace files, config, external comms identity, connected services,
|
|
@@ -174,10 +143,24 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
174
143
|
const bootstrap = readPromptFile(bootstrapPath);
|
|
175
144
|
const updates = readPromptFile(updatesPath);
|
|
176
145
|
|
|
177
|
-
|
|
146
|
+
const includeBootstrap = !!bootstrap && !options?.excludeBootstrap;
|
|
147
|
+
|
|
148
|
+
// Template prompt files contain placeholder fields and meta-instructions
|
|
149
|
+
// meant for the assistant to fill in during onboarding. When included
|
|
150
|
+
// verbatim in the system prompt, the model can leak internal details and
|
|
151
|
+
// narrate its own setup process instead of following the BOOTSTRAP.md
|
|
152
|
+
// ritual. Detect unmodified templates by comparing against the bundled
|
|
153
|
+
// source and skip them — SOUL.md provides sufficient personality defaults
|
|
154
|
+
// until onboarding completes.
|
|
155
|
+
const identityIsTemplate = isTemplateContent(identity, "IDENTITY.md");
|
|
156
|
+
const userIsTemplate = isTemplateContent(user, "USER.md");
|
|
157
|
+
|
|
158
|
+
if (identity && !identityIsTemplate) {
|
|
159
|
+
dynamicParts.push(identity);
|
|
160
|
+
}
|
|
178
161
|
if (soul) dynamicParts.push(soul);
|
|
179
|
-
if (user) dynamicParts.push(user);
|
|
180
|
-
if (
|
|
162
|
+
if (user && !userIsTemplate) dynamicParts.push(user);
|
|
163
|
+
if (includeBootstrap) {
|
|
181
164
|
dynamicParts.push(
|
|
182
165
|
"# First-Run Ritual\n\n" +
|
|
183
166
|
"BOOTSTRAP.md is present — this is your first conversation. Follow its instructions.\n\n" +
|
|
@@ -201,9 +184,12 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
201
184
|
].join("\n"),
|
|
202
185
|
);
|
|
203
186
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
187
|
+
// Configuration section removed — workspace files are self-describing,
|
|
188
|
+
// tool routing lives in tool descriptions.
|
|
189
|
+
// External Communications Identity removed — guidance lives in messaging
|
|
190
|
+
// and phone-calls skill SKILL.md files.
|
|
191
|
+
const integrationSection = buildIntegrationSection();
|
|
192
|
+
if (integrationSection) dynamicParts.push(integrationSection);
|
|
207
193
|
|
|
208
194
|
const dynamicWithSkills = appendSkillsCatalog(dynamicParts.join("\n\n"));
|
|
209
195
|
|
|
@@ -212,63 +198,15 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
212
198
|
);
|
|
213
199
|
}
|
|
214
200
|
|
|
215
|
-
function buildTaskScheduleReminderRoutingSection(): string {
|
|
216
|
-
return [
|
|
217
|
-
"## Tool Routing: Tasks vs Schedules vs Notifications",
|
|
218
|
-
"",
|
|
219
|
-
'Three tools, each for a different purpose. Load the "Time-Based Actions" skill for the full decision framework.',
|
|
220
|
-
"",
|
|
221
|
-
"| Tool | Purpose |",
|
|
222
|
-
"|------|---------|",
|
|
223
|
-
'| `task_list_add` | Track work — no time trigger ("add to my tasks", "remind me to X" without a time) |',
|
|
224
|
-
'| `schedule_create` | Any time-based automation — recurring cron/RRULE ("every day at 9am") OR one-shot future alert with `fire_at` ("remind me at 3pm") |',
|
|
225
|
-
"| `send_notification` | **Immediate-only** — fires instantly, NO delay capability |",
|
|
226
|
-
"",
|
|
227
|
-
"### Critical: `send_notification` is immediate-only",
|
|
228
|
-
"NEVER use `send_notification` for future-time requests — it fires NOW. Use `schedule_create` with `fire_at` for any delayed alert.",
|
|
229
|
-
"",
|
|
230
|
-
"### Quick routing rules",
|
|
231
|
-
"- Future time, one-shot → `schedule_create` with `fire_at`",
|
|
232
|
-
"- Recurring pattern → `schedule_create`",
|
|
233
|
-
"- No time, track as work → `task_list_add`",
|
|
234
|
-
"- Instant alert → `send_notification`",
|
|
235
|
-
"- Modify existing task → `task_list_update` (NOT `task_list_add`)",
|
|
236
|
-
"- Remove task → `task_list_remove` (NOT `task_list_update`)",
|
|
237
|
-
"",
|
|
238
|
-
"### Entity type routing: work items vs task templates",
|
|
239
|
-
"",
|
|
240
|
-
"Two entity types with separate ID spaces — do NOT mix:",
|
|
241
|
-
"- **Work items** (task queue) — task_list_add, task_list_show, task_list_update, task_list_remove",
|
|
242
|
-
"- **Task templates** (reusable definitions) — task_save, task_list, task_run, task_delete",
|
|
243
|
-
"",
|
|
244
|
-
'If an error says "entity mismatch", read the corrective action and selector fields it provides to pick the right tool.',
|
|
245
|
-
"",
|
|
246
|
-
].join("\n");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
201
|
function buildAttachmentSection(): string {
|
|
250
202
|
return [
|
|
251
203
|
"## Sending Files to the User",
|
|
252
204
|
"",
|
|
253
|
-
|
|
205
|
+
'To deliver files to the user, include `<vellum-attachment source="sandbox" path="scratch/output.png" />` in your response text. This tag is the ONLY way files reach the user - omitting it means the user won\'t see the file.',
|
|
254
206
|
"",
|
|
255
|
-
"
|
|
256
|
-
'<vellum-attachment source="sandbox" path="scratch/output.png" />',
|
|
257
|
-
"```",
|
|
207
|
+
'Use `source="host"` with an absolute path for host filesystem files. Optional attributes: `filename` (display name override), `mime_type` (override auto-detection).',
|
|
258
208
|
"",
|
|
259
|
-
"
|
|
260
|
-
"",
|
|
261
|
-
"- `source`: `sandbox` (default, files inside the sandbox working directory) or `host` (absolute paths on the host filesystem — requires user approval).",
|
|
262
|
-
"- `path`: Required. Relative path for sandbox, absolute path for host.",
|
|
263
|
-
"- `filename`: Optional override for the delivered filename (defaults to the basename of the path).",
|
|
264
|
-
"- `mime_type`: Optional MIME type override (inferred from the file extension if omitted).",
|
|
265
|
-
"",
|
|
266
|
-
'Example: `<vellum-attachment source="sandbox" path="scratch/chart.png" />`',
|
|
267
|
-
"",
|
|
268
|
-
"Limits: 50 MB per attachment. Tool outputs that produce image or file content blocks are also automatically converted into attachments.",
|
|
269
|
-
"",
|
|
270
|
-
"### Inline Images and GIFs",
|
|
271
|
-
"Embed images/GIFs inline using markdown: ``. Do NOT wrap in code fences.",
|
|
209
|
+
"Embed images/GIFs inline using markdown: ``.",
|
|
272
210
|
].join("\n");
|
|
273
211
|
}
|
|
274
212
|
|
|
@@ -276,276 +214,27 @@ function buildInChatConfigurationSection(): string {
|
|
|
276
214
|
return [
|
|
277
215
|
"## In-Chat Configuration",
|
|
278
216
|
"",
|
|
279
|
-
"When the user needs to configure a value
|
|
280
|
-
"",
|
|
281
|
-
"**How to collect credentials and secrets:**",
|
|
282
|
-
...(isPlatformManaged()
|
|
283
|
-
? [
|
|
284
|
-
"- Secrets and API keys are managed through the platform's credential system. Users connect credentials via OAuth or platform-managed secrets — the `credential_store` prompt flow for API keys is not available in managed deployments.",
|
|
285
|
-
"- For OAuth flows, guide the user to connect through the platform. After connecting, run `assistant oauth connections list` to find the connection ID, and use the `platform_oauth:<connectionId>` handle with CES tools (`make_authenticated_request`, `run_authenticated_command`) for authenticated work.",
|
|
286
|
-
"- For non-secret config values (e.g. a public URL, a webhook URL), ask the user directly in the conversation and use the appropriate config tool to persist the value.",
|
|
287
|
-
]
|
|
288
|
-
: [
|
|
289
|
-
'- Use `credential_store` with `action: "prompt"` to present a secure input field. The value never appears in the conversation. Once stored, run `assistant credentials list` to find the service:field identifiers, construct the CES handle as `local_static:<service>/<field>`, and use CES tools (`make_authenticated_request`, `run_authenticated_command`) for authenticated work.',
|
|
290
|
-
'- For OAuth flows, use `credential_store` with `action: "oauth2_connect"` to handle the authorization in-browser. Some services (e.g. Twitter/X) define their own auth flow via dedicated skill instructions — check the service\'s skill documentation for provider-specific setup steps. After connecting, run `assistant oauth connections list` to find the provider key, construct the CES handle, and use CES tools.',
|
|
291
|
-
"- For non-secret config values (e.g. a public URL, a webhook URL), ask the user directly in the conversation and use the appropriate config tool to persist the value.",
|
|
292
|
-
]),
|
|
293
|
-
"",
|
|
294
|
-
'**After saving a value**, confirm success with a message like: "Great, saved! You can always update this from the Settings page."',
|
|
295
|
-
"",
|
|
296
|
-
"**Never tell the user to go to Settings to enter a value.** The Settings page is for reviewing and updating existing configuration, not for initial setup. Always prefer the in-chat flow for first-time configuration.",
|
|
297
|
-
"",
|
|
298
|
-
"### Avatar Customisation",
|
|
299
|
-
"",
|
|
300
|
-
"When the user asks to change, update, or customise your avatar, load the **vellum-avatar** skill using `skill_load`. The skill covers building a native character from traits, uploading an image, or generating one with AI.",
|
|
301
|
-
"",
|
|
302
|
-
"**After any avatar change**, always update the `## Avatar` section in `IDENTITY.md` with a brief description of the current avatar appearance. This ensures you remember what you look like across sessions. Example:",
|
|
303
|
-
"```",
|
|
304
|
-
"## Avatar",
|
|
305
|
-
"A friendly purple cat with green eyes wearing a tiny hat",
|
|
306
|
-
"```",
|
|
307
|
-
].join("\n");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export function buildStarterTaskPlaybookSection(): string {
|
|
311
|
-
return [
|
|
312
|
-
"## Starter Task Playbooks",
|
|
313
|
-
"",
|
|
314
|
-
"When the user clicks a starter task card in the dashboard, you receive a deterministic kickoff message in the format `[STARTER_TASK:<task_id>]`. Follow the playbook for that task exactly.",
|
|
315
|
-
"",
|
|
316
|
-
"### Kickoff intent contract",
|
|
317
|
-
'- `[STARTER_TASK:make_it_yours]` — "Make it yours" color personalisation flow',
|
|
318
|
-
'- `[STARTER_TASK:research_topic]` — "Research something for me" flow',
|
|
319
|
-
'- `[STARTER_TASK:research_to_ui]` — "Turn it into a webpage or interactive UI" flow',
|
|
320
|
-
"",
|
|
321
|
-
"### Playbook: make_it_yours",
|
|
322
|
-
"Goal: Help the user choose an accent color preference for apps and interfaces.",
|
|
323
|
-
"",
|
|
324
|
-
"1. If the user's locale is missing or has `confidence: low` in USER.md, briefly confirm their location/language before proceeding.",
|
|
325
|
-
"2. Present a concise set of accent color options (e.g. 5-7 curated colors with names and hex codes). Keep it short and scannable.",
|
|
326
|
-
'3. Let the user pick one. Accept color names, hex values, or descriptions (e.g. "something warm").',
|
|
327
|
-
'4. Confirm the selection: "I\'ll set your accent color to **{label}** ({hex}). Sound good?"',
|
|
328
|
-
"5. On confirmation:",
|
|
329
|
-
' - Use `app_file_edit` to update the `## Color Preference` section in USER.md with `label`, `hex`, and `source: "user_selected"`.',
|
|
330
|
-
" - Use `app_file_edit` to update the `## Onboarding Tasks` section: set `make_it_yours` to `done`.",
|
|
331
|
-
"6. If the user declines or wants to skip, set `make_it_yours` to `skipped` in USER.md and move on.",
|
|
332
|
-
"",
|
|
333
|
-
"### Playbook: research_topic",
|
|
334
|
-
"Goal: Research a topic the user is interested in and summarise findings.",
|
|
335
|
-
"",
|
|
336
|
-
'1. Ask the user what topic they\'d like researched. Be specific: "What would you like me to look into?"',
|
|
337
|
-
"2. Once given a topic, use available tools (web search, browser, etc.) to gather information.",
|
|
338
|
-
"3. Synthesise the findings into a clear, well-structured summary.",
|
|
339
|
-
"4. Update the `## Onboarding Tasks` section in USER.md: set `research_topic` to `done`.",
|
|
340
|
-
"",
|
|
341
|
-
"### Playbook: research_to_ui",
|
|
342
|
-
"Goal: Transform research (from a prior research_topic task or current conversation context) into a visual webpage or interactive UI.",
|
|
343
|
-
"",
|
|
344
|
-
"1. Check the conversation history for prior research content. If none exists, ask the user what content they'd like visualised.",
|
|
345
|
-
"2. Synthesise the research into a polished, interactive HTML page using `app_create`.",
|
|
346
|
-
"3. Follow all Dynamic UI quality standards (anti-AI-slop rules, design tokens, hover states, etc.).",
|
|
347
|
-
"4. Update the `## Onboarding Tasks` section in USER.md: set `research_to_ui` to `done`.",
|
|
348
|
-
"",
|
|
349
|
-
"### General rules for all starter tasks",
|
|
350
|
-
"- Update the relevant task status in the `## Onboarding Tasks` section of USER.md as you progress (`in_progress` when starting, `done` when complete).",
|
|
351
|
-
"- Respect trust gating: do NOT ask for elevated permissions during any starter task flow. These are introductory experiences.",
|
|
352
|
-
"- Keep responses concise and action-oriented. Avoid lengthy explanations of what you're about to do.",
|
|
353
|
-
"- If the user deviates from the flow, adapt gracefully. Complete the task if possible, or mark it as `deferred_to_dashboard`.",
|
|
354
|
-
].join("\n");
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function buildToolPermissionSection(): string {
|
|
358
|
-
return [
|
|
359
|
-
"## Tool Permissions",
|
|
360
|
-
"",
|
|
361
|
-
"Some tools (host_bash, host_file_write, host_file_edit, host_file_read) require your user's approval before they run. When you call one of these tools, your user sees **Allow / Don't Allow** buttons in the chat directly below your message.",
|
|
362
|
-
"",
|
|
363
|
-
"**CRITICAL RULE:** You MUST ALWAYS output a text message BEFORE calling any tool that requires approval. NEVER call a permission-gated tool without preceding text. Your user needs context to decide whether to allow.",
|
|
364
|
-
"",
|
|
365
|
-
'**IMPORTANT:** If your user has already granted broad approval for the current conversation (e.g. via "Allow for 10 minutes", "Allow for this conversation", or "Always Allow"), do NOT ask for permission again. Instead, just briefly describe what you\'re about to do and proceed. Only ask "Can you allow?" on the FIRST tool call when you haven\'t been granted permission yet.',
|
|
366
|
-
"",
|
|
367
|
-
"Your text should follow this pattern:",
|
|
368
|
-
"1. **Acknowledge** the request conversationally.",
|
|
369
|
-
'2. **Explain what you need at a high level** (e.g. "I\'ll need to look through your Downloads folder"). Do NOT include raw terminal commands or backtick code. Keep it non-technical.',
|
|
370
|
-
"3. **State safety** in plain language. Is it read-only? Will it change anything?",
|
|
371
|
-
"4. **Ask for permission** only if this is the first time and you haven't been previously approved. If you have been approved, just say what you're doing.",
|
|
372
|
-
"",
|
|
373
|
-
"Style rules:",
|
|
374
|
-
'- NEVER use em dashes (the long dash). Use commas, periods, or "and" instead.',
|
|
375
|
-
"- NEVER show raw commands in backticks like `ls -lt ~/Downloads`. Describe the action in plain English.",
|
|
376
|
-
"- Keep it conversational, like you're talking to a friend.",
|
|
377
|
-
"",
|
|
378
|
-
'First time (no prior approval): "To show your recent downloads, I\'ll need to look through your Downloads folder. This is read-only. Can you allow this?"',
|
|
379
|
-
'Already approved: "Let me check your Downloads folder real quick."',
|
|
380
|
-
'Bad: "I\'ll run `ls -lt ~/Desktop/`" (raw command), or calling a tool with no preceding text.',
|
|
381
|
-
"",
|
|
382
|
-
"### Handling Permission Denials",
|
|
383
|
-
"",
|
|
384
|
-
'When your user denies a tool permission (clicks "Don\'t Allow"), you will receive an error indicating the denial. Follow these rules:',
|
|
385
|
-
"",
|
|
386
|
-
"1. **Do NOT immediately retry the tool call.** Retrying without waiting creates another permission prompt, which is annoying and disrespectful of the user's decision.",
|
|
387
|
-
"2. **Acknowledge the denial.** Tell the user that the action was not performed because they chose not to allow it.",
|
|
388
|
-
"3. **Ask before retrying.** Ask if they would like you to try again, or if they would prefer a different approach.",
|
|
389
|
-
"4. **Wait for an explicit response.** Only retry the tool call after the user explicitly confirms they want you to try again.",
|
|
390
|
-
"5. **Offer alternatives.** If possible, suggest alternative approaches that might not require the denied permission.",
|
|
391
|
-
"",
|
|
392
|
-
"Example:",
|
|
393
|
-
'- Tool denied → "No problem! I wasn\'t able to access your Downloads folder since you chose not to allow it. Would you like me to try again, or is there another way I can help?"',
|
|
394
|
-
"",
|
|
395
|
-
"### Always-Available Tools (No Approval Required)",
|
|
396
|
-
"",
|
|
397
|
-
"- **file_read** on your workspace directory — You can freely read any file under your `.vellum` workspace at any time. Use this proactively to check files, load context, and inform your responses without asking. **Always use `file_read` for workspace files, never `host_file_read`.** Note: your core prompt files (IDENTITY.md, SOUL.md, USER.md) are already loaded into your system prompt — no need to re-read them at the start of a conversation.",
|
|
398
|
-
"- **web_search** — You can search the web at any time without approval. Use this to look up documentation, current information, or anything you need.",
|
|
399
|
-
].join("\n");
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function buildSystemPermissionSection(): string {
|
|
403
|
-
return [
|
|
404
|
-
"## System Permissions",
|
|
405
|
-
"",
|
|
406
|
-
'When a tool execution fails with a permission/access error (e.g. "Operation not permitted", "EACCES", sandbox denial), use `request_system_permission` to ask your user to grant the required macOS permission through System Settings.',
|
|
407
|
-
"",
|
|
408
|
-
"Common cases:",
|
|
409
|
-
"- Reading files in ~/Documents, ~/Desktop, ~/Downloads → `full_disk_access`",
|
|
410
|
-
"- Screen capture / recording → `screen_recording`",
|
|
411
|
-
"- Accessibility / UI automation → `accessibility`",
|
|
412
|
-
"",
|
|
413
|
-
"Do NOT explain how to open System Settings manually — the tool handles it with a clickable button.",
|
|
414
|
-
].join("\n");
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export function buildChannelAwarenessSection(): string {
|
|
418
|
-
return [
|
|
419
|
-
"## Channel Awareness & Trust Gating",
|
|
420
|
-
"",
|
|
421
|
-
"Each turn may include a `<channel_capabilities>` block in the user message describing what the current channel supports. Use this to adapt your behaviour:",
|
|
422
|
-
"",
|
|
423
|
-
"### Channel-specific rules",
|
|
424
|
-
"- When `dashboard_capable` is `false`, never reference the dashboard UI, settings panels, dynamic pages, or visual pickers. Present data as formatted text.",
|
|
425
|
-
"- When `supports_dynamic_ui` is `false`, do not call `ui_show`, `ui_update`, or `app_create`.",
|
|
426
|
-
"- When `supports_voice_input` is `false`, do not ask the user to speak or use their microphone.",
|
|
427
|
-
"- Non-dashboard channels should defer dashboard-specific actions. Tell the user they can complete those steps later from the desktop app.",
|
|
428
|
-
"",
|
|
429
|
-
"### Permission ask trust gating",
|
|
430
|
-
"- Do NOT proactively ask for elevated permissions (microphone, computer control, file access) until the trust stage field `firstConversationComplete` in USER.md is `true`.",
|
|
431
|
-
"- Even after `firstConversationComplete`, only ask for permissions that are relevant to the current channel capabilities.",
|
|
432
|
-
"- Do not ask for microphone permissions on channels where `supports_voice_input` is `false`.",
|
|
433
|
-
"- Do not ask for computer-control permissions on non-dashboard channels.",
|
|
434
|
-
"- When you do request a permission, be transparent about what it enables and why you need it.",
|
|
435
|
-
"",
|
|
436
|
-
"### Push-to-talk awareness",
|
|
437
|
-
"- The `<channel_capabilities>` block may include `ptt_activation_key` and `ptt_enabled` fields indicating the user's push-to-talk configuration.",
|
|
438
|
-
'- You can change the push-to-talk activation key using the `voice_config_update` tool. The key is provided as a JSON PTTActivator payload (e.g. `{"kind":"modifierOnly","modifierFlags":8388608}` for Fn).',
|
|
439
|
-
"- When the user asks about voice input or push-to-talk settings, use the tool to apply changes directly rather than directing them to settings.",
|
|
440
|
-
"- When `microphone_permission_granted` is `false`, guide the user to grant microphone access in System Settings before using voice features.",
|
|
441
|
-
"",
|
|
442
|
-
"### Platform formatting",
|
|
443
|
-
"- **WhatsApp:** Do not use markdown tables — use bullet lists instead. No markdown headers — use **bold** or CAPS for emphasis.",
|
|
444
|
-
"",
|
|
445
|
-
"### Channel command handling",
|
|
446
|
-
"Some channel turns include a `<channel_command_context>` block indicating the user triggered a bot command (e.g. Telegram `/start`).",
|
|
447
|
-
"When `command_type` is `start`: generate a warm, brief greeting (1-3 sentences). Treat `/start` verbatim as a hello. Do NOT reset conversation or mention slash commands. If a `payload` is present, acknowledge it warmly. Respond in the same language as the user's locale if available from channel context, otherwise default to English.",
|
|
448
|
-
].join("\n");
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
export function buildExternalCommsIdentitySection(): string {
|
|
452
|
-
const userRef = resolveUserReference();
|
|
453
|
-
const userPronouns = resolveUserPronouns();
|
|
454
|
-
const lines = [
|
|
455
|
-
"## External Communications Identity",
|
|
456
|
-
"",
|
|
457
|
-
"When communicating with people outside your user's household (phone calls, messages to non-guardian contacts, emails to third parties, etc.):",
|
|
458
|
-
"",
|
|
459
|
-
`- Refer to yourself as an **assistant**, not an "AI assistant" or "artificial intelligence". Keep identity framing simple and natural.`,
|
|
460
|
-
`- When introducing who you represent, say you are acting on behalf of **${userRef}**.`,
|
|
461
|
-
];
|
|
462
|
-
if (userPronouns) {
|
|
463
|
-
lines.push(
|
|
464
|
-
`- Your user's pronouns are **${userPronouns}**. Use these when referring to your user in the third person.`,
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
lines.push(
|
|
468
|
-
"- Do not volunteer that you are an AI unless directly asked. If asked, answer honestly.",
|
|
469
|
-
"- This is guidance for natural, human-like communication — not a hard constraint. Occasional variations are acceptable.",
|
|
470
|
-
);
|
|
471
|
-
return lines.join("\n");
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
export function buildSwarmGuidanceSection(): string {
|
|
475
|
-
return [
|
|
476
|
-
"## Parallel Task Orchestration",
|
|
477
|
-
"",
|
|
478
|
-
'When a task has **multiple independent parts** that benefit from parallel execution (e.g. "research X, implement Y, and review Z"), load the `orchestration` skill using `skill_load` first, then use `swarm_delegate` to decompose and run them in parallel. For single-focus tasks, work directly — do not decompose them into a swarm.',
|
|
217
|
+
"When the user needs to configure a value, collect it conversationally in the chat. Never direct the user to the Settings page for initial setup - Settings is for reviewing and updating existing configuration.",
|
|
479
218
|
].join("\n");
|
|
480
219
|
}
|
|
481
220
|
|
|
482
221
|
function buildAccessPreferenceSection(hasNoClient: boolean): string {
|
|
483
222
|
if (hasNoClient) {
|
|
484
223
|
return [
|
|
485
|
-
"## External Service Access
|
|
486
|
-
"",
|
|
487
|
-
"When interacting with external services (GitHub, Slack, Linear, Jira, cloud providers, etc.),",
|
|
488
|
-
"follow this priority order:",
|
|
224
|
+
"## External Service Access",
|
|
489
225
|
"",
|
|
490
|
-
"1
|
|
491
|
-
" If a tool (git, curl, jq, etc.) is not installed, install it yourself using `bash`",
|
|
492
|
-
" (e.g. `apt-get install -y git`). The sandbox is your own machine — you have full control.",
|
|
493
|
-
"2. **web_fetch** — For public endpoints or simple API calls that don't need auth.",
|
|
494
|
-
"3. **Browser automation as last resort** — Only when the task genuinely requires a browser",
|
|
495
|
-
" (e.g., no API exists, visual interaction needed, or OAuth consent screen).",
|
|
226
|
+
"Priority: (1) sandbox `bash` — install tools yourself; (2) browser automation as last resort (no API, visual interaction, or OAuth consent).",
|
|
496
227
|
].join("\n");
|
|
497
228
|
}
|
|
498
229
|
|
|
499
230
|
return [
|
|
500
|
-
"## External Service Access
|
|
231
|
+
"## External Service Access",
|
|
501
232
|
"",
|
|
502
|
-
"
|
|
503
|
-
"follow this priority order:",
|
|
504
|
-
"",
|
|
505
|
-
"1. **Sandbox first (`bash`)** — Always try to do things in your own sandbox environment first.",
|
|
506
|
-
" If a tool (git, curl, jq, etc.) is not installed, install it yourself using `bash`",
|
|
507
|
-
" (e.g. `apt-get install -y git`). The sandbox is your own machine — you have full control.",
|
|
508
|
-
" Only fall back to host tools when you genuinely need access to the user's local files,",
|
|
509
|
-
" environment, or host-specific resources (e.g. their local git repos, host-installed CLIs",
|
|
510
|
-
" with existing auth, macOS-specific apps).",
|
|
511
|
-
"2. **CES tools for authenticated work** — When a task requires credentials (API keys, OAuth tokens),",
|
|
512
|
-
" discover available handles with `assistant credentials list` or `assistant oauth connections list`,",
|
|
513
|
-
" then use CES tools (`make_authenticated_request`, `run_authenticated_command`). CES injects",
|
|
514
|
-
" credentials securely without exposing raw secrets to the assistant.",
|
|
515
|
-
"3. **CLI tools via host_bash** — If you need access to the user's host environment and a CLI",
|
|
516
|
-
" is installed on their machine (gh, slack, linear, jira, aws, gcloud, etc.), use it.",
|
|
517
|
-
" CLIs handle auth, pagination, and output formatting.",
|
|
518
|
-
" Use --json or equivalent flags for structured output when available.",
|
|
519
|
-
" Note: `host_bash` is approval-gated and outside the CES secrecy boundary.",
|
|
520
|
-
"4. **web_fetch** — For public endpoints or simple API calls that don't need auth.",
|
|
521
|
-
"5. **Browser automation as last resort** — Only when the task genuinely requires a browser",
|
|
522
|
-
" (e.g., no API exists, visual interaction needed, or OAuth consent screen).",
|
|
523
|
-
"",
|
|
524
|
-
"Before reaching for host tools or browser automation, ask yourself:",
|
|
525
|
-
"- Can I do this entirely in my sandbox? (install tools, clone repos, run commands)",
|
|
526
|
-
"- Can I use CES tools for authenticated requests instead of extracting raw tokens?",
|
|
527
|
-
"- Do I actually need something from the user's host machine?",
|
|
528
|
-
"",
|
|
529
|
-
"If you can do it in your sandbox or through CES, do it there. Only use host tools when you need the user's",
|
|
530
|
-
"local files or host-specific capabilities.",
|
|
233
|
+
"Priority: (1) sandbox `bash` - install tools yourself, only fall back to host when you need local files/auth; (2) `host_bash` with CLIs (gh, aws, etc.) using --json flags; (3) browser automation as last resort (no API, visual interaction, or OAuth consent).",
|
|
531
234
|
...(isMacOS()
|
|
532
235
|
? [
|
|
533
236
|
"",
|
|
534
|
-
"On macOS,
|
|
535
|
-
"(Messages, Contacts, Calendar, Mail, Reminders, Music, Finder, etc.) via osascript.",
|
|
536
|
-
"",
|
|
537
|
-
"### Foreground Computer Use — Last Resort",
|
|
538
|
-
"",
|
|
539
|
-
"Computer use tools (clicking, typing, scrolling) take over the user's cursor and keyboard.",
|
|
540
|
-
"They are disruptive and should be your LAST resort. Prefer this hierarchy:",
|
|
541
|
-
"",
|
|
542
|
-
"1. **CLI tools / osascript** — Use `host_bash` with shell commands or `osascript` with",
|
|
543
|
-
" AppleScript to accomplish tasks in the background without interrupting the user.",
|
|
544
|
-
"2. **Background computer use** — If you must interact with a GUI app, prefer AppleScript",
|
|
545
|
-
' automation (e.g. `tell application "Safari" to set URL of current tab to ...`).',
|
|
546
|
-
"3. **Foreground computer use** — Only use computer use tools when the task genuinely",
|
|
547
|
-
" cannot be done any other way (e.g. complex multi-step GUI interactions with no scripting",
|
|
548
|
-
" support) or the user explicitly asks you to take control.",
|
|
237
|
+
"On macOS, prefer osascript/CLI via `host_bash` over computer use tools, which take over the user's cursor. Use foreground computer use only when no scripting alternative exists or the user explicitly asks.",
|
|
549
238
|
]
|
|
550
239
|
: []),
|
|
551
240
|
].join("\n");
|
|
@@ -573,77 +262,10 @@ function buildIntegrationSection(): string {
|
|
|
573
262
|
return lines.join("\n");
|
|
574
263
|
}
|
|
575
264
|
|
|
576
|
-
function buildMemoryPersistenceSection(): string {
|
|
577
|
-
return [
|
|
578
|
-
"## Memory Persistence",
|
|
579
|
-
"",
|
|
580
|
-
"Your memory does not survive session restarts. If you want to remember something, **save it**.",
|
|
581
|
-
"",
|
|
582
|
-
'- Use `memory_manage` with `op: "save"` for facts, preferences, learnings, and anything worth recalling later.',
|
|
583
|
-
"- Update workspace files (USER.md, SOUL.md) for profile and personality changes.",
|
|
584
|
-
'- When someone says "remember this," save it immediately — don\'t rely on keeping it in context.',
|
|
585
|
-
"- When you make a mistake, save the lesson so future-you doesn't repeat it.",
|
|
586
|
-
"",
|
|
587
|
-
"Saved > unsaved. Always.",
|
|
588
|
-
].join("\n");
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function buildMemoryRecallSection(): string {
|
|
592
|
-
return [
|
|
593
|
-
"## Memory Recall",
|
|
594
|
-
"",
|
|
595
|
-
"You have access to a `memory_recall` tool for deep memory retrieval. Use it when:",
|
|
596
|
-
"",
|
|
597
|
-
"- The user asks about past conversations, decisions, or context you don't have in the current window",
|
|
598
|
-
"- You need to recall specific facts, preferences, or project details",
|
|
599
|
-
"- The auto-injected memory context doesn't contain what you need",
|
|
600
|
-
"- The user references something from a previous session",
|
|
601
|
-
"",
|
|
602
|
-
"The tool uses hybrid search (dense and sparse vectors) supplemented by recency. Be specific in your query for best results.",
|
|
603
|
-
].join("\n");
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
function buildWorkspaceReflectionSection(): string {
|
|
607
|
-
return [
|
|
608
|
-
"## Workspace Reflection",
|
|
609
|
-
"",
|
|
610
|
-
"Before you finish responding to a conversation, pause and consider: did you learn anything worth saving?",
|
|
611
|
-
"",
|
|
612
|
-
"- Did your user share personal facts (name, role, timezone, preferences)?",
|
|
613
|
-
"- Did they correct your behavior or express a preference about how you communicate?",
|
|
614
|
-
"- Did they mention a project, tool, or workflow you should remember?",
|
|
615
|
-
"- Did you adapt your style in a way that worked well and should persist?",
|
|
616
|
-
"",
|
|
617
|
-
"If yes, briefly explain what you're updating, then update the relevant workspace file (USER.md, SOUL.md, or IDENTITY.md) as part of your response.",
|
|
618
|
-
].join("\n");
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
function buildLearningMemorySection(): string {
|
|
622
|
-
return [
|
|
623
|
-
"## Learning from Mistakes",
|
|
624
|
-
"",
|
|
625
|
-
"When you make a mistake, hit a dead end, or discover something non-obvious, save it to memory so you don't repeat it.",
|
|
626
|
-
"",
|
|
627
|
-
'Use `memory_manage` with `op: "save", kind: "constraint"` for:',
|
|
628
|
-
"- **Mistakes and corrections** — wrong assumptions, failed approaches, gotchas you ran into",
|
|
629
|
-
"- **Discoveries** — undocumented behaviors, surprising API quirks, things that weren't obvious",
|
|
630
|
-
"- **Working solutions** — the approach that actually worked after trial and error",
|
|
631
|
-
"- **Tool/service insights** — rate limits, auth flows, CLI flags that matter",
|
|
632
|
-
"",
|
|
633
|
-
"The statement should capture both what happened and the takeaway. Write it as advice to your future self.",
|
|
634
|
-
"",
|
|
635
|
-
"Examples:",
|
|
636
|
-
'- `memory_manage({ op: "save", kind: "constraint", subject: "macOS Shortcuts CLI", statement: "shortcuts CLI requires full disk access to export shortcuts — if permission is denied, guide the user to grant it in System Settings rather than retrying." })`',
|
|
637
|
-
'- `memory_manage({ op: "save", kind: "constraint", subject: "Gmail API pagination", statement: "Gmail search returns max 100 results per page. Always check nextPageToken and loop if the user asks for \'all\' messages." })`',
|
|
638
|
-
"",
|
|
639
|
-
"Don't overthink it. If you catch yourself thinking \"I'll remember that for next time,\" save it.",
|
|
640
|
-
].join("\n");
|
|
641
|
-
}
|
|
642
|
-
|
|
643
265
|
function buildContainerizedSection(): string {
|
|
644
266
|
const baseDataDir = getBaseDataDir() ?? "$BASE_DATA_DIR";
|
|
645
267
|
return [
|
|
646
|
-
"## Running in a Container
|
|
268
|
+
"## Running in a Container - Data Persistence",
|
|
647
269
|
"",
|
|
648
270
|
`You are running inside a container. Only the directory \`${baseDataDir}\` is mounted to a persistent volume.`,
|
|
649
271
|
"",
|
|
@@ -653,148 +275,25 @@ function buildContainerizedSection(): string {
|
|
|
653
275
|
`- Always store new data, notes, memories, configs, and downloads under \`${baseDataDir}\``,
|
|
654
276
|
"- Never write persistent data to system directories, `/tmp`, or paths outside the mounted volume",
|
|
655
277
|
"- When in doubt, prefer paths nested under the data directory",
|
|
656
|
-
"- If you create a file that is only needed temporarily (scratch files, intermediate outputs, download staging), delete it when you are done
|
|
278
|
+
"- If you create a file that is only needed temporarily (scratch files, intermediate outputs, download staging), delete it when you are done - disk space on the persistent volume is finite and will grow unboundedly if temp files are not cleaned up",
|
|
657
279
|
].join("\n");
|
|
658
280
|
}
|
|
659
281
|
|
|
660
|
-
function
|
|
282
|
+
function buildParallelToolCallsSection(): string {
|
|
661
283
|
return [
|
|
662
|
-
"
|
|
663
|
-
"",
|
|
664
|
-
"
|
|
665
|
-
"- When a user request requires a tool, call it immediately at the start of your response",
|
|
666
|
-
"- If the request needs multiple tool steps, stay silent while you work and respond once you have concrete results",
|
|
667
|
-
'- Do NOT narrate retries or internal process chatter (for example: "hmm", "that didn\'t work", "let me try...")',
|
|
668
|
-
"- Speak mid-workflow only when you need user input (permission, clarification, or blocker)",
|
|
669
|
-
"- Do NOT provide conversational preamble before calling tools",
|
|
670
|
-
"",
|
|
671
|
-
"Example (CORRECT):",
|
|
672
|
-
" → Call document_create",
|
|
673
|
-
" → Call document_update",
|
|
674
|
-
' → Text: "Drafted and filled your blog post. Review and tell me what to change."',
|
|
675
|
-
"",
|
|
676
|
-
"Example (WRONG):",
|
|
677
|
-
' → Text: "I\'ll try one approach... hmm not that... trying again..."',
|
|
678
|
-
" → Call document_create",
|
|
679
|
-
"",
|
|
680
|
-
"For permission-gated tools, send one short context sentence immediately before the tool call so the user can make an informed allow/deny decision.",
|
|
681
|
-
"",
|
|
682
|
-
'**Reason field:** For every tool call, include a `reason` parameter — a brief, non-technical explanation of what you are doing and why. This is shown to the user as a live status update. Use simple language a non-technical person would understand (e.g. "Checking your project settings" not "file_read config.ts").',
|
|
683
|
-
].join("\n");
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
function buildConfigSection(hasNoClient: boolean): string {
|
|
687
|
-
// Always use `file_edit` (not `host_file_edit`) for workspace files — file_edit
|
|
688
|
-
// handles sandbox path mapping internally, and host_file_edit is permission-gated
|
|
689
|
-
// which would trigger approval prompts for routine workspace updates.
|
|
690
|
-
const hostWorkspaceDir = getWorkspaceDir();
|
|
691
|
-
|
|
692
|
-
const config = getConfig();
|
|
693
|
-
const configPreamble = `Your configuration directory is \`${hostWorkspaceDir}/\`.`;
|
|
694
|
-
|
|
695
|
-
const fileToolGuidance = hasNoClient
|
|
696
|
-
? `${configPreamble} **Always use \`file_read\` and \`file_edit\` for these files** — they are inside your sandbox working directory:`
|
|
697
|
-
: `${configPreamble} **Always use \`file_read\` and \`file_edit\` (not \`host_file_read\` / \`host_file_edit\`) for these files** — they are inside your sandbox working directory and do not require host access or user approval:`;
|
|
698
|
-
|
|
699
|
-
return [
|
|
700
|
-
"## Configuration",
|
|
701
|
-
`- **Active model**: \`${config.services.inference.model}\` (provider: ${config.services.inference.provider})`,
|
|
702
|
-
fileToolGuidance,
|
|
703
|
-
"",
|
|
704
|
-
"- `IDENTITY.md` — Your name, nature, personality, and emoji. Updated during the first-run ritual.",
|
|
705
|
-
"- `SOUL.md` — Core principles, personality, and evolution guidance. Your behavioral foundation.",
|
|
706
|
-
"- `USER.md` — Profile of your user. Update as you learn about them over time.",
|
|
707
|
-
"- `HEARTBEAT.md` — Checklist for periodic heartbeat runs. When heartbeat is enabled, the assistant runs this checklist on a timer and flags anything that needs attention. Edit this file to control what gets checked each run.",
|
|
708
|
-
"- `BOOTSTRAP.md` — First-run ritual script (only present during onboarding; you delete it when done).",
|
|
709
|
-
"- `UPDATES.md` — Release update notes (created automatically on new releases; delete when updates are actioned).",
|
|
710
|
-
"- `skills/` — Directory of installed skills (loaded automatically at startup).",
|
|
711
|
-
"",
|
|
712
|
-
"### Heartbeat",
|
|
713
|
-
"",
|
|
714
|
-
"The heartbeat feature runs your `HEARTBEAT.md` checklist periodically in a background conversation. To enable it, set `heartbeat.enabled: true` and `heartbeat.intervalMs` (default: 3600000 = 1 hour) in `config.json`. You can also set `heartbeat.activeHoursStart` and `heartbeat.activeHoursEnd` (0-23) to restrict runs to certain hours. When asked to set up a heartbeat, edit both the config and `HEARTBEAT.md` directly — no restart is needed for checklist changes, but toggling `heartbeat.enabled` requires a daemon restart.",
|
|
715
|
-
"",
|
|
716
|
-
"### Proactive Workspace Editing",
|
|
717
|
-
"",
|
|
718
|
-
`You MUST actively update your workspace files as you learn. You don't need to ask your user whether it's okay — just briefly explain what you're updating, then use \`file_edit\` to make targeted edits.`,
|
|
719
|
-
"",
|
|
720
|
-
"**USER.md** — update when you learn:",
|
|
721
|
-
"- Their name or what they prefer to be called",
|
|
722
|
-
"- Projects they're working on, tools they use, languages they code in",
|
|
723
|
-
"- Communication preferences (concise vs detailed, formal vs casual)",
|
|
724
|
-
"- Interests, hobbies, or context that helps you assist them better",
|
|
725
|
-
"- Anything else about your user that will help you serve them better",
|
|
726
|
-
"",
|
|
727
|
-
"**SOUL.md** — update when you notice:",
|
|
728
|
-
"- They prefer a different tone or interaction style (add to Personality or User-Specific Behavior)",
|
|
729
|
-
'- A behavioral pattern worth codifying (e.g. "always explain before acting", "skip preamble")',
|
|
730
|
-
"- You've adapted in a way that's working well and should persist",
|
|
731
|
-
"- You decide to change your personality to better serve your user",
|
|
732
|
-
"",
|
|
733
|
-
"**IDENTITY.md** — update when:",
|
|
734
|
-
"- They rename you or change your role",
|
|
735
|
-
"- Your avatar appearance changes (update the `## Avatar` section with a description of the new look)",
|
|
736
|
-
"",
|
|
737
|
-
...(hasNoClient
|
|
738
|
-
? [
|
|
739
|
-
"When reading or updating workspace files, always use the sandbox tools (`file_read`, `file_edit`).",
|
|
740
|
-
]
|
|
741
|
-
: [
|
|
742
|
-
"When reading or updating workspace files, always use the sandbox tools (`file_read`, `file_edit`). Never use `host_file_read` or `host_file_edit` for workspace files — those are for host-only resources outside your workspace.",
|
|
743
|
-
]),
|
|
744
|
-
"",
|
|
745
|
-
"When updating, read the file first, then make a targeted edit. Include all useful information, but don't bloat the files over time",
|
|
284
|
+
"<use_parallel_tool_calls>",
|
|
285
|
+
"For maximum efficiency, whenever you perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. Prioritize calling tools in parallel whenever possible. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. When running multiple read-only commands like `ls` or `list_dir`, always run all of the commands in parallel. Err on the side of maximizing parallel tool calls rather than running too many tools sequentially.",
|
|
286
|
+
"</use_parallel_tool_calls>",
|
|
746
287
|
].join("\n");
|
|
747
288
|
}
|
|
748
289
|
|
|
749
290
|
export function buildCliReferenceSection(): string {
|
|
750
|
-
if (cachedCliHelp === undefined) {
|
|
751
|
-
cachedCliHelp = CLI_HELP_REFERENCE.trim();
|
|
752
|
-
}
|
|
753
|
-
|
|
754
291
|
return [
|
|
755
292
|
"## Assistant CLI",
|
|
756
293
|
"",
|
|
757
|
-
"The `assistant` CLI is available in the sandbox. Always use the `bash` tool (never `host_bash`) when running `assistant` commands.",
|
|
758
|
-
"",
|
|
759
|
-
"### Credential Discovery and Authenticated Work",
|
|
760
|
-
"",
|
|
761
|
-
"When you need to make authenticated requests or run commands that require credentials, follow this workflow:",
|
|
762
|
-
"",
|
|
763
|
-
"1. **Discover available credentials** by running:",
|
|
764
|
-
" - `assistant credentials list` — lists local credentials with their service:field identifiers",
|
|
765
|
-
" - `assistant oauth connections list` — lists OAuth connections with provider keys",
|
|
766
|
-
" - `assistant credentials list --search <query>` — filter by service, field, or description",
|
|
767
|
-
...(isPlatformManaged()
|
|
768
|
-
? [
|
|
769
|
-
" In managed deployments, credential handles use the `platform_oauth:<connectionId>` format (shown in the `handle` field of `assistant oauth connections list`). Local credential handles (`local_static`, `local_oauth`) are not available in managed mode.",
|
|
770
|
-
]
|
|
771
|
-
: [
|
|
772
|
-
" For local credentials, construct the CES handle as `local_static:<service>/<field>` from the listed identifiers. For local OAuth connections, the handle is `local_oauth:<providerKey>/<connectionId>` (shown in the `handle` field of `assistant oauth connections list`). Platform-managed entries use `platform_oauth:<connectionId>` handles, also shown in their `handle` field.",
|
|
773
|
-
]),
|
|
774
|
-
"",
|
|
775
|
-
"2. **Use CES tools** with the handle to perform authenticated work:",
|
|
776
|
-
" - `make_authenticated_request` — authenticated HTTP requests (API calls, webhooks). CES injects the credential and returns the response; the assistant never sees raw secrets.",
|
|
777
|
-
" - `run_authenticated_command` — run a command with credential environment variables injected by CES. The command runs inside the CES sandbox.",
|
|
778
|
-
" - `manage_secure_command_tool` — install, update, or remove secure command tool bundles. Accepts only bundle metadata for guardian review.",
|
|
779
|
-
"",
|
|
780
|
-
"3. **Never reveal raw secrets.** Do not use `assistant credentials reveal` or `assistant oauth connections token` to extract raw token values and pass them to `bash` or `host_bash`. Always route authenticated work through CES tools.",
|
|
781
|
-
"",
|
|
782
|
-
"For account setup and credential management (not execution), use:",
|
|
783
|
-
"- `assistant credentials set ...` — store a new credential",
|
|
784
|
-
"- `assistant oauth connections connect <provider>` — initiate an OAuth flow",
|
|
785
|
-
"- `assistant mcp auth <name>` — when an MCP server needs OAuth login",
|
|
786
|
-
"- `assistant platform status` — platform-linked deployment and auth context",
|
|
787
|
-
"- If a bundled skill documents a service-specific `assistant <service>` auth or session flow, follow that CLI exactly.",
|
|
788
|
-
"",
|
|
789
|
-
"### host_bash and Credentials",
|
|
294
|
+
"The `assistant` CLI is available in the sandbox for managing assistant settings, integrations, and services. Always use the `bash` tool (never `host_bash`) when running `assistant` commands.",
|
|
790
295
|
"",
|
|
791
|
-
"`
|
|
792
|
-
"",
|
|
793
|
-
"```",
|
|
794
|
-
cachedCliHelp,
|
|
795
|
-
"```",
|
|
796
|
-
"",
|
|
797
|
-
"Run `assistant <command> --help` for detailed help on any subcommand.",
|
|
296
|
+
"Run `assistant --help` to see all available commands, or `assistant <command> --help` for detailed help on any subcommand.",
|
|
798
297
|
].join("\n");
|
|
799
298
|
}
|
|
800
299
|
|
|
@@ -827,6 +326,34 @@ export function stripCommentLines(content: string): string {
|
|
|
827
326
|
.trim();
|
|
828
327
|
}
|
|
829
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Returns true when the prompt file content is still the unmodified template
|
|
331
|
+
* shipped with the daemon. Compares the stripped workspace content against
|
|
332
|
+
* the stripped bundled template source so the check stays accurate even if
|
|
333
|
+
* templates are edited in future releases.
|
|
334
|
+
*/
|
|
335
|
+
export function isTemplateContent(
|
|
336
|
+
content: string | null,
|
|
337
|
+
templateFileName: string,
|
|
338
|
+
): boolean {
|
|
339
|
+
if (content == null) return false;
|
|
340
|
+
const templatesDir = resolveBundledDir(
|
|
341
|
+
import.meta.dirname ?? __dirname,
|
|
342
|
+
"templates",
|
|
343
|
+
"templates",
|
|
344
|
+
);
|
|
345
|
+
const templatePath = join(templatesDir, templateFileName);
|
|
346
|
+
if (!existsSync(templatePath)) return false;
|
|
347
|
+
try {
|
|
348
|
+
const templateContent = stripCommentLines(
|
|
349
|
+
readFileSync(templatePath, "utf-8"),
|
|
350
|
+
);
|
|
351
|
+
return content === templateContent;
|
|
352
|
+
} catch {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
830
357
|
function readPromptFile(path: string): string | null {
|
|
831
358
|
if (!existsSync(path)) return null;
|
|
832
359
|
|
|
@@ -852,7 +379,12 @@ export function buildCoreIdentityContext(): string | null {
|
|
|
852
379
|
const parts: string[] = [];
|
|
853
380
|
for (const file of PROMPT_FILES) {
|
|
854
381
|
const content = readPromptFile(getWorkspacePromptPath(file));
|
|
855
|
-
if (content)
|
|
382
|
+
if (!content) continue;
|
|
383
|
+
// SOUL.md is always included — it provides personality defaults even
|
|
384
|
+
// before onboarding completes. Only skip IDENTITY.md and USER.md when
|
|
385
|
+
// they are still unmodified templates (matching buildSystemPrompt).
|
|
386
|
+
if (file !== "SOUL.md" && isTemplateContent(content, file)) continue;
|
|
387
|
+
parts.push(content);
|
|
856
388
|
}
|
|
857
389
|
return parts.length > 0 ? parts.join("\n\n") : null;
|
|
858
390
|
}
|
|
@@ -872,57 +404,9 @@ function appendSkillsCatalog(basePrompt: string): string {
|
|
|
872
404
|
const catalog = formatSkillsCatalog(flagFiltered);
|
|
873
405
|
if (catalog) sections.push(catalog);
|
|
874
406
|
|
|
875
|
-
sections.push(buildDynamicSkillWorkflowSection(config, flagFiltered));
|
|
876
|
-
|
|
877
407
|
return sections.join("\n\n");
|
|
878
408
|
}
|
|
879
409
|
|
|
880
|
-
function buildDynamicSkillWorkflowSection(
|
|
881
|
-
_config: import("../config/schema.js").AssistantConfig,
|
|
882
|
-
_activeSkills: SkillSummary[],
|
|
883
|
-
): string {
|
|
884
|
-
const lines = [
|
|
885
|
-
"## Dynamic Skill Authoring Workflow",
|
|
886
|
-
"",
|
|
887
|
-
"When no existing tool or skill can satisfy a request:",
|
|
888
|
-
"1. Validate the gap — confirm no existing tool/skill covers it.",
|
|
889
|
-
"2. Draft a TypeScript snippet exporting a `default` or `run` function (`(input: unknown) => unknown | Promise<unknown>`).",
|
|
890
|
-
'3. Test the snippet by writing it to a temp file with `bash` (e.g., `bash command="mkdir -p /tmp/vellum-eval && cat > /tmp/vellum-eval/snippet.ts << \'SNIPPET_EOF\'\\n...\\nSNIPPET_EOF"`) and running it with `bash command="bun run /tmp/vellum-eval/snippet.ts"`. Do not use `file_write` for temp files outside the working directory. Iterate until it passes (max 3 attempts, then ask the user). Clean up temp files after.',
|
|
891
|
-
"4. Persist with `scaffold_managed_skill` only after user consent.",
|
|
892
|
-
"5. Load with `skill_load` before use.",
|
|
893
|
-
"",
|
|
894
|
-
"**Never persist or delete skills without explicit user confirmation.** To remove: `delete_managed_skill`.",
|
|
895
|
-
"After a skill is written or deleted, the next turn may run in a recreated session due to file-watcher eviction. Continue normally.",
|
|
896
|
-
];
|
|
897
|
-
|
|
898
|
-
lines.push(
|
|
899
|
-
"",
|
|
900
|
-
"### Community Skills Discovery",
|
|
901
|
-
"",
|
|
902
|
-
"When no built-in skill satisfies a request, search the community skills.sh registry:",
|
|
903
|
-
"1. Run `assistant skills search <query>` to find community skills. Results include install counts and security audit badges (ATH, Socket, Snyk).",
|
|
904
|
-
"2. Present the search results to the user, highlighting the security audit status. ATH is Gen Agent Trust Hub. Audits show PASS (safe/low risk), WARN (medium risk), or FAIL (high/critical risk) for each provider.",
|
|
905
|
-
"3. Check the skill's **source owner** to determine the trust level:",
|
|
906
|
-
" - **Vellum-owned** (source starts with `vellum-ai/`): These are first-party skills published by the Vellum team. Install them directly without prompting — they are vetted and trusted.",
|
|
907
|
-
" - **Third-party** (any other owner): Ask the user for permission before installing. Say something like: \"I found a community skill that could help with this, but it's published by a third party — we haven't vetted it. Want to install it anyway?\" Share the skill name, source, audit results, and install count.",
|
|
908
|
-
"4. Install with `assistant skills add <owner>/<repo>@<skill-name>` (e.g., `assistant skills add vercel-labs/skills@find-skills`).",
|
|
909
|
-
"5. After installation, load the skill with `skill_load` as usual.",
|
|
910
|
-
"",
|
|
911
|
-
"**Never install third-party community skills without explicit user confirmation.** Vellum-owned skills (`vellum-ai/*`) can be installed automatically.",
|
|
912
|
-
);
|
|
913
|
-
|
|
914
|
-
return lines.join("\n");
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
function escapeXml(str: string): string {
|
|
918
|
-
return str
|
|
919
|
-
.replace(/&/g, "&")
|
|
920
|
-
.replace(/</g, "<")
|
|
921
|
-
.replace(/>/g, ">")
|
|
922
|
-
.replace(/"/g, """)
|
|
923
|
-
.replace(/'/g, "'");
|
|
924
|
-
}
|
|
925
|
-
|
|
926
410
|
/**
|
|
927
411
|
* Build a dynamic description for the mcp-setup skill that includes
|
|
928
412
|
* configured MCP server names, so the model knows which servers exist.
|
|
@@ -931,44 +415,31 @@ function getMcpSetupDescription(): string {
|
|
|
931
415
|
const config = getConfig();
|
|
932
416
|
const servers = config.mcp?.servers;
|
|
933
417
|
if (!servers || Object.keys(servers).length === 0) {
|
|
934
|
-
return "Add, authenticate, list, and remove MCP
|
|
418
|
+
return "Add, authenticate, list, and remove MCP servers";
|
|
935
419
|
}
|
|
936
420
|
|
|
937
421
|
const serverNames = Object.keys(servers).sort();
|
|
938
|
-
return `Manage MCP servers. Configured: ${serverNames.join(", ")}. Load
|
|
422
|
+
return `Manage MCP servers. Configured: ${serverNames.join(", ")}. Load to check status, authenticate, or add/remove servers.`;
|
|
939
423
|
}
|
|
940
424
|
|
|
941
425
|
function formatSkillsCatalog(skills: SkillSummary[]): string {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
skill.avoidWhen && skill.avoidWhen.length > 0
|
|
959
|
-
? ` avoid-when="${escapeXml(skill.avoidWhen.join("; "))}"`
|
|
960
|
-
: "";
|
|
961
|
-
lines.push(
|
|
962
|
-
`<skill id="${idAttr}" name="${nameAttr}" description="${descAttr}"${hintsAttr}${avoidAttr} />`,
|
|
963
|
-
);
|
|
426
|
+
if (skills.length === 0) return "";
|
|
427
|
+
|
|
428
|
+
const lines = ["## Available Skills", ""];
|
|
429
|
+
for (const skill of skills) {
|
|
430
|
+
const desc =
|
|
431
|
+
skill.id === "mcp-setup" ? getMcpSetupDescription() : skill.description;
|
|
432
|
+
|
|
433
|
+
// Build a single line: - **id**: description. Hints. Avoid: ...
|
|
434
|
+
const parts = [desc.replace(/\.\s*$/, "")];
|
|
435
|
+
if (skill.activationHints && skill.activationHints.length > 0) {
|
|
436
|
+
parts.push(skill.activationHints.join(". "));
|
|
437
|
+
}
|
|
438
|
+
if (skill.avoidWhen && skill.avoidWhen.length > 0) {
|
|
439
|
+
parts.push(`Avoid: ${skill.avoidWhen.join(". ")}`);
|
|
440
|
+
}
|
|
441
|
+
lines.push(`- **${skill.id}**: ${parts.join(". ")}`);
|
|
964
442
|
}
|
|
965
|
-
lines.push("</available_skills>");
|
|
966
443
|
|
|
967
|
-
return
|
|
968
|
-
"## Available Skills",
|
|
969
|
-
"The following skills are available. Before executing one, call `skill_load` to load the full instructions, then use `skill_execute` to invoke the skill's tools.",
|
|
970
|
-
"",
|
|
971
|
-
lines.join("\n"),
|
|
972
|
-
"",
|
|
973
|
-
].join("\n");
|
|
444
|
+
return lines.join("\n");
|
|
974
445
|
}
|