@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# Example — Habit Tracker
|
|
2
|
+
|
|
3
|
+
A 7-day habit grid: add habits, toggle a checkmark per day, delete habits. This is the
|
|
4
|
+
canonical **CRUD over a custom route** example — full create / read / update / delete
|
|
5
|
+
backed by a JSON file on disk, called from a multi-file TSX (`formatVersion: 2`) app via
|
|
6
|
+
`window.vellum.fetch`.
|
|
7
|
+
|
|
8
|
+
**What it demonstrates**
|
|
9
|
+
|
|
10
|
+
- A `routes/habits.ts` handler exporting `GET` / `POST` / `PATCH` / `DELETE`.
|
|
11
|
+
- Mutations addressed by `id` via a **query param** (`/v1/x/habits?id=…`) — route files
|
|
12
|
+
cannot use `[id].ts` path segments (see [CUSTOM_ROUTES.md](../CUSTOM_ROUTES.md)).
|
|
13
|
+
- A frontend that always checks `res.ok`, surfaces errors, and re-reads after every write
|
|
14
|
+
so the UI reflects persisted state rather than optimistic guesses.
|
|
15
|
+
|
|
16
|
+
## File tree
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/index.html
|
|
20
|
+
src/main.tsx
|
|
21
|
+
src/components/HabitTracker.tsx
|
|
22
|
+
src/components/HabitRow.tsx
|
|
23
|
+
src/styles.css
|
|
24
|
+
routes/habits.ts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Route handler
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// routes/habits.ts — Habit CRUD, persisted as a JSON file in the app workspace.
|
|
31
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
32
|
+
import { join } from "node:path";
|
|
33
|
+
|
|
34
|
+
export const description = "Habit CRUD — stores habits as a JSON file";
|
|
35
|
+
|
|
36
|
+
interface Habit {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
completedDates: string[];
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const DATA_DIR = join(process.env.VELLUM_WORKSPACE_DIR!, "data");
|
|
44
|
+
const DATA_FILE = join(DATA_DIR, "habits.json");
|
|
45
|
+
|
|
46
|
+
function loadHabits(): Habit[] {
|
|
47
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
48
|
+
if (!existsSync(DATA_FILE)) return [];
|
|
49
|
+
return JSON.parse(readFileSync(DATA_FILE, "utf-8")) as Habit[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function saveHabits(habits: Habit[]): void {
|
|
53
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
54
|
+
writeFileSync(DATA_FILE, JSON.stringify(habits, null, 2));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function GET(): Response {
|
|
58
|
+
return Response.json(loadHabits());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function POST(request: Request): Promise<Response> {
|
|
62
|
+
const body = (await request.json()) as { name?: unknown };
|
|
63
|
+
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
64
|
+
if (!name)
|
|
65
|
+
return Response.json({ error: "name is required" }, { status: 400 });
|
|
66
|
+
|
|
67
|
+
const habit: Habit = {
|
|
68
|
+
id: crypto.randomUUID(),
|
|
69
|
+
name,
|
|
70
|
+
completedDates: [],
|
|
71
|
+
createdAt: new Date().toISOString(),
|
|
72
|
+
};
|
|
73
|
+
const habits = loadHabits();
|
|
74
|
+
habits.push(habit);
|
|
75
|
+
saveHabits(habits);
|
|
76
|
+
return Response.json(habit, { status: 201 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function PATCH(request: Request): Promise<Response> {
|
|
80
|
+
const id = new URL(request.url).searchParams.get("id");
|
|
81
|
+
if (!id) return Response.json({ error: "id is required" }, { status: 400 });
|
|
82
|
+
|
|
83
|
+
const body = (await request.json()) as { completedDates?: unknown };
|
|
84
|
+
if (!Array.isArray(body.completedDates)) {
|
|
85
|
+
return Response.json(
|
|
86
|
+
{ error: "completedDates must be an array" },
|
|
87
|
+
{ status: 400 },
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const habits = loadHabits();
|
|
92
|
+
const habit = habits.find((h) => h.id === id);
|
|
93
|
+
if (!habit) return Response.json({ error: "not found" }, { status: 404 });
|
|
94
|
+
|
|
95
|
+
habit.completedDates = body.completedDates.filter(
|
|
96
|
+
(d): d is string => typeof d === "string",
|
|
97
|
+
);
|
|
98
|
+
saveHabits(habits);
|
|
99
|
+
return Response.json(habit);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function DELETE(request: Request): Response {
|
|
103
|
+
const id = new URL(request.url).searchParams.get("id");
|
|
104
|
+
if (!id) return Response.json({ error: "id is required" }, { status: 400 });
|
|
105
|
+
|
|
106
|
+
const habits = loadHabits();
|
|
107
|
+
const next = habits.filter((h) => h.id !== id);
|
|
108
|
+
if (next.length === habits.length) {
|
|
109
|
+
return Response.json({ error: "not found" }, { status: 404 });
|
|
110
|
+
}
|
|
111
|
+
saveHabits(next);
|
|
112
|
+
return Response.json({ ok: true });
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Frontend
|
|
117
|
+
|
|
118
|
+
```html
|
|
119
|
+
<!-- src/index.html -->
|
|
120
|
+
<!DOCTYPE html>
|
|
121
|
+
<html lang="en">
|
|
122
|
+
<head>
|
|
123
|
+
<meta charset="UTF-8" />
|
|
124
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
125
|
+
<title>Habit Tracker</title>
|
|
126
|
+
</head>
|
|
127
|
+
<body>
|
|
128
|
+
<div id="app"></div>
|
|
129
|
+
</body>
|
|
130
|
+
</html>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
// src/main.tsx
|
|
135
|
+
import { render } from "preact";
|
|
136
|
+
import { HabitTracker } from "./components/HabitTracker.js";
|
|
137
|
+
import "./styles.css";
|
|
138
|
+
|
|
139
|
+
render(<HabitTracker />, document.getElementById("app")!);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// src/components/HabitTracker.tsx
|
|
144
|
+
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
145
|
+
import { HabitRow } from "./HabitRow.js";
|
|
146
|
+
|
|
147
|
+
interface Habit {
|
|
148
|
+
id: string;
|
|
149
|
+
name: string;
|
|
150
|
+
completedDates: string[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getDates(): string[] {
|
|
154
|
+
const dates: string[] = [];
|
|
155
|
+
for (let i = 6; i >= 0; i--) {
|
|
156
|
+
const d = new Date();
|
|
157
|
+
d.setDate(d.getDate() - i);
|
|
158
|
+
dates.push(d.toISOString().slice(0, 10));
|
|
159
|
+
}
|
|
160
|
+
return dates;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getDayNames(dates: string[]): string[] {
|
|
164
|
+
const names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
165
|
+
return dates.map((d) => names[new Date(d + "T12:00:00").getDay()]);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function HabitTracker() {
|
|
169
|
+
const [habits, setHabits] = useState<Habit[]>([]);
|
|
170
|
+
const [input, setInput] = useState("");
|
|
171
|
+
const [error, setError] = useState<string | null>(null);
|
|
172
|
+
const dates = getDates();
|
|
173
|
+
const dayNames = getDayNames(dates);
|
|
174
|
+
|
|
175
|
+
const loadHabits = useCallback(async () => {
|
|
176
|
+
try {
|
|
177
|
+
const res = await window.vellum.fetch("/v1/x/habits");
|
|
178
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
179
|
+
setHabits(await res.json());
|
|
180
|
+
setError(null);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
setError("Couldn't load habits. Try again.");
|
|
183
|
+
console.error(e);
|
|
184
|
+
}
|
|
185
|
+
}, []);
|
|
186
|
+
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
loadHabits();
|
|
189
|
+
}, [loadHabits]);
|
|
190
|
+
|
|
191
|
+
const addHabit = async () => {
|
|
192
|
+
const name = input.trim();
|
|
193
|
+
if (!name) return;
|
|
194
|
+
setInput("");
|
|
195
|
+
try {
|
|
196
|
+
const res = await window.vellum.fetch("/v1/x/habits", {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: { "Content-Type": "application/json" },
|
|
199
|
+
body: JSON.stringify({ name }),
|
|
200
|
+
});
|
|
201
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
202
|
+
await loadHabits();
|
|
203
|
+
} catch (e) {
|
|
204
|
+
setError("Couldn't add habit. Try again.");
|
|
205
|
+
console.error(e);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const toggleDate = async (id: string, date: string) => {
|
|
210
|
+
const habit = habits.find((h) => h.id === id);
|
|
211
|
+
if (!habit) return;
|
|
212
|
+
const completed = habit.completedDates.includes(date)
|
|
213
|
+
? habit.completedDates.filter((d) => d !== date)
|
|
214
|
+
: [...habit.completedDates, date];
|
|
215
|
+
try {
|
|
216
|
+
const res = await window.vellum.fetch(`/v1/x/habits?id=${id}`, {
|
|
217
|
+
method: "PATCH",
|
|
218
|
+
headers: { "Content-Type": "application/json" },
|
|
219
|
+
body: JSON.stringify({ completedDates: completed }),
|
|
220
|
+
});
|
|
221
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
222
|
+
await loadHabits();
|
|
223
|
+
} catch (e) {
|
|
224
|
+
setError("Couldn't update habit. Try again.");
|
|
225
|
+
console.error(e);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const deleteHabit = async (id: string) => {
|
|
230
|
+
try {
|
|
231
|
+
const res = await window.vellum.fetch(`/v1/x/habits?id=${id}`, {
|
|
232
|
+
method: "DELETE",
|
|
233
|
+
});
|
|
234
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
235
|
+
await loadHabits();
|
|
236
|
+
} catch (e) {
|
|
237
|
+
setError("Couldn't delete habit. Try again.");
|
|
238
|
+
console.error(e);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div>
|
|
244
|
+
<div class="header">
|
|
245
|
+
<h1>Habit Tracker</h1>
|
|
246
|
+
</div>
|
|
247
|
+
{error && <div class="error-banner">{error}</div>}
|
|
248
|
+
<div class="add-form">
|
|
249
|
+
<input
|
|
250
|
+
type="text"
|
|
251
|
+
value={input}
|
|
252
|
+
onInput={(e) => setInput((e.target as HTMLInputElement).value)}
|
|
253
|
+
onKeyDown={(e) => e.key === "Enter" && addHabit()}
|
|
254
|
+
placeholder="Add a new habit..."
|
|
255
|
+
/>
|
|
256
|
+
<button class="btn-primary" onClick={addHabit}>
|
|
257
|
+
Add
|
|
258
|
+
</button>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="days-header">
|
|
261
|
+
<div />
|
|
262
|
+
{dayNames.map((name, i) => (
|
|
263
|
+
<div key={i} class="day-label">
|
|
264
|
+
{name}
|
|
265
|
+
</div>
|
|
266
|
+
))}
|
|
267
|
+
</div>
|
|
268
|
+
<div>
|
|
269
|
+
{habits.length === 0 ? (
|
|
270
|
+
<div class="empty-state">No habits yet. Add one above!</div>
|
|
271
|
+
) : (
|
|
272
|
+
habits.map((habit) => (
|
|
273
|
+
<HabitRow
|
|
274
|
+
key={habit.id}
|
|
275
|
+
habit={habit}
|
|
276
|
+
dates={dates}
|
|
277
|
+
onToggle={toggleDate}
|
|
278
|
+
onDelete={deleteHabit}
|
|
279
|
+
/>
|
|
280
|
+
))
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
// src/components/HabitRow.tsx
|
|
290
|
+
interface Habit {
|
|
291
|
+
id: string;
|
|
292
|
+
name: string;
|
|
293
|
+
completedDates: string[];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
interface HabitRowProps {
|
|
297
|
+
habit: Habit;
|
|
298
|
+
dates: string[];
|
|
299
|
+
onToggle: (id: string, date: string) => void;
|
|
300
|
+
onDelete: (id: string) => void;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function HabitRow({ habit, dates, onToggle, onDelete }: HabitRowProps) {
|
|
304
|
+
return (
|
|
305
|
+
<div class="habit-row">
|
|
306
|
+
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
|
307
|
+
<span class="habit-name">{habit.name}</span>
|
|
308
|
+
<button class="delete-btn" onClick={() => onDelete(habit.id)}>
|
|
309
|
+
x
|
|
310
|
+
</button>
|
|
311
|
+
</div>
|
|
312
|
+
{dates.map((date) => {
|
|
313
|
+
const checked = habit.completedDates.includes(date);
|
|
314
|
+
return (
|
|
315
|
+
<div key={date} class="check-cell">
|
|
316
|
+
<button
|
|
317
|
+
class={`check-btn${checked ? " checked" : ""}`}
|
|
318
|
+
onClick={() => onToggle(habit.id, date)}
|
|
319
|
+
>
|
|
320
|
+
{checked ? "\u2713" : ""}
|
|
321
|
+
</button>
|
|
322
|
+
</div>
|
|
323
|
+
);
|
|
324
|
+
})}
|
|
325
|
+
</div>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
```css
|
|
331
|
+
/* src/styles.css */
|
|
332
|
+
:root {
|
|
333
|
+
--bg: #0f172a;
|
|
334
|
+
--surface: #1e293b;
|
|
335
|
+
--primary: #6366f1;
|
|
336
|
+
--primary-hover: #5558e6;
|
|
337
|
+
--success: #22c55e;
|
|
338
|
+
--text: #f1f5f9;
|
|
339
|
+
--text-secondary: #94a3b8;
|
|
340
|
+
--border: #334155;
|
|
341
|
+
--radius: 10px;
|
|
342
|
+
}
|
|
343
|
+
* {
|
|
344
|
+
margin: 0;
|
|
345
|
+
padding: 0;
|
|
346
|
+
box-sizing: border-box;
|
|
347
|
+
}
|
|
348
|
+
body {
|
|
349
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
|
|
350
|
+
background: var(--bg);
|
|
351
|
+
color: var(--text);
|
|
352
|
+
padding: 24px;
|
|
353
|
+
min-height: 100vh;
|
|
354
|
+
}
|
|
355
|
+
.header {
|
|
356
|
+
display: flex;
|
|
357
|
+
justify-content: space-between;
|
|
358
|
+
align-items: center;
|
|
359
|
+
margin-bottom: 24px;
|
|
360
|
+
}
|
|
361
|
+
h1 {
|
|
362
|
+
font-size: 1.4rem;
|
|
363
|
+
font-weight: 600;
|
|
364
|
+
}
|
|
365
|
+
.error-banner {
|
|
366
|
+
background: rgba(239, 68, 68, 0.12);
|
|
367
|
+
color: #fca5a5;
|
|
368
|
+
padding: 10px 14px;
|
|
369
|
+
border-radius: var(--radius);
|
|
370
|
+
margin-bottom: 16px;
|
|
371
|
+
font-size: 0.85rem;
|
|
372
|
+
}
|
|
373
|
+
.add-form {
|
|
374
|
+
display: flex;
|
|
375
|
+
gap: 8px;
|
|
376
|
+
margin-bottom: 24px;
|
|
377
|
+
}
|
|
378
|
+
.add-form input {
|
|
379
|
+
flex: 1;
|
|
380
|
+
padding: 10px 14px;
|
|
381
|
+
background: var(--surface);
|
|
382
|
+
border: 1px solid var(--border);
|
|
383
|
+
border-radius: var(--radius);
|
|
384
|
+
color: var(--text);
|
|
385
|
+
font-family: inherit;
|
|
386
|
+
font-size: 0.9rem;
|
|
387
|
+
outline: none;
|
|
388
|
+
}
|
|
389
|
+
.add-form input:focus {
|
|
390
|
+
border-color: var(--primary);
|
|
391
|
+
}
|
|
392
|
+
.add-form input::placeholder {
|
|
393
|
+
color: var(--text-secondary);
|
|
394
|
+
}
|
|
395
|
+
button {
|
|
396
|
+
font-family: inherit;
|
|
397
|
+
font-size: 0.85rem;
|
|
398
|
+
font-weight: 500;
|
|
399
|
+
padding: 10px 18px;
|
|
400
|
+
border: none;
|
|
401
|
+
border-radius: var(--radius);
|
|
402
|
+
cursor: pointer;
|
|
403
|
+
transition: background 0.2s;
|
|
404
|
+
}
|
|
405
|
+
.btn-primary {
|
|
406
|
+
background: var(--primary);
|
|
407
|
+
color: white;
|
|
408
|
+
}
|
|
409
|
+
.btn-primary:hover {
|
|
410
|
+
background: var(--primary-hover);
|
|
411
|
+
}
|
|
412
|
+
.days-header {
|
|
413
|
+
display: grid;
|
|
414
|
+
grid-template-columns: 1fr repeat(7, 40px);
|
|
415
|
+
gap: 4px;
|
|
416
|
+
margin-bottom: 8px;
|
|
417
|
+
padding: 0 4px;
|
|
418
|
+
}
|
|
419
|
+
.day-label {
|
|
420
|
+
text-align: center;
|
|
421
|
+
font-size: 0.7rem;
|
|
422
|
+
color: var(--text-secondary);
|
|
423
|
+
text-transform: uppercase;
|
|
424
|
+
}
|
|
425
|
+
.habit-row {
|
|
426
|
+
display: grid;
|
|
427
|
+
grid-template-columns: 1fr repeat(7, 40px);
|
|
428
|
+
gap: 4px;
|
|
429
|
+
padding: 10px 4px;
|
|
430
|
+
border-radius: var(--radius);
|
|
431
|
+
margin-bottom: 4px;
|
|
432
|
+
align-items: center;
|
|
433
|
+
}
|
|
434
|
+
.habit-row:hover {
|
|
435
|
+
background: var(--surface);
|
|
436
|
+
}
|
|
437
|
+
.habit-name {
|
|
438
|
+
font-size: 0.9rem;
|
|
439
|
+
font-weight: 500;
|
|
440
|
+
overflow: hidden;
|
|
441
|
+
text-overflow: ellipsis;
|
|
442
|
+
white-space: nowrap;
|
|
443
|
+
}
|
|
444
|
+
.check-cell {
|
|
445
|
+
display: flex;
|
|
446
|
+
justify-content: center;
|
|
447
|
+
align-items: center;
|
|
448
|
+
}
|
|
449
|
+
.check-btn {
|
|
450
|
+
width: 28px;
|
|
451
|
+
height: 28px;
|
|
452
|
+
border-radius: 6px;
|
|
453
|
+
border: 2px solid var(--border);
|
|
454
|
+
background: transparent;
|
|
455
|
+
cursor: pointer;
|
|
456
|
+
padding: 0;
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
justify-content: center;
|
|
460
|
+
transition: all 0.15s;
|
|
461
|
+
color: transparent;
|
|
462
|
+
font-size: 14px;
|
|
463
|
+
}
|
|
464
|
+
.check-btn.checked {
|
|
465
|
+
background: var(--success);
|
|
466
|
+
border-color: var(--success);
|
|
467
|
+
color: white;
|
|
468
|
+
}
|
|
469
|
+
.check-btn:hover {
|
|
470
|
+
border-color: var(--success);
|
|
471
|
+
}
|
|
472
|
+
.delete-btn {
|
|
473
|
+
background: transparent;
|
|
474
|
+
color: var(--text-secondary);
|
|
475
|
+
border: none;
|
|
476
|
+
padding: 4px 8px;
|
|
477
|
+
font-size: 0.8rem;
|
|
478
|
+
cursor: pointer;
|
|
479
|
+
border-radius: 4px;
|
|
480
|
+
}
|
|
481
|
+
.delete-btn:hover {
|
|
482
|
+
color: #ef4444;
|
|
483
|
+
background: rgba(239, 68, 68, 0.1);
|
|
484
|
+
}
|
|
485
|
+
.empty-state {
|
|
486
|
+
text-align: center;
|
|
487
|
+
padding: 48px 0;
|
|
488
|
+
color: var(--text-secondary);
|
|
489
|
+
}
|
|
490
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as appStore from "../../../../memory/app-store.js";
|
|
2
|
+
import type {
|
|
3
|
+
ToolContext,
|
|
4
|
+
ToolExecutionResult,
|
|
5
|
+
} from "../../../../tools/types.js";
|
|
6
|
+
|
|
7
|
+
interface AppListEntry {
|
|
8
|
+
app_id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
updated_at: number;
|
|
12
|
+
created_at: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function toEntry(app: appStore.AppDefinition): AppListEntry {
|
|
16
|
+
return {
|
|
17
|
+
app_id: app.id,
|
|
18
|
+
name: app.name,
|
|
19
|
+
...(app.description ? { description: app.description } : {}),
|
|
20
|
+
updated_at: app.updatedAt,
|
|
21
|
+
created_at: app.createdAt,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function run(
|
|
26
|
+
input: Record<string, unknown>,
|
|
27
|
+
_context: ToolContext,
|
|
28
|
+
): Promise<ToolExecutionResult> {
|
|
29
|
+
const apps = appStore.listApps();
|
|
30
|
+
const entries = apps.map(toEntry);
|
|
31
|
+
|
|
32
|
+
const query =
|
|
33
|
+
typeof input.query === "string" ? input.query.trim().toLowerCase() : "";
|
|
34
|
+
|
|
35
|
+
if (!query) {
|
|
36
|
+
return {
|
|
37
|
+
content: JSON.stringify({ count: entries.length, apps: entries }),
|
|
38
|
+
isError: false,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Resolve the app the user mentioned by name. Prefer an exact (case-insensitive)
|
|
43
|
+
// name match, then fall back to substring matches in either direction so
|
|
44
|
+
// "habit tracker" resolves "Habit Tracker" and "my budget" resolves "Budget".
|
|
45
|
+
const exact = entries.filter((e) => e.name.toLowerCase() === query);
|
|
46
|
+
const matches =
|
|
47
|
+
exact.length > 0
|
|
48
|
+
? exact
|
|
49
|
+
: entries.filter((e) => {
|
|
50
|
+
const name = e.name.toLowerCase();
|
|
51
|
+
return name.includes(query) || query.includes(name);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
content: JSON.stringify({
|
|
56
|
+
query: input.query,
|
|
57
|
+
match_count: matches.length,
|
|
58
|
+
matches,
|
|
59
|
+
}),
|
|
60
|
+
isError: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -1,44 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: document-editor
|
|
3
|
-
description:
|
|
3
|
+
description: Use whenever the user wants to write or draft an article, blog post, essay, report, or any long-form content. Creates the content in a rich text editor instead of dumping it in chat, so it can be streamed, reviewed, edited, and exported.
|
|
4
4
|
compatibility: "Designed for Vellum personal assistants"
|
|
5
5
|
metadata:
|
|
6
|
-
emoji: "
|
|
6
|
+
emoji: "✍️"
|
|
7
7
|
vellum:
|
|
8
|
-
display-name: "Document
|
|
8
|
+
display-name: "Document Writer"
|
|
9
9
|
activation-hints:
|
|
10
|
-
- "User asks to write, draft, or
|
|
11
|
-
- "
|
|
12
|
-
- "
|
|
10
|
+
- "User asks to write, draft, or compose an article, blog post, essay, report, story, or any long-form content — always create it in the document editor, not as a chat reply"
|
|
11
|
+
- "User wants written content they will iterate on, review, or export — use the editor instead of inline markdown"
|
|
12
|
+
- "A file attachment contains a draft or document the user wants to revise — open it in the editor"
|
|
13
|
+
avoid-when:
|
|
14
|
+
- "The user wants an interactive app, dashboard, calculator, game, or anything with state or data — use app-builder instead"
|
|
15
|
+
- "A one or two sentence answer is enough — just reply in chat"
|
|
13
16
|
---
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
Write and edit long-form documents using the built-in rich text editor. Documents open in workspace mode with chat docked to the side. When a request is about writing prose (an article, blog post, report, essay, story, or similar), create it here rather than writing it into the chat response.
|
|
16
19
|
|
|
17
20
|
## Tools
|
|
18
21
|
|
|
19
|
-
- **
|
|
20
|
-
- **document_create** - Opens a new document editor with an optional title and initial Markdown content. Returns a `surface_id` for subsequent updates.
|
|
22
|
+
- **document_create** - Opens a new document editor with an optional title and initial Markdown content. Returns a `surface_id` for subsequent updates. This is the entry point for any new piece of writing.
|
|
21
23
|
- **document_update** - Updates content in an open document editor by `surface_id`. Supports `replace` (overwrite) and `append` (add to end) modes.
|
|
22
24
|
- **document_read** - Reads the current content of a document by `surface_id` when it belongs to the current conversation, or when the current actor is the guardian/local user. Use to verify content before editing.
|
|
23
|
-
- **document_list** - Lists documents. Without `query`, lists the current conversation's documents. With `query`, searches by title; guardian/local users can search across conversations, while other actors are scoped to the current conversation.
|
|
24
25
|
- **document_find** - Searches a document for text or regex patterns. Returns matching lines with line numbers, match positions, and matched text.
|
|
25
26
|
- **document_replace_text** - Targeted find-and-replace within a document. Supports literal and regex patterns (with backreferences). Optionally limit the number of replacements.
|
|
27
|
+
- **document_list** - Lists documents. Without `query`, lists the current conversation's documents. With `query`, searches by title; guardian/local users can search across conversations, while other actors are scoped to the current conversation.
|
|
28
|
+
- **document_open** - Opens an existing document in the editor panel by `surface_id`. Use this when a document exists but isn't visible in the editor — for example after the user switches devices, refreshes the page, or when the editor panel was closed. Fetches the document from storage and sends it to the client.
|
|
26
29
|
- **document_delete** - Deletes a document by `surface_id`. Use to clean up unwanted documents.
|
|
27
30
|
|
|
28
|
-
## Retrieving existing documents
|
|
29
|
-
|
|
30
|
-
When the user asks to see, open, or pull up a document:
|
|
31
|
-
|
|
32
|
-
1. Check the `<active_documents>` block in your context — it lists all documents in this conversation with their `surface_id` and title.
|
|
33
|
-
2. If the document is NOT in `<active_documents>`, call `document_list` with a `query` matching the document title. For guardian/local users, this searches across previous conversations and sessions.
|
|
34
|
-
3. Once you have the `surface_id`, call `document_open` to open the editor panel. This both surfaces the editor on the client and returns the document content. If the user only needs the text (not the editor), use `document_read` instead.
|
|
35
|
-
|
|
36
|
-
**Never** search the filesystem, conversation history, or archives to find a document. Always use `document_list` with a `query`.
|
|
37
|
-
|
|
38
|
-
**If the user says they can't see a document you know exists** (e.g. after switching from macOS to web, or after a page refresh), call `document_open` with the `surface_id` to re-surface the editor panel on their current client.
|
|
39
|
-
|
|
40
31
|
## Creating a new document
|
|
41
32
|
|
|
33
|
+
This is the default path when the user asks you to write something.
|
|
34
|
+
|
|
42
35
|
1. **Create the document**: Call `document_create` with a title (inferred from the request). Call the tool immediately, not after conversational preamble. Capture the `surface_id` from the response — every subsequent `document_update` call must reference it.
|
|
43
36
|
2. **Write content in Markdown**: Use proper structure (`#` for titles, `##` for sections), **bold**, _italic_, code blocks, tables, lists, blockquotes as appropriate.
|
|
44
37
|
3. **CRITICAL - Stream content in chunks**: Call `document_update` MULTIPLE times, not just once. Break content into logical chunks (paragraphs, sections, or every 200-300 words). Call `document_update` with `mode: "append"` for EACH chunk separately. The user experiences real-time content appearing as you write.
|
|
@@ -59,6 +52,18 @@ When the user requests changes to a document:
|
|
|
59
52
|
- `document_find` + `document_replace_text` — **for everything else**. Fixing typos, renaming terms, swapping sections, reordering content, adjusting formatting, or any edit that touches only part of the document. This is the default choice for edits. It avoids rewriting the entire document and eliminates the risk of accidentally dropping content.
|
|
60
53
|
4. **Do NOT use `document_update` with `mode: "replace"` for targeted edits.** Rewriting the entire document to change a few words or rearrange sections is wasteful and error-prone.
|
|
61
54
|
|
|
55
|
+
## Retrieving existing documents
|
|
56
|
+
|
|
57
|
+
When the user asks to see, open, or pull up a document:
|
|
58
|
+
|
|
59
|
+
1. Check the `<active_documents>` block in your context — it lists all documents in this conversation with their `surface_id` and title.
|
|
60
|
+
2. If the document is NOT in `<active_documents>`, call `document_list` with a `query` matching the document title. For guardian/local users, this searches across previous conversations and sessions.
|
|
61
|
+
3. Once you have the `surface_id`, call `document_open` to open the editor panel. This surfaces the editor on the client and returns document metadata (`surface_id`, `title`, `word_count`) — not the full content. If you need the actual document text, follow up with `document_read`.
|
|
62
|
+
|
|
63
|
+
**Never** search the filesystem, conversation history, or archives to find a document. Always use `document_list` with a `query`.
|
|
64
|
+
|
|
65
|
+
**If the user says they can't see a document you know exists** (e.g. after switching from macOS to web, or after a page refresh), call `document_open` with the `surface_id` to re-surface the editor panel on their current client.
|
|
66
|
+
|
|
62
67
|
## Find & Replace
|
|
63
68
|
|
|
64
69
|
Use `document_find` and `document_replace_text` for surgical edits that target specific text patterns without rewriting the entire document.
|
|
@@ -117,7 +122,7 @@ Users can leave inline comments on documents. Open comments are surfaced in a `<
|
|
|
117
122
|
## Anti-Patterns
|
|
118
123
|
|
|
119
124
|
- **Don't use `app_create` for blog posts, articles, or written content.** Use `document_create` — apps are for interactive content with state/data.
|
|
120
|
-
- **Don't
|
|
125
|
+
- **Don't write the article into the chat response.** Long-form prose goes in the document editor via `document_create`, not in chat and not into a `.md` file in the workspace. Acknowledge what you're doing and stream to the editor.
|
|
121
126
|
- **Don't wait to generate everything before sending.** Stream content in chunks via `document_update` with `mode: "append"` so users see progress in real time.
|
|
122
127
|
|
|
123
128
|
## Usage Notes
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
"name": "document_update",
|
|
45
|
-
"description": "
|
|
45
|
+
"description": "Append to or fully replace a document's content. Takes the full Markdown in `content` plus a `mode`: \"append\" adds it to the end (use this to stream generated content in chunks), \"replace\" overwrites the entire document. This tool does NOT do targeted edits — for changing specific words, phrases, or sections, use document_replace_text instead. There is no old/new or find/replace parameter here.",
|
|
46
46
|
"category": "document-editor",
|
|
47
47
|
"risk": "low",
|
|
48
48
|
"input_schema": {
|
|
@@ -27,13 +27,6 @@ When the user mentions "email" - sending, reading, checking, decluttering, draft
|
|
|
27
27
|
|
|
28
28
|
Do not offer the assistant's own email as an option unless the user specifically asks. If Gmail and Outlook are not connected, guide them through setup.
|
|
29
29
|
|
|
30
|
-
## Communication Style
|
|
31
|
-
|
|
32
|
-
- **Be action-oriented.** When the user asks to do something ("declutter", "check my email"), start doing it immediately. Don't ask for permission to read their inbox - that's obviously what they want.
|
|
33
|
-
- **Keep it human.** Never mention OAuth, tokens, APIs, sandboxes, credential proxies, or other technical internals. If something isn't working, say "Gmail needs to be reconnected" - not "the OAuth2 access token for google has expired."
|
|
34
|
-
- **Show progress.** When running a tool that scans many emails, tell the user what you're doing: "Scanning your inbox for clutter..." Don't go silent.
|
|
35
|
-
- **Be brief and warm.** One or two sentences per update is plenty. Don't over-explain what you're about to do - just do it and narrate lightly.
|
|
36
|
-
|
|
37
30
|
When a platform is connected (auth test succeeds), always use the messaging API tools for that platform. Never fall back to browser automation, shell commands (bash, curl), or any other approach for operations that messaging tools can handle. The messaging tools handle authentication internally - never try to access tokens or call APIs directly. Browser automation is only appropriate for initial credential setup (OAuth consent screens), not for day-to-day messaging operations.
|
|
38
31
|
|
|
39
32
|
**Exception: Slack.** Slack messaging should use the Slack Web API directly via CLI, not messaging tools. See the **slack** skill for details.
|
|
@@ -23,6 +23,7 @@ import * as acpSteer from "./bundled-skills/acp/tools/acp-steer.js";
|
|
|
23
23
|
import * as appCreate from "./bundled-skills/app-builder/tools/app-create.js";
|
|
24
24
|
import * as appDelete from "./bundled-skills/app-builder/tools/app-delete.js";
|
|
25
25
|
import * as appGenerateIcon from "./bundled-skills/app-builder/tools/app-generate-icon.js";
|
|
26
|
+
import * as appList from "./bundled-skills/app-builder/tools/app-list.js";
|
|
26
27
|
import * as appRefresh from "./bundled-skills/app-builder/tools/app-refresh.js";
|
|
27
28
|
// ── app-control ────────────────────────────────────────────────────────────────
|
|
28
29
|
import * as appControlClick from "./bundled-skills/app-control/tools/app-control-click.js";
|
|
@@ -142,6 +143,7 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
|
|
|
142
143
|
["app-builder:tools/app-delete.ts", appDelete],
|
|
143
144
|
["app-builder:tools/app-refresh.ts", appRefresh],
|
|
144
145
|
["app-builder:tools/app-generate-icon.ts", appGenerateIcon],
|
|
146
|
+
["app-builder:tools/app-list.ts", appList],
|
|
145
147
|
|
|
146
148
|
// app-control
|
|
147
149
|
["app-control:tools/app-control-start.ts", appControlStart],
|