@vellumai/assistant 0.6.2 → 0.6.3
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/bun.lock +40 -40
- package/bunfig.toml +3 -0
- package/docs/architecture/memory.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +184 -69
- package/package.json +41 -41
- package/scripts/generate-openapi.ts +1 -2
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/browser-fill-credential.test.ts +229 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/catalog-files.test.ts +862 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +125 -48
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/context-overflow-approval.test.ts +16 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +1 -1
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -2
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-queue.test.ts +45 -2
- package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -4
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +2 -2
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/gemini-provider.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +707 -371
- package/src/__tests__/headless-browser-navigate.test.ts +389 -47
- package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
- package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
- package/src/__tests__/host-bash-proxy.test.ts +150 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
- package/src/__tests__/host-cu-proxy.test.ts +171 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +61 -2
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +101 -1
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/oauth-apps-routes.test.ts +17 -12
- package/src/__tests__/oauth-cli.test.ts +707 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +50 -14
- package/src/__tests__/oauth-store.test.ts +1386 -182
- package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
- package/src/__tests__/onboarding-template-contract.test.ts +75 -57
- package/src/__tests__/openai-provider.test.ts +2 -2
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/require-fresh-approval.test.ts +40 -1
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
- package/src/__tests__/slack-channel-config.test.ts +12 -15
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +72 -1
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +14 -29
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/loop.ts +12 -6
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +53 -3
- package/src/cli/commands/browser-relay.ts +339 -409
- package/src/cli/commands/credentials.ts +3 -3
- package/src/cli/commands/email.ts +18 -13
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +44 -44
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +6 -3
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +200 -36
- package/src/cli/commands/oauth/shared.ts +5 -5
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +26 -249
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/contacts/SKILL.md +3 -0
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/outlook/SKILL.md +7 -0
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/env-registry.ts +14 -0
- package/src/config/env.ts +21 -0
- package/src/config/feature-flag-registry.json +44 -5
- package/src/config/loader.ts +56 -1
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +46 -5
- package/src/config/schemas/host-browser.ts +66 -0
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +8 -0
- package/src/config/types.ts +0 -1
- package/src/context/post-turn-tool-result-truncation.ts +176 -0
- package/src/context/window-manager.ts +19 -1
- package/src/credential-execution/approval-bridge.ts +49 -15
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/context-overflow-approval.ts +5 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
- package/src/daemon/conversation-agent-loop.ts +58 -24
- package/src/daemon/conversation-attachments.ts +40 -0
- package/src/daemon/conversation-process.ts +48 -1
- package/src/daemon/conversation-runtime-assembly.ts +118 -36
- package/src/daemon/conversation-surfaces.ts +37 -36
- package/src/daemon/conversation-tool-setup.ts +74 -8
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +226 -8
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/conversations.ts +9 -140
- package/src/daemon/handlers/shared.ts +58 -0
- package/src/daemon/handlers/skills.ts +232 -37
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +191 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +65 -11
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/conversations.ts +55 -13
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/messages.ts +5 -5
- package/src/daemon/message-types/skills.ts +10 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/server.ts +92 -12
- package/src/daemon/tool-side-effects.ts +6 -0
- package/src/daemon/transport-hints.ts +5 -24
- package/src/inbound/platform-callback-registration.ts +18 -17
- package/src/mcp/client.ts +59 -24
- package/src/memory/app-store.ts +31 -1
- package/src/memory/conversation-crud.ts +23 -0
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +12 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +176 -17
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/retriever.ts +40 -22
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/llm-usage-store.ts +45 -4
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +1 -0
- package/src/memory/schema/oauth.ts +18 -13
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +8 -8
- package/src/oauth/byo-connection.ts +7 -7
- package/src/oauth/connect-orchestrator.ts +23 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +16 -16
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +214 -100
- package/src/oauth/platform-connection.test.ts +3 -3
- package/src/oauth/platform-connection.ts +4 -4
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +126 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -1
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/prompts/system-prompt.ts +18 -21
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -105
- package/src/providers/anthropic/client.ts +1 -0
- package/src/providers/types.ts +1 -1
- package/src/runtime/AGENTS.md +23 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/assistant-event-hub.ts +2 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +6 -7
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/chrome-extension-registry.ts +332 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +425 -70
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
- package/src/runtime/migrations/migration-transport.ts +6 -0
- package/src/runtime/migrations/migration-wizard.ts +22 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
- package/src/runtime/migrations/vbundle-importer.ts +55 -5
- package/src/runtime/pending-interactions.ts +29 -13
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/browser-cdp-routes.ts +229 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
- package/src/runtime/routes/conversation-analysis-routes.ts +2 -1
- package/src/runtime/routes/conversation-management-routes.ts +108 -0
- package/src/runtime/routes/conversation-routes.ts +301 -27
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/host-browser-routes.ts +279 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-routes.ts +259 -16
- package/src/runtime/routes/log-export-routes.ts +42 -22
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +87 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +9 -97
- package/src/runtime/routes/skills-routes.ts +52 -2
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/usage-routes.ts +8 -7
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/schedule/scheduler.ts +7 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +42 -25
- package/src/security/secure-keys.ts +118 -25
- package/src/security/token-manager.ts +23 -10
- package/src/skills/catalog-files.ts +492 -0
- package/src/subagent/manager.ts +131 -26
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +645 -340
- package/src/tools/browser/browser-manager.ts +36 -12
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
- package/src/tools/browser/cdp-client/errors.ts +34 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
- package/src/tools/browser/cdp-client/factory.ts +204 -0
- package/src/tools/browser/cdp-client/index.ts +14 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +52 -0
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/permission-checker.ts +77 -82
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -0
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/shell.ts +21 -16
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/types.ts +2 -0
- package/src/util/platform.ts +14 -19
- package/src/workspace/top-level-renderer.ts +19 -1
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -8,6 +8,10 @@ metadata:
|
|
|
8
8
|
display-name: "App Builder"
|
|
9
9
|
includes:
|
|
10
10
|
- "frontend-design"
|
|
11
|
+
activation-hints:
|
|
12
|
+
- "User asks to build an app, landing page, website, dashboard, tool, calculator, game, tracker, or interactive page"
|
|
13
|
+
- "User asks to visualize data or says 'let's visualize this' — use the app sandbox to build interactive visualizations"
|
|
14
|
+
- "ALWAYS prefer the app sandbox over building standalone web apps, local servers, or outputting raw HTML/CSS/JS in chat — even when the user says 'make this an app' or 'turn this into an app'"
|
|
11
15
|
---
|
|
12
16
|
|
|
13
17
|
You are an expert app builder and visual designer. When the user asks you to create an app, tool, or utility, you immediately design a data schema, choose a stunning visual direction, build the interface, and open it - all in one step. You don't discuss or ask for permission to be creative. You ARE the designer: you pick the colors, the layout, the atmosphere, the micro-interactions. Your apps should make users stop and say "whoa" - they should feel designed, not generated.
|
|
@@ -173,13 +177,16 @@ export const Header: FunctionComponent<Props> = ({ title, count }) => {
|
|
|
173
177
|
|
|
174
178
|
**CSS:** Import CSS files directly in TSX (`import './styles.css'`). You can also use inline styles via the `style` attribute on JSX elements.
|
|
175
179
|
|
|
176
|
-
**
|
|
180
|
+
**Custom routes in TSX:** Use `window.vellum.fetch()` to call custom route handlers from components — see the [Custom route handlers](#custom-route-handlers-user-defined-routes) section for full details:
|
|
177
181
|
|
|
178
182
|
```tsx
|
|
179
|
-
const [
|
|
183
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
180
184
|
|
|
181
185
|
useEffect(() => {
|
|
182
|
-
window.vellum.
|
|
186
|
+
window.vellum.fetch("/v1/x/items")
|
|
187
|
+
.then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
|
|
188
|
+
.then(setItems)
|
|
189
|
+
.catch(console.error);
|
|
183
190
|
}, []);
|
|
184
191
|
```
|
|
185
192
|
|
|
@@ -211,7 +218,10 @@ export const App: FunctionComponent = () => {
|
|
|
211
218
|
const [records, setRecords] = useState([]);
|
|
212
219
|
|
|
213
220
|
useEffect(() => {
|
|
214
|
-
window.vellum.
|
|
221
|
+
window.vellum.fetch("/v1/x/projects")
|
|
222
|
+
.then((res) => res.ok ? res.json() : Promise.reject(res.status))
|
|
223
|
+
.then(setRecords)
|
|
224
|
+
.catch(console.error);
|
|
215
225
|
}, []);
|
|
216
226
|
|
|
217
227
|
return (
|
|
@@ -309,131 +319,15 @@ window.addEventListener("vellum-theme-change", (e) => {
|
|
|
309
319
|
|
|
310
320
|
#### Widget component library
|
|
311
321
|
|
|
312
|
-
A CSS/JS widget library is auto-injected alongside the design system. Use
|
|
313
|
-
|
|
314
|
-
**Layout widgets** (class names, infer HTML structure):
|
|
315
|
-
|
|
316
|
-
| Widget | Purpose |
|
|
317
|
-
| ------------------------------------------------------------ | -------------------------------------------------------------- |
|
|
318
|
-
| `.v-metric-card` (`.v-metric-grid`) | Big number with emoji icon, label, trend |
|
|
319
|
-
| `.v-data-table` | Sortable table with sticky header, `th[data-sortable]` |
|
|
320
|
-
| `.v-tabs` / `.v-tab-bar` / `.v-tab-panel` | Tab navigation with keyboard support |
|
|
321
|
-
| `.v-accordion` / `.v-accordion-item` | Collapsible sections |
|
|
322
|
-
| `.v-search-bar` | Search input with clear button |
|
|
323
|
-
| `.v-empty-state` | No-data placeholder with CTA |
|
|
324
|
-
| `.v-timeline` / `.v-timeline-entry` | Vertical timeline (`.active`/`.success`/`.error`) |
|
|
325
|
-
| `.v-action-list` / `.v-action-list-item` | Rows with per-item actions |
|
|
326
|
-
| `.v-card-grid` | Responsive card grid |
|
|
327
|
-
| `.v-progress-bar` / `.v-progress-track` / `.v-progress-fill` | Horizontal progress |
|
|
328
|
-
| `.v-status-badge` | Colored pill with dot (`.success`/`.error`/`.warning`/`.info`) |
|
|
329
|
-
| `.v-stat-row` / `.v-stat` | Horizontal label-value pairs |
|
|
330
|
-
| `.v-toast` | Notification banner - prefer `vellum.widgets.toast()` |
|
|
331
|
-
| `.v-avatar-row` | Contact/team display |
|
|
332
|
-
| `.v-tag-group` | Wrapping tag row |
|
|
333
|
-
|
|
334
|
-
**Domain-specific widgets** (class names, infer HTML structure):
|
|
335
|
-
|
|
336
|
-
| Widget | Purpose |
|
|
337
|
-
| ------------------ | ---------------------- |
|
|
338
|
-
| `.v-weather-card` | Temperature + forecast |
|
|
339
|
-
| `.v-stock-ticker` | Price display + chart |
|
|
340
|
-
| `.v-flight-card` | Flight info with route |
|
|
341
|
-
| `.v-billing-chart` | Usage/billing display |
|
|
342
|
-
| `.v-boarding-pass` | Pass-styled layout |
|
|
343
|
-
| `.v-itinerary` | Day-by-day travel plan |
|
|
344
|
-
| `.v-receipt` | Receipt layout |
|
|
345
|
-
| `.v-invoice` | Formal invoice |
|
|
346
|
-
|
|
347
|
-
**Content & landing page components** (class names, infer HTML structure):
|
|
348
|
-
|
|
349
|
-
| Widget | Purpose |
|
|
350
|
-
| ------------------------------------------------ | --------------------------------------------------- |
|
|
351
|
-
| `.v-hero` / `.v-hero-badge` / `.v-hero-subtitle` | Hero banner with gradient, trust badge, accent word |
|
|
352
|
-
| `.v-section-header` / `.v-section-label` | Section intro with label |
|
|
353
|
-
| `.v-feature-grid` / `.v-feature-card` | Feature showcase with hover lift |
|
|
354
|
-
| `.v-pullquote` | Blockquote with gradient accent border |
|
|
355
|
-
| `.v-comparison` | Before/after cards (`.before`/`.after`) |
|
|
356
|
-
| `.v-page` | Centered container (max-width 600px) |
|
|
357
|
-
| `.v-gradient-text` | Accent-colored gradient text |
|
|
358
|
-
| `.v-animate-in` | Staggered fade-in for children |
|
|
359
|
-
|
|
360
|
-
#### Widget JavaScript utilities
|
|
361
|
-
|
|
362
|
-
Interactive utilities at `window.vellum.widgets.*`:
|
|
363
|
-
|
|
364
|
-
**Charts** (always use these instead of hand-coding SVG/CSS charts):
|
|
322
|
+
A CSS/JS widget library is auto-injected alongside the design system. Use `.v-*` class names for standard UI patterns (tables, metrics, timelines, cards, etc.) and `window.vellum.widgets.*` JS utilities for charts, data formatting, and interactive behaviors. **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts.
|
|
365
323
|
|
|
366
|
-
|
|
367
|
-
vellum.widgets.sparkline("container-id", [10, 25, 15, 30], {
|
|
368
|
-
width: 200,
|
|
369
|
-
height: 40,
|
|
370
|
-
color: "var(--v-success)",
|
|
371
|
-
strokeWidth: 2,
|
|
372
|
-
fill: true,
|
|
373
|
-
});
|
|
374
|
-
vellum.widgets.barChart(
|
|
375
|
-
"container-id",
|
|
376
|
-
[
|
|
377
|
-
{ label: "Jan", value: 120 },
|
|
378
|
-
{ label: "Feb", value: 180, color: "var(--v-success)" },
|
|
379
|
-
],
|
|
380
|
-
{
|
|
381
|
-
width: 400,
|
|
382
|
-
height: 200,
|
|
383
|
-
showLabels: true,
|
|
384
|
-
showValues: true,
|
|
385
|
-
horizontal: false,
|
|
386
|
-
},
|
|
387
|
-
);
|
|
388
|
-
vellum.widgets.lineChart(
|
|
389
|
-
"container-id",
|
|
390
|
-
[
|
|
391
|
-
{ label: "Mon", value: 42 },
|
|
392
|
-
{ label: "Tue", value: 58 },
|
|
393
|
-
],
|
|
394
|
-
{ width: 400, height: 200, showDots: true, showGrid: true, gridLines: 4 },
|
|
395
|
-
);
|
|
396
|
-
vellum.widgets.progressRing("container-id", 75, {
|
|
397
|
-
size: 100,
|
|
398
|
-
strokeWidth: 8,
|
|
399
|
-
color: "var(--v-success)",
|
|
400
|
-
label: "75%",
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
**Data Formatting:**
|
|
405
|
-
|
|
406
|
-
```javascript
|
|
407
|
-
vellum.widgets.formatCurrency(1234.56, "USD"); // "$1,234.56"
|
|
408
|
-
vellum.widgets.formatDate("2025-01-15", "relative"); // "3d ago"
|
|
409
|
-
vellum.widgets.formatDate("2025-01-15", "short"); // "1/15/25"
|
|
410
|
-
vellum.widgets.formatNumber(1234567, { compact: true }); // "1.2M"
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
**Interactive Behaviors:**
|
|
414
|
-
|
|
415
|
-
```javascript
|
|
416
|
-
vellum.widgets.sortTable("table-id"); // Wire th[data-sortable] click-to-sort
|
|
417
|
-
vellum.widgets.filterTable("table-id", "input-id"); // Live text search
|
|
418
|
-
vellum.widgets.tabs("tabs-id"); // Tab switching + keyboard nav
|
|
419
|
-
vellum.widgets.accordion("accordion-id", { allowMultiple: true });
|
|
420
|
-
vellum.widgets.multiSelect("table-id"); // Checkboxes + select-all
|
|
421
|
-
vellum.widgets.toast("Saved!", "success", 4000); // Auto-dismiss notification
|
|
422
|
-
vellum.widgets.countdown("timer-el", "2025-12-31T00:00:00Z", {
|
|
423
|
-
onComplete: () => {},
|
|
424
|
-
});
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
#### When to use widgets vs custom HTML
|
|
324
|
+
For the full widget reference (class names, JS APIs, chart functions, formatting utilities), see **[Widget Component Library](references/WIDGETS.md)**.
|
|
428
325
|
|
|
429
|
-
|
|
430
|
-
- **Use custom HTML** for novel or creative UIs - games, art tools, unique dashboards
|
|
431
|
-
- **Mix freely** - widgets compose well together and with custom elements
|
|
432
|
-
- **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
|
|
326
|
+
#### Data bridge API (deprecated)
|
|
433
327
|
|
|
434
|
-
|
|
328
|
+
> **Prefer custom route handlers** for new apps. The data bridge (`window.vellum.data`) only works for assistants that run on the same machine as the desktop app, which will also be deprecated soon.
|
|
435
329
|
|
|
436
|
-
The
|
|
330
|
+
The native WebView can read and write app records via `window.vellum.data`. All methods return Promises.
|
|
437
331
|
|
|
438
332
|
- `window.vellum.data.query()` - Returns all records: `{ id, appId, data, createdAt, updatedAt }[]`
|
|
439
333
|
- `window.vellum.data.create(data)` - Creates a record. Returns the created record.
|
|
@@ -450,85 +344,9 @@ Important:
|
|
|
450
344
|
|
|
451
345
|
#### Custom route handlers (user-defined routes)
|
|
452
346
|
|
|
453
|
-
When the app needs server-side persistence, custom API logic, or workspace file access, use **user-defined routes**. Route handlers are TypeScript
|
|
454
|
-
|
|
455
|
-
**Common use cases:** CRUD storage, file-based persistence, search/aggregation, external API proxying, webhook receivers.
|
|
456
|
-
|
|
457
|
-
**Handler file convention:**
|
|
458
|
-
|
|
459
|
-
Each handler file exports named functions for the HTTP methods it supports (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`). Handlers use the standard Web API `Request`/`Response` signature.
|
|
460
|
-
|
|
461
|
-
```
|
|
462
|
-
{workspaceDir}/routes/
|
|
463
|
-
items.ts # Handles /v1/x/items
|
|
464
|
-
items/
|
|
465
|
-
[id].ts # Not supported — use query params instead
|
|
466
|
-
index.ts # Also handles /v1/x/items (index convention)
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
**Example handler — JSON file persistence:**
|
|
470
|
-
|
|
471
|
-
```typescript
|
|
472
|
-
// routes/items.ts
|
|
473
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
474
|
-
import { join } from "node:path";
|
|
475
|
-
|
|
476
|
-
export const description = "Item CRUD — stores records as a JSON file";
|
|
477
|
-
|
|
478
|
-
const DATA_DIR = join(process.env.VELLUM_WORKSPACE_DIR!, "data");
|
|
479
|
-
const DATA_FILE = join(DATA_DIR, "items.json");
|
|
480
|
-
|
|
481
|
-
function loadItems(): Array<Record<string, unknown>> {
|
|
482
|
-
mkdirSync(DATA_DIR, { recursive: true });
|
|
483
|
-
if (!existsSync(DATA_FILE)) return [];
|
|
484
|
-
return JSON.parse(readFileSync(DATA_FILE, "utf-8"));
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function saveItems(items: Array<Record<string, unknown>>): void {
|
|
488
|
-
mkdirSync(DATA_DIR, { recursive: true });
|
|
489
|
-
writeFileSync(DATA_FILE, JSON.stringify(items, null, 2));
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
export function GET(): Response {
|
|
493
|
-
return Response.json(loadItems());
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
export async function POST(request: Request): Promise<Response> {
|
|
497
|
-
const body = await request.json();
|
|
498
|
-
const items = loadItems();
|
|
499
|
-
const item = { id: crypto.randomUUID(), ...body, createdAt: new Date().toISOString() };
|
|
500
|
-
items.push(item);
|
|
501
|
-
saveItems(items);
|
|
502
|
-
return Response.json(item, { status: 201 });
|
|
503
|
-
}
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
**Calling routes from the app frontend:**
|
|
347
|
+
When the app needs server-side persistence, custom API logic, or workspace file access, use **user-defined routes**. Route handlers are TypeScript/JavaScript files in the workspace `routes/` directory, served under `/v1/x/`. Call them from the frontend via `window.vellum.fetch("/v1/x/...")`. **Never use raw `fetch()` for `/v1/x/` routes** — it will fail in the sandboxed origin.
|
|
507
348
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
```typescript
|
|
511
|
-
// In a TSX component or HTML script
|
|
512
|
-
const res = await fetch("/v1/x/items");
|
|
513
|
-
const items = await res.json();
|
|
514
|
-
|
|
515
|
-
// Create a new item
|
|
516
|
-
await fetch("/v1/x/items", {
|
|
517
|
-
method: "POST",
|
|
518
|
-
headers: { "Content-Type": "application/json" },
|
|
519
|
-
body: JSON.stringify({ name: "New item", status: "active" }),
|
|
520
|
-
});
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
**Key rules:**
|
|
524
|
-
|
|
525
|
-
- Always create the route handler files via `file_write` before calling `app_refresh`
|
|
526
|
-
- Export an optional `description` string for CLI discoverability (`assistant routes list`)
|
|
527
|
-
- Handlers have full Node.js API access — `fs`, `path`, `crypto`, etc.
|
|
528
|
-
- Handlers get a 30-second timeout per request
|
|
529
|
-
- Files are hot-reloaded on change (mtime-based cache)
|
|
530
|
-
- Use `.ts` (preferred) or `.js` extensions
|
|
531
|
-
- Route resolution: `routes/foo.ts` → `/v1/x/foo`, `routes/bar/index.ts` → `/v1/x/bar`
|
|
349
|
+
For handler conventions, examples, key rules, and frontend usage patterns, see **[Custom Route Handlers](references/CUSTOM_ROUTES.md)**.
|
|
532
350
|
|
|
533
351
|
#### Client-side state management
|
|
534
352
|
|
|
@@ -549,7 +367,8 @@ let allRecords = [];
|
|
|
549
367
|
|
|
550
368
|
async function loadRecords() {
|
|
551
369
|
try {
|
|
552
|
-
const res = await fetch("/v1/x/records");
|
|
370
|
+
const res = await window.vellum.fetch("/v1/x/records");
|
|
371
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
553
372
|
allRecords = await res.json();
|
|
554
373
|
render();
|
|
555
374
|
} catch (err) {
|
|
@@ -652,58 +471,16 @@ Slides are a different domain from apps. Skip app-specific patterns (contextual
|
|
|
652
471
|
|
|
653
472
|
## Error Handling
|
|
654
473
|
|
|
655
|
-
- All `fetch()` calls to custom routes must be wrapped in `try/catch` with user-friendly feedback.
|
|
474
|
+
- All `window.vellum.fetch()` calls to custom routes must be wrapped in `try/catch` with user-friendly feedback. Always check `res.ok` before parsing the response body.
|
|
656
475
|
- Never let a failed operation silently pass - always show a toast or inline error.
|
|
657
476
|
- If the page loads with no data, show a designed empty state (`.v-empty-state`).
|
|
658
477
|
- For forms, show validation errors inline next to the relevant field.
|
|
659
478
|
|
|
660
479
|
## App Interaction Hooks
|
|
661
480
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
### Reactive hooks
|
|
665
|
-
|
|
666
|
-
Reactive hooks trigger an assistant response. Use them for moments where the assistant's input adds value - selections that need explanation, completions worth celebrating, or submissions that benefit from feedback.
|
|
667
|
-
|
|
668
|
-
```javascript
|
|
669
|
-
// User selects a city on a map — assistant can provide insights
|
|
670
|
-
window.vellum.sendAction('city_selected', { city: 'Tokyo' });
|
|
671
|
-
|
|
672
|
-
// User submits a form — assistant can confirm and suggest next steps
|
|
673
|
-
window.vellum.sendAction('form_submitted', { formId: 'signup', email: 'user@example.com' });
|
|
674
|
-
|
|
675
|
-
// User completes a level — assistant can congratulate and hint at what's next
|
|
676
|
-
window.vellum.sendAction('level_complete', { level: 5, score: 2400 });
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
### Silent hooks
|
|
680
|
-
|
|
681
|
-
Silent hooks accumulate state without interrupting the user. The state is automatically included as context when the next reactive hook fires.
|
|
682
|
-
|
|
683
|
-
```javascript
|
|
684
|
-
// User navigates to a new tab — no response needed, but assistant should know
|
|
685
|
-
window.vellum.sendAction('state_update', { currentView: 'forecast', city: 'Tokyo' });
|
|
686
|
-
|
|
687
|
-
// Score changes during gameplay — track silently
|
|
688
|
-
window.vellum.sendAction('state_update', { score: 1250, lives: 2 });
|
|
689
|
-
|
|
690
|
-
// User applies a filter — context for future questions
|
|
691
|
-
window.vellum.sendAction('state_update', { filter: 'last-30-days', sortBy: 'revenue' });
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
### When to use reactive vs silent
|
|
695
|
-
|
|
696
|
-
Choose based on whether the assistant's response would genuinely help the user at that moment:
|
|
697
|
-
|
|
698
|
-
| App type | Silent (state accumulation) | Reactive (triggers response) |
|
|
699
|
-
|---|---|---|
|
|
700
|
-
| **Dashboards** | Tab navigation, filter changes, date range selection | Anomaly detected, threshold breached, data export complete |
|
|
701
|
-
| **Games** | Score updates, move tracking, timer ticks | Level complete, achievement unlocked, game over |
|
|
702
|
-
| **Forms & wizards** | Field focus, partial input, step navigation | Form submitted, validation failed on submit |
|
|
703
|
-
| **Trackers** | Incremental progress, status toggles, reordering | Milestone reached, streak achieved, all items complete |
|
|
704
|
-
| **Data explorers** | Sorting, paging, column toggling | Row selected for detail, comparison initiated |
|
|
481
|
+
Proactively wire `window.vellum.sendAction()` hooks so the assistant stays aware of meaningful user interactions. Two patterns: **reactive** hooks (trigger assistant response) and **silent** hooks (`state_update` — accumulate context without interrupting). Wire hooks during the initial build, don't wait for the user to ask.
|
|
705
482
|
|
|
706
|
-
|
|
483
|
+
For examples, reactive vs silent guidance, and per-app-type recommendations, see **[App Interaction Hooks](references/INTERACTION_HOOKS.md)**.
|
|
707
484
|
|
|
708
485
|
## Actionable UI
|
|
709
486
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Custom Route Handlers (User-Defined Routes)
|
|
2
|
+
|
|
3
|
+
When the app needs server-side persistence, custom API logic, or workspace file access, use **user-defined routes**. Route handlers are TypeScript or JavaScript files that live in the workspace `routes/` directory and are served under the `/v1/x/` URL path.
|
|
4
|
+
|
|
5
|
+
**Common use cases:** CRUD storage, file-based persistence, search/aggregation, external API proxying, webhook receivers.
|
|
6
|
+
|
|
7
|
+
## Handler file convention
|
|
8
|
+
|
|
9
|
+
Each handler file exports named functions for the HTTP methods it supports (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`). Handlers use the standard Web API `Request`/`Response` signature.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{workspaceDir}/routes/
|
|
13
|
+
items.ts # Handles /v1/x/items
|
|
14
|
+
items/
|
|
15
|
+
[id].ts # Not supported — use query params instead
|
|
16
|
+
index.ts # Also handles /v1/x/items (index convention)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Example handler — JSON file persistence
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// routes/items.ts
|
|
23
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
|
|
26
|
+
export const description = "Item CRUD — stores records as a JSON file";
|
|
27
|
+
|
|
28
|
+
const DATA_DIR = join(process.env.VELLUM_WORKSPACE_DIR!, "data");
|
|
29
|
+
const DATA_FILE = join(DATA_DIR, "items.json");
|
|
30
|
+
|
|
31
|
+
function loadItems(): Array<Record<string, unknown>> {
|
|
32
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
33
|
+
if (!existsSync(DATA_FILE)) return [];
|
|
34
|
+
return JSON.parse(readFileSync(DATA_FILE, "utf-8"));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function saveItems(items: Array<Record<string, unknown>>): void {
|
|
38
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
39
|
+
writeFileSync(DATA_FILE, JSON.stringify(items, null, 2));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function GET(): Response {
|
|
43
|
+
return Response.json(loadItems());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function POST(request: Request): Promise<Response> {
|
|
47
|
+
const body = await request.json();
|
|
48
|
+
const items = loadItems();
|
|
49
|
+
const item = {
|
|
50
|
+
id: crypto.randomUUID(),
|
|
51
|
+
...body,
|
|
52
|
+
createdAt: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
items.push(item);
|
|
55
|
+
saveItems(items);
|
|
56
|
+
return Response.json(item, { status: 201 });
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Calling routes from the app frontend
|
|
61
|
+
|
|
62
|
+
Apps call custom routes via `window.vellum.fetch()` using the `/v1/x/` prefix. This authenticated wrapper automatically injects the gateway URL and auth headers so requests reach the assistant runtime. **Never use raw `fetch()` for `/v1/x/` routes** — it will fail because the app runs in a sandboxed origin.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// In a TSX component or HTML script
|
|
66
|
+
const res = await window.vellum.fetch("/v1/x/items");
|
|
67
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
68
|
+
const items = await res.json();
|
|
69
|
+
|
|
70
|
+
// Create a new item
|
|
71
|
+
const createRes = await window.vellum.fetch("/v1/x/items", {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
74
|
+
body: JSON.stringify({ name: "New item", status: "active" }),
|
|
75
|
+
});
|
|
76
|
+
if (!createRes.ok) throw new Error(`HTTP ${createRes.status}`);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Key rules
|
|
80
|
+
|
|
81
|
+
- Always create the route handler files via `file_write` before calling `app_refresh`
|
|
82
|
+
- Export an optional `description` string for CLI discoverability (`assistant routes list`)
|
|
83
|
+
- Handlers have full Node.js API access — `fs`, `path`, `crypto`, etc.
|
|
84
|
+
- Handlers get a 30-second timeout per request
|
|
85
|
+
- Files are hot-reloaded on change (mtime-based cache)
|
|
86
|
+
- Use `.ts` (preferred) or `.js` extensions
|
|
87
|
+
- Route resolution: `routes/foo.ts` → `/v1/x/foo`, `routes/bar/index.ts` → `/v1/x/bar`
|
|
88
|
+
|
|
89
|
+
## Using custom routes in TSX components
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
window.vellum
|
|
96
|
+
.fetch("/v1/x/items")
|
|
97
|
+
.then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
|
|
98
|
+
.then(setItems)
|
|
99
|
+
.catch(console.error);
|
|
100
|
+
}, []);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Error handling
|
|
104
|
+
|
|
105
|
+
All `window.vellum.fetch()` calls to custom routes must be wrapped in `try/catch` with user-friendly feedback. Always check `res.ok` before parsing the response body. Never let a failed operation silently pass — always show a toast or inline error.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# App Interaction Hooks
|
|
2
|
+
|
|
3
|
+
When building apps, proactively wire `sendAction` hooks so the assistant stays aware of meaningful user interactions. Two patterns are available:
|
|
4
|
+
|
|
5
|
+
## Reactive hooks
|
|
6
|
+
|
|
7
|
+
Reactive hooks trigger an assistant response. Use them for moments where the assistant's input adds value - selections that need explanation, completions worth celebrating, or submissions that benefit from feedback.
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// User selects a city on a map — assistant can provide insights
|
|
11
|
+
window.vellum.sendAction("city_selected", { city: "Tokyo" });
|
|
12
|
+
|
|
13
|
+
// User submits a form — assistant can confirm and suggest next steps
|
|
14
|
+
window.vellum.sendAction("form_submitted", {
|
|
15
|
+
formId: "signup",
|
|
16
|
+
email: "user@example.com",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// User completes a level — assistant can congratulate and hint at what's next
|
|
20
|
+
window.vellum.sendAction("level_complete", { level: 5, score: 2400 });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Silent hooks
|
|
24
|
+
|
|
25
|
+
Silent hooks accumulate state without interrupting the user. The state is automatically included as context when the next reactive hook fires.
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// User navigates to a new tab — no response needed, but assistant should know
|
|
29
|
+
window.vellum.sendAction("state_update", {
|
|
30
|
+
currentView: "forecast",
|
|
31
|
+
city: "Tokyo",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Score changes during gameplay — track silently
|
|
35
|
+
window.vellum.sendAction("state_update", { score: 1250, lives: 2 });
|
|
36
|
+
|
|
37
|
+
// User applies a filter — context for future questions
|
|
38
|
+
window.vellum.sendAction("state_update", {
|
|
39
|
+
filter: "last-30-days",
|
|
40
|
+
sortBy: "revenue",
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## When to use reactive vs silent
|
|
45
|
+
|
|
46
|
+
Choose based on whether the assistant's response would genuinely help the user at that moment:
|
|
47
|
+
|
|
48
|
+
| App type | Silent (state accumulation) | Reactive (triggers response) |
|
|
49
|
+
| ------------------- | ---------------------------------------------------- | ---------------------------------------------------------- |
|
|
50
|
+
| **Dashboards** | Tab navigation, filter changes, date range selection | Anomaly detected, threshold breached, data export complete |
|
|
51
|
+
| **Games** | Score updates, move tracking, timer ticks | Level complete, achievement unlocked, game over |
|
|
52
|
+
| **Forms & wizards** | Field focus, partial input, step navigation | Form submitted, validation failed on submit |
|
|
53
|
+
| **Trackers** | Incremental progress, status toggles, reordering | Milestone reached, streak achieved, all items complete |
|
|
54
|
+
| **Data explorers** | Sorting, paging, column toggling | Row selected for detail, comparison initiated |
|
|
55
|
+
|
|
56
|
+
Wire hooks during the initial build - don't wait for the user to ask. Apps that communicate state back to the assistant feel alive; apps that don't feel like static pages.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Widget Component Library
|
|
2
|
+
|
|
3
|
+
A CSS/JS widget library is auto-injected alongside the design system. Use these for standard UI patterns - skip them when custom HTML serves the user better.
|
|
4
|
+
|
|
5
|
+
## Layout widgets
|
|
6
|
+
|
|
7
|
+
| Widget | Purpose |
|
|
8
|
+
| ------------------------------------------------------------ | -------------------------------------------------------------- |
|
|
9
|
+
| `.v-metric-card` (`.v-metric-grid`) | Big number with emoji icon, label, trend |
|
|
10
|
+
| `.v-data-table` | Sortable table with sticky header, `th[data-sortable]` |
|
|
11
|
+
| `.v-tabs` / `.v-tab-bar` / `.v-tab-panel` | Tab navigation with keyboard support |
|
|
12
|
+
| `.v-accordion` / `.v-accordion-item` | Collapsible sections |
|
|
13
|
+
| `.v-search-bar` | Search input with clear button |
|
|
14
|
+
| `.v-empty-state` | No-data placeholder with CTA |
|
|
15
|
+
| `.v-timeline` / `.v-timeline-entry` | Vertical timeline (`.active`/`.success`/`.error`) |
|
|
16
|
+
| `.v-action-list` / `.v-action-list-item` | Rows with per-item actions |
|
|
17
|
+
| `.v-card-grid` | Responsive card grid |
|
|
18
|
+
| `.v-progress-bar` / `.v-progress-track` / `.v-progress-fill` | Horizontal progress |
|
|
19
|
+
| `.v-status-badge` | Colored pill with dot (`.success`/`.error`/`.warning`/`.info`) |
|
|
20
|
+
| `.v-stat-row` / `.v-stat` | Horizontal label-value pairs |
|
|
21
|
+
| `.v-toast` | Notification banner - prefer `vellum.widgets.toast()` |
|
|
22
|
+
| `.v-avatar-row` | Contact/team display |
|
|
23
|
+
| `.v-tag-group` | Wrapping tag row |
|
|
24
|
+
|
|
25
|
+
## Domain-specific widgets
|
|
26
|
+
|
|
27
|
+
| Widget | Purpose |
|
|
28
|
+
| ------------------ | ---------------------- |
|
|
29
|
+
| `.v-weather-card` | Temperature + forecast |
|
|
30
|
+
| `.v-stock-ticker` | Price display + chart |
|
|
31
|
+
| `.v-flight-card` | Flight info with route |
|
|
32
|
+
| `.v-billing-chart` | Usage/billing display |
|
|
33
|
+
| `.v-boarding-pass` | Pass-styled layout |
|
|
34
|
+
| `.v-itinerary` | Day-by-day travel plan |
|
|
35
|
+
| `.v-receipt` | Receipt layout |
|
|
36
|
+
| `.v-invoice` | Formal invoice |
|
|
37
|
+
|
|
38
|
+
## Content & landing page components
|
|
39
|
+
|
|
40
|
+
| Widget | Purpose |
|
|
41
|
+
| ------------------------------------------------ | --------------------------------------------------- |
|
|
42
|
+
| `.v-hero` / `.v-hero-badge` / `.v-hero-subtitle` | Hero banner with gradient, trust badge, accent word |
|
|
43
|
+
| `.v-section-header` / `.v-section-label` | Section intro with label |
|
|
44
|
+
| `.v-feature-grid` / `.v-feature-card` | Feature showcase with hover lift |
|
|
45
|
+
| `.v-pullquote` | Blockquote with gradient accent border |
|
|
46
|
+
| `.v-comparison` | Before/after cards (`.before`/`.after`) |
|
|
47
|
+
| `.v-page` | Centered container (max-width 600px) |
|
|
48
|
+
| `.v-gradient-text` | Accent-colored gradient text |
|
|
49
|
+
| `.v-animate-in` | Staggered fade-in for children |
|
|
50
|
+
|
|
51
|
+
## Widget JavaScript utilities
|
|
52
|
+
|
|
53
|
+
Interactive utilities at `window.vellum.widgets.*`:
|
|
54
|
+
|
|
55
|
+
### Charts
|
|
56
|
+
|
|
57
|
+
Always use these instead of hand-coding SVG/CSS charts:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
vellum.widgets.sparkline("container-id", [10, 25, 15, 30], {
|
|
61
|
+
width: 200,
|
|
62
|
+
height: 40,
|
|
63
|
+
color: "var(--v-success)",
|
|
64
|
+
strokeWidth: 2,
|
|
65
|
+
fill: true,
|
|
66
|
+
});
|
|
67
|
+
vellum.widgets.barChart(
|
|
68
|
+
"container-id",
|
|
69
|
+
[
|
|
70
|
+
{ label: "Jan", value: 120 },
|
|
71
|
+
{ label: "Feb", value: 180, color: "var(--v-success)" },
|
|
72
|
+
],
|
|
73
|
+
{
|
|
74
|
+
width: 400,
|
|
75
|
+
height: 200,
|
|
76
|
+
showLabels: true,
|
|
77
|
+
showValues: true,
|
|
78
|
+
horizontal: false,
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
vellum.widgets.lineChart(
|
|
82
|
+
"container-id",
|
|
83
|
+
[
|
|
84
|
+
{ label: "Mon", value: 42 },
|
|
85
|
+
{ label: "Tue", value: 58 },
|
|
86
|
+
],
|
|
87
|
+
{ width: 400, height: 200, showDots: true, showGrid: true, gridLines: 4 },
|
|
88
|
+
);
|
|
89
|
+
vellum.widgets.progressRing("container-id", 75, {
|
|
90
|
+
size: 100,
|
|
91
|
+
strokeWidth: 8,
|
|
92
|
+
color: "var(--v-success)",
|
|
93
|
+
label: "75%",
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Data Formatting
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
vellum.widgets.formatCurrency(1234.56, "USD"); // "$1,234.56"
|
|
101
|
+
vellum.widgets.formatDate("2025-01-15", "relative"); // "3d ago"
|
|
102
|
+
vellum.widgets.formatDate("2025-01-15", "short"); // "1/15/25"
|
|
103
|
+
vellum.widgets.formatNumber(1234567, { compact: true }); // "1.2M"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Interactive Behaviors
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
vellum.widgets.sortTable("table-id"); // Wire th[data-sortable] click-to-sort
|
|
110
|
+
vellum.widgets.filterTable("table-id", "input-id"); // Live text search
|
|
111
|
+
vellum.widgets.tabs("tabs-id"); // Tab switching + keyboard nav
|
|
112
|
+
vellum.widgets.accordion("accordion-id", { allowMultiple: true });
|
|
113
|
+
vellum.widgets.multiSelect("table-id"); // Checkboxes + select-all
|
|
114
|
+
vellum.widgets.toast("Saved!", "success", 4000); // Auto-dismiss notification
|
|
115
|
+
vellum.widgets.countdown("timer-el", "2025-12-31T00:00:00Z", {
|
|
116
|
+
onComplete: () => {},
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## When to use widgets vs custom HTML
|
|
121
|
+
|
|
122
|
+
- **Use widgets** for standard patterns - tables, metrics, timelines, notifications
|
|
123
|
+
- **Use custom HTML** for novel or creative UIs - games, art tools, unique dashboards
|
|
124
|
+
- **Mix freely** - widgets compose well together and with custom elements
|
|
125
|
+
- **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
|
|
@@ -6,6 +6,9 @@ metadata:
|
|
|
6
6
|
emoji: "👥"
|
|
7
7
|
vellum:
|
|
8
8
|
display-name: "Contacts"
|
|
9
|
+
activation-hints:
|
|
10
|
+
- "Look up contact info before asking the user for email addresses or phone numbers"
|
|
11
|
+
- "User wants to manage who can message the assistant, or create/revoke invite links"
|
|
9
12
|
---
|
|
10
13
|
|
|
11
14
|
Manage the user's contacts, relationship graph, access control (trusted contacts), and invite links. This skill covers contact CRUD with multi-channel tracking, controlling who can message the assistant through external channels (Telegram, phone), and creating/managing invite links that grant access.
|
|
@@ -6,6 +6,10 @@ metadata:
|
|
|
6
6
|
emoji: "📄"
|
|
7
7
|
vellum:
|
|
8
8
|
display-name: "Document"
|
|
9
|
+
activation-hints:
|
|
10
|
+
- "User asks to write, draft, or collaborate on long-form content — use the document editor for a better editing experience"
|
|
11
|
+
- "When content will be iterated on, reviewed, or exported, prefer the document editor over inline markdown"
|
|
12
|
+
- "When a file attachment contains a draft or document the user wants to iterate on, open it in the editor"
|
|
9
13
|
---
|
|
10
14
|
|
|
11
15
|
Create and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side.
|
|
@@ -161,7 +161,7 @@ Scan tools (`gmail_sender_digest`, `gmail_outreach_scan`) return a `scan_id` tha
|
|
|
161
161
|
|
|
162
162
|
Before composing any email that references a date or time:
|
|
163
163
|
|
|
164
|
-
1. Check the `
|
|
164
|
+
1. Check the `current_time:` field in the `<turn_context>` block for today's date and timezone
|
|
165
165
|
2. Verify that "tomorrow" means the day after today's date, "next week" means the upcoming Monday–Friday, etc.
|
|
166
166
|
3. If the email references a date from another message, cross-check it against the turn context to ensure it's in the future
|
|
167
167
|
|