@vellumai/assistant 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +5 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +325 -3
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +60 -36
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +266 -10
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +55 -13
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +31 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/types.ts +108 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +329 -317
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +38 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/feature-flag-registry.json +41 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +7 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop.ts +169 -9
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +16 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +98 -23
- package/src/daemon/lifecycle.ts +45 -35
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +49 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +1 -1
- package/src/daemon/pkb-reminder-builder.ts +1 -1
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +21 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +41 -0
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +22 -0
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +110 -10
- package/src/memory/db-init.ts +6 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/conversation-graph-memory.ts +31 -15
- package/src/memory/graph/tools.ts +3 -3
- package/src/memory/indexer.ts +34 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/inference.ts +1 -3
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/injection.test.ts +98 -8
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/injection.ts +32 -6
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +35 -5
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/emit-signal.ts +20 -1
- package/src/notifications/home-feed-side-effect.ts +54 -0
- package/src/notifications/signal.ts +3 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +36 -3
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +105 -32
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +31 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +12 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -166
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/providers/__tests__/inference.test.ts +22 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/connection-resolution.ts +7 -0
- package/src/providers/inference/adapter-factory.ts +41 -4
- package/src/providers/inference/connections.ts +74 -29
- package/src/providers/inference/resolve-auth.ts +12 -4
- package/src/providers/model-catalog.ts +294 -12
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/registry.ts +22 -14
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +42 -14
- package/src/runtime/auth/route-policy.ts +8 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-types.ts +19 -0
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +40 -35
- package/src/runtime/routes/conversation-routes.ts +90 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +15 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- 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 +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { QuestionPrompter } from "../../permissions/question-prompter.js";
|
|
4
|
+
import { RiskLevel } from "../../permissions/types.js";
|
|
5
|
+
import type { ToolDefinition } from "../../providers/types.js";
|
|
6
|
+
import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
|
|
7
|
+
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
8
|
+
|
|
9
|
+
// ── Input schema ────────────────────────────────────────────────────
|
|
10
|
+
// Runtime validation lives in Zod; the wire-level definition surfaced
|
|
11
|
+
// to the LLM is the hand-written JSON Schema in getDefinition() below.
|
|
12
|
+
// (The codebase does not currently use zod-to-json-schema for tool defs,
|
|
13
|
+
// so the two are kept in sync manually.)
|
|
14
|
+
|
|
15
|
+
const OptionSchema = z.object({
|
|
16
|
+
id: z.string().min(1),
|
|
17
|
+
label: z.string().min(1),
|
|
18
|
+
description: z.string().optional(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// One question in a (possibly single-element) batch. Intentionally has no
|
|
22
|
+
// `id` field — per-question ids are daemon-assigned (`q1`, `q2`, ...) inside
|
|
23
|
+
// the prompter, never supplied by the LLM. This keeps the LLM-facing schema
|
|
24
|
+
// smaller and removes a validation surface (no duplicate-id check, no
|
|
25
|
+
// length cap on ids).
|
|
26
|
+
const SingleQuestionSchema = z.object({
|
|
27
|
+
question: z.string().min(1),
|
|
28
|
+
description: z.string().optional(),
|
|
29
|
+
// 2–4 LLM-supplied options. The client renders a fixed 5th "Type
|
|
30
|
+
// something else" slot for free-text, so the model must keep the
|
|
31
|
+
// structured set to 4 or fewer.
|
|
32
|
+
options: z.array(OptionSchema).min(2).max(4),
|
|
33
|
+
freeTextPlaceholder: z.string().optional(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Cap at 5 questions per batch. Past that it starts to feel like a form,
|
|
37
|
+
// not a clarification — the model should be implementing, not asking. Any
|
|
38
|
+
// input with ≥6 entries is rejected with a clear Zod error.
|
|
39
|
+
const MAX_QUESTIONS_PER_BATCH = 5;
|
|
40
|
+
|
|
41
|
+
// Both the new batched shape (`questions[]`) and the legacy flat shape are
|
|
42
|
+
// accepted. `execute()` normalizes legacy callers into a one-element
|
|
43
|
+
// `questions` array before forwarding to the prompter.
|
|
44
|
+
const InputSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
questions: z
|
|
47
|
+
.array(SingleQuestionSchema)
|
|
48
|
+
.min(1)
|
|
49
|
+
.max(MAX_QUESTIONS_PER_BATCH, {
|
|
50
|
+
message: `At most ${MAX_QUESTIONS_PER_BATCH} questions per batch; split into multiple turns if you need more.`,
|
|
51
|
+
})
|
|
52
|
+
.optional(),
|
|
53
|
+
// Legacy flat fields. Optional so batched callers can omit them; when
|
|
54
|
+
// present and `questions` is absent, they are normalized into a
|
|
55
|
+
// one-element batch in `execute()`.
|
|
56
|
+
question: z.string().min(1).optional(),
|
|
57
|
+
description: z.string().optional(),
|
|
58
|
+
options: z.array(OptionSchema).min(2).max(4).optional(),
|
|
59
|
+
freeTextPlaceholder: z.string().optional(),
|
|
60
|
+
})
|
|
61
|
+
.refine(
|
|
62
|
+
(v) =>
|
|
63
|
+
v.questions !== undefined ||
|
|
64
|
+
(v.question !== undefined && v.options !== undefined),
|
|
65
|
+
{
|
|
66
|
+
message:
|
|
67
|
+
"Provide `questions` (preferred) or the legacy flat fields (`question` + `options`).",
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export type SingleQuestion = z.infer<typeof SingleQuestionSchema>;
|
|
72
|
+
export type AskQuestionInput = z.infer<typeof InputSchema>;
|
|
73
|
+
|
|
74
|
+
// ── Tool description ────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
const DESCRIPTION = [
|
|
77
|
+
"Use this tool whenever a request is ambiguous and can be resolved",
|
|
78
|
+
"by 2–4 plausible interpretations or discrete choices. Prefer it over",
|
|
79
|
+
"plain-text clarification — structured options are faster to answer and",
|
|
80
|
+
"remove guessing.",
|
|
81
|
+
"",
|
|
82
|
+
"When in doubt between (a) asking inline and (b) calling ask_question with",
|
|
83
|
+
"structured options: call ask_question. The structured choices are better UX.",
|
|
84
|
+
"",
|
|
85
|
+
'Example: given a request like "schedule lunch with Alice next week" where there',
|
|
86
|
+
"are two plausible Alice contacts, ask which Alice with options like",
|
|
87
|
+
'`{id: "alice_work", label: "Alice (work)"}` and',
|
|
88
|
+
'`{id: "alice_personal", label: "Alice (personal)"}`.',
|
|
89
|
+
"",
|
|
90
|
+
"Batch related clarifications into one call by passing multiple entries in",
|
|
91
|
+
"`questions` (up to 5). Each question gets its own page with a Skip button.",
|
|
92
|
+
"",
|
|
93
|
+
"When NOT to use this tool:",
|
|
94
|
+
"- The answer is obvious from context or recent conversation.",
|
|
95
|
+
"- The question is genuinely open-ended (more than ~4 plausible answers) —",
|
|
96
|
+
" fall back to plain text.",
|
|
97
|
+
"- You're about to take a low-stakes reversible action and can adjust based",
|
|
98
|
+
" on feedback.",
|
|
99
|
+
"",
|
|
100
|
+
"If a question is skipped, proceed with reasonable defaults for that",
|
|
101
|
+
"question; if every question in the batch is skipped, stop interrupting",
|
|
102
|
+
"and use defaults across the board.",
|
|
103
|
+
"",
|
|
104
|
+
"Provide 2–4 options. A free-text fallback is always added by the UI — do not",
|
|
105
|
+
"include a 'something else' option yourself.",
|
|
106
|
+
"",
|
|
107
|
+
"Each option needs a stable `id` (the value the response carries back) and a",
|
|
108
|
+
"short human-readable `label`. Optional `description` adds one line of",
|
|
109
|
+
"context shown beneath the label.",
|
|
110
|
+
].join("\n");
|
|
111
|
+
|
|
112
|
+
// ── Tool ────────────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
export class AskQuestionTool implements Tool {
|
|
115
|
+
name = "ask_question";
|
|
116
|
+
description = DESCRIPTION;
|
|
117
|
+
category = "interaction";
|
|
118
|
+
defaultRiskLevel = RiskLevel.Low;
|
|
119
|
+
|
|
120
|
+
// Override hook for tests: lets a test replace the prompter factory
|
|
121
|
+
// without monkey-patching the module. Default factory wires the real
|
|
122
|
+
// broadcastMessage so the question reaches every connected client.
|
|
123
|
+
private prompterFactory: () => Pick<QuestionPrompter, "prompt">;
|
|
124
|
+
|
|
125
|
+
constructor(
|
|
126
|
+
prompterFactory: () => Pick<QuestionPrompter, "prompt"> = () =>
|
|
127
|
+
new QuestionPrompter({ broadcastMessage }),
|
|
128
|
+
) {
|
|
129
|
+
this.prompterFactory = prompterFactory;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getDefinition(): ToolDefinition {
|
|
133
|
+
// Shared option-schema fragment used by both the batched `questions[]`
|
|
134
|
+
// shape and the legacy flat `options` field.
|
|
135
|
+
const optionItemsSchema = {
|
|
136
|
+
type: "object",
|
|
137
|
+
properties: {
|
|
138
|
+
id: {
|
|
139
|
+
type: "string",
|
|
140
|
+
description:
|
|
141
|
+
"Stable identifier for this option (returned verbatim in the response).",
|
|
142
|
+
},
|
|
143
|
+
label: {
|
|
144
|
+
type: "string",
|
|
145
|
+
description: "Short human-readable label.",
|
|
146
|
+
},
|
|
147
|
+
description: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "Optional one-line context shown beneath the label.",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
required: ["id", "label"],
|
|
153
|
+
} as const;
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
name: this.name,
|
|
157
|
+
description: this.description,
|
|
158
|
+
input_schema: {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
// ── Recommended shape ─────────────────────────────────────
|
|
162
|
+
questions: {
|
|
163
|
+
type: "array",
|
|
164
|
+
minItems: 1,
|
|
165
|
+
maxItems: MAX_QUESTIONS_PER_BATCH,
|
|
166
|
+
description: `Recommended shape. 1–${MAX_QUESTIONS_PER_BATCH} clarifying questions to ask in a single turn. Use a batch when several independent ambiguities block progress; ask one at a time when they're sequentially dependent. Past ${MAX_QUESTIONS_PER_BATCH} questions you should be implementing, not asking.`,
|
|
167
|
+
items: {
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
question: {
|
|
171
|
+
type: "string",
|
|
172
|
+
description: "The clarifying question to display.",
|
|
173
|
+
},
|
|
174
|
+
description: {
|
|
175
|
+
type: "string",
|
|
176
|
+
description:
|
|
177
|
+
"Optional one-line context shown beneath the question.",
|
|
178
|
+
},
|
|
179
|
+
options: {
|
|
180
|
+
type: "array",
|
|
181
|
+
minItems: 2,
|
|
182
|
+
maxItems: 4,
|
|
183
|
+
description:
|
|
184
|
+
"2–4 structured options. The UI always appends a free-text fallback slot, so do not include a 'something else' option here.",
|
|
185
|
+
items: optionItemsSchema,
|
|
186
|
+
},
|
|
187
|
+
freeTextPlaceholder: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description:
|
|
190
|
+
"Optional placeholder text shown inside the free-text fallback input.",
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
required: ["question", "options"],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
// ── Legacy single-question fields ─────────────────────────
|
|
197
|
+
// Kept optional so existing prompt caches and any single-question
|
|
198
|
+
// callers continue to work. New callers should use `questions`.
|
|
199
|
+
question: {
|
|
200
|
+
type: "string",
|
|
201
|
+
description:
|
|
202
|
+
"Legacy: the single clarifying question. Prefer `questions[]` for new code.",
|
|
203
|
+
},
|
|
204
|
+
description: {
|
|
205
|
+
type: "string",
|
|
206
|
+
description:
|
|
207
|
+
"Legacy: optional one-line context shown beneath the question. Prefer `questions[].description`.",
|
|
208
|
+
},
|
|
209
|
+
options: {
|
|
210
|
+
type: "array",
|
|
211
|
+
minItems: 2,
|
|
212
|
+
maxItems: 4,
|
|
213
|
+
description:
|
|
214
|
+
"Legacy: 2–4 structured options. Prefer `questions[].options`. The UI always appends a free-text fallback slot, so do not include a 'something else' option here.",
|
|
215
|
+
items: optionItemsSchema,
|
|
216
|
+
},
|
|
217
|
+
freeTextPlaceholder: {
|
|
218
|
+
type: "string",
|
|
219
|
+
description:
|
|
220
|
+
"Legacy: optional placeholder text for the free-text fallback input. Prefer `questions[].freeTextPlaceholder`.",
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
// No top-level `required` — caller must supply either `questions`
|
|
224
|
+
// or the legacy flat trio (`question` + `options`). Enforced in Zod.
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async execute(
|
|
230
|
+
input: Record<string, unknown>,
|
|
231
|
+
context: ToolContext,
|
|
232
|
+
): Promise<ToolExecutionResult> {
|
|
233
|
+
const parsed = InputSchema.safeParse(input);
|
|
234
|
+
if (!parsed.success) {
|
|
235
|
+
return {
|
|
236
|
+
content: `Invalid input: ${parsed.error.message}`,
|
|
237
|
+
isError: true,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Normalize legacy flat input into a one-element `questions` batch so
|
|
242
|
+
// downstream code only has to deal with the batched shape. The refine
|
|
243
|
+
// above guarantees `question` and `options` are present whenever
|
|
244
|
+
// `questions` is absent.
|
|
245
|
+
const questions: SingleQuestion[] = parsed.data.questions ?? [
|
|
246
|
+
{
|
|
247
|
+
question: parsed.data.question!,
|
|
248
|
+
description: parsed.data.description,
|
|
249
|
+
options: parsed.data.options!,
|
|
250
|
+
freeTextPlaceholder: parsed.data.freeTextPlaceholder,
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
const prompter = this.prompterFactory();
|
|
255
|
+
const result = await prompter.prompt({
|
|
256
|
+
conversationId: context.conversationId,
|
|
257
|
+
questions,
|
|
258
|
+
toolUseId: context.toolUseId,
|
|
259
|
+
signal: context.signal,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Format the aggregated transcript. Each line is keyed by the original
|
|
263
|
+
// question text (not the daemon-assigned id) — the LLM never sees those
|
|
264
|
+
// ids, and human-readable labels read better in the result content.
|
|
265
|
+
const lines = result.entries.map((entry, i) => {
|
|
266
|
+
const q = questions[i]!;
|
|
267
|
+
const prefix = `Question "${q.question}" →`;
|
|
268
|
+
if (entry.decision === "option") {
|
|
269
|
+
const chosen = q.options.find((o) => o.id === entry.optionId);
|
|
270
|
+
const label = chosen?.label ?? "(unknown)";
|
|
271
|
+
return `${prefix} Option: ${entry.optionId} (${label})`;
|
|
272
|
+
}
|
|
273
|
+
if (entry.decision === "free_text") {
|
|
274
|
+
return `${prefix} Free text: ${entry.text ?? ""}`;
|
|
275
|
+
}
|
|
276
|
+
return `${prefix} Skipped`;
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
switch (result.overall) {
|
|
280
|
+
case "completed":
|
|
281
|
+
return { content: lines.join("\n"), isError: false };
|
|
282
|
+
case "closed": {
|
|
283
|
+
const summary =
|
|
284
|
+
"User closed the question card without answering. All questions skipped.";
|
|
285
|
+
return {
|
|
286
|
+
content: [summary, ...lines].join("\n"),
|
|
287
|
+
isError: false,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
case "timed_out":
|
|
291
|
+
return {
|
|
292
|
+
content: "User did not respond within timeout",
|
|
293
|
+
isError: true,
|
|
294
|
+
};
|
|
295
|
+
case "aborted":
|
|
296
|
+
return {
|
|
297
|
+
content: "Question aborted",
|
|
298
|
+
isError: true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export const askQuestionTool = new AskQuestionTool();
|
|
@@ -90,7 +90,7 @@ const MODE_TRADEOFFS: Record<StatusCheckMode, string[]> = {
|
|
|
90
90
|
[BROWSER_STATUS_MODE.EXTENSION]: [
|
|
91
91
|
"This is the preferred approach for all things browser-use.",
|
|
92
92
|
"On macOS, the host browser proxy is provisioned automatically via the desktop client's SSE bridge — no extension install required.",
|
|
93
|
-
"When the Chrome extension is also installed, it takes priority for direct WebSocket routing to the
|
|
93
|
+
"When the Chrome extension is also installed, it takes priority for direct WebSocket routing to the active Chrome session.",
|
|
94
94
|
"More secure than relying on Chrome's native remote debugging functionality.",
|
|
95
95
|
],
|
|
96
96
|
[BROWSER_STATUS_MODE.CDP_INSPECT]: [
|
|
@@ -101,8 +101,8 @@ const MODE_TRADEOFFS: Record<StatusCheckMode, string[]> = {
|
|
|
101
101
|
],
|
|
102
102
|
[BROWSER_STATUS_MODE.LOCAL]: [
|
|
103
103
|
"The least-preferred approach for all things browser-use.",
|
|
104
|
-
"Considered a last-resort fallback
|
|
105
|
-
"Does not use the
|
|
104
|
+
"Considered a last-resort fallback when the Chrome Extension is not installed, remote debugging in Chrome is not enabled, and neither will be enabled.",
|
|
105
|
+
"Does not use the existing browser profile, so sessions/cookies may differ.",
|
|
106
106
|
"Requires that Playwright and Chromium are installed on the host machine,",
|
|
107
107
|
],
|
|
108
108
|
};
|
|
@@ -392,8 +392,8 @@ function acquireCdpClientWithMode(
|
|
|
392
392
|
targetClientId != null
|
|
393
393
|
? "extension"
|
|
394
394
|
: browserMode === "auto" && rememberedKind !== null
|
|
395
|
-
|
|
396
|
-
|
|
395
|
+
? rememberedKind
|
|
396
|
+
: browserMode;
|
|
397
397
|
|
|
398
398
|
try {
|
|
399
399
|
const raw = getCdpClient(context, { mode: effectiveMode, targetClientId });
|
|
@@ -406,7 +406,11 @@ function acquireCdpClientWithMode(
|
|
|
406
406
|
// sticky preference doesn't surface as a hard failure.
|
|
407
407
|
// Do not apply this fallback when target_client_id is set — a targeting
|
|
408
408
|
// failure must surface as an error, not silently route elsewhere.
|
|
409
|
-
if (
|
|
409
|
+
if (
|
|
410
|
+
browserMode === "auto" &&
|
|
411
|
+
effectiveMode !== "auto" &&
|
|
412
|
+
targetClientId == null
|
|
413
|
+
) {
|
|
410
414
|
browserManager.clearPreferredBackendKind(context.conversationId);
|
|
411
415
|
try {
|
|
412
416
|
const raw = getCdpClient(context, { mode: "auto", targetClientId });
|
|
@@ -952,10 +956,10 @@ export async function executeBrowserNavigate(
|
|
|
952
956
|
"2. Use credential fill to enter email/password from credential_store",
|
|
953
957
|
);
|
|
954
958
|
lines.push(
|
|
955
|
-
"3. For email verification codes, use ui_show with a form to
|
|
959
|
+
"3. For email verification codes, use ui_show with a form to request the code mid-turn",
|
|
956
960
|
);
|
|
957
961
|
lines.push(
|
|
958
|
-
"4. Do NOT give up or
|
|
962
|
+
"4. Do NOT give up or suggest manual sign-in - handle the login flow yourself",
|
|
959
963
|
);
|
|
960
964
|
}
|
|
961
965
|
} else {
|
|
@@ -964,7 +968,7 @@ export async function executeBrowserNavigate(
|
|
|
964
968
|
"⚠️ CAPTCHA/Cloudflare verification detected on this page.",
|
|
965
969
|
);
|
|
966
970
|
lines.push(
|
|
967
|
-
"
|
|
971
|
+
"This challenge requires human verification. Surface this clearly: the page cannot be accessed until the verification is solved manually.",
|
|
968
972
|
);
|
|
969
973
|
}
|
|
970
974
|
} else {
|
|
@@ -979,10 +983,10 @@ export async function executeBrowserNavigate(
|
|
|
979
983
|
"2. Use credential fill to enter email/password from credential_store",
|
|
980
984
|
);
|
|
981
985
|
lines.push(
|
|
982
|
-
"3. For email verification codes, use ui_show with a form to
|
|
986
|
+
"3. For email verification codes, use ui_show with a form to request the code mid-turn",
|
|
983
987
|
);
|
|
984
988
|
lines.push(
|
|
985
|
-
"4. Do NOT give up or
|
|
989
|
+
"4. Do NOT give up or suggest manual sign-in - handle the login flow yourself",
|
|
986
990
|
);
|
|
987
991
|
}
|
|
988
992
|
}
|
|
@@ -374,7 +374,7 @@ export const computerUseOpenAppTool: Tool = {
|
|
|
374
374
|
export const computerUseRunAppleScriptTool: Tool = {
|
|
375
375
|
name: "computer_use_run_applescript",
|
|
376
376
|
description:
|
|
377
|
-
"Run an AppleScript command. Prefer this over click/type when possible - it doesn't move the cursor or interrupt
|
|
377
|
+
"Run an AppleScript command. Prefer this over click/type when possible - it doesn't move the cursor or interrupt foreground activity. Never use 'do shell script' inside AppleScript (blocked for security).",
|
|
378
378
|
category: "computer-use",
|
|
379
379
|
defaultRiskLevel: RiskLevel.Low,
|
|
380
380
|
executionMode: "proxy",
|
|
@@ -448,7 +448,7 @@ export const computerUseDoneTool: Tool = {
|
|
|
448
448
|
export const computerUseRespondTool: Tool = {
|
|
449
449
|
name: "computer_use_respond",
|
|
450
450
|
description:
|
|
451
|
-
"
|
|
451
|
+
"Reply with a text answer instead of performing computer actions. Use this when you can answer directly without interacting with the screen.",
|
|
452
452
|
category: "computer-use",
|
|
453
453
|
defaultRiskLevel: RiskLevel.Low,
|
|
454
454
|
executionMode: "proxy",
|
|
@@ -462,7 +462,7 @@ export const computerUseRespondTool: Tool = {
|
|
|
462
462
|
properties: {
|
|
463
463
|
answer: {
|
|
464
464
|
type: "string",
|
|
465
|
-
description: "The text answer to display
|
|
465
|
+
description: "The text answer to display",
|
|
466
466
|
},
|
|
467
467
|
reasoning: {
|
|
468
468
|
type: "string",
|
|
@@ -88,7 +88,7 @@ class CredentialStoreTool implements Tool {
|
|
|
88
88
|
type: "string",
|
|
89
89
|
enum: ["store", "list", "delete", "prompt"],
|
|
90
90
|
description:
|
|
91
|
-
'The operation to perform. Use "prompt" to
|
|
91
|
+
'The operation to perform. Use "prompt" to request a secret via secure UI - the value never enters the conversation.',
|
|
92
92
|
},
|
|
93
93
|
service: {
|
|
94
94
|
type: "string",
|
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
deleteDocument,
|
|
5
|
+
getDocumentById,
|
|
6
|
+
getDocumentsForConversation,
|
|
7
|
+
isDocumentAssociatedWithConversation,
|
|
4
8
|
saveDocument,
|
|
9
|
+
searchDocumentsByTitle,
|
|
5
10
|
updateDocumentContent,
|
|
6
11
|
} from "../../documents/document-store.js";
|
|
7
12
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
8
13
|
|
|
14
|
+
function isPrivilegedDocumentActor(context: ToolContext): boolean {
|
|
15
|
+
return (
|
|
16
|
+
context.trustClass === "guardian" || context.executionChannel === "vellum"
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function documentNotFound(surfaceId: string): ToolExecutionResult {
|
|
21
|
+
return {
|
|
22
|
+
content: JSON.stringify({
|
|
23
|
+
success: false,
|
|
24
|
+
surface_id: surfaceId,
|
|
25
|
+
error: "Document not found",
|
|
26
|
+
}),
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function canAccessDocument(surfaceId: string, context: ToolContext): boolean {
|
|
32
|
+
return (
|
|
33
|
+
isPrivilegedDocumentActor(context) ||
|
|
34
|
+
isDocumentAssociatedWithConversation(surfaceId, context.conversationId)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
9
38
|
// ── Exported execute functions ──────────────────────────────────────
|
|
10
39
|
|
|
11
40
|
export function executeDocumentCreate(
|
|
@@ -85,7 +114,21 @@ export function executeDocumentUpdate(
|
|
|
85
114
|
const content = input.content as string;
|
|
86
115
|
const mode = (input.mode as string | undefined) || "append";
|
|
87
116
|
|
|
88
|
-
|
|
117
|
+
if (!canAccessDocument(surfaceId, context)) {
|
|
118
|
+
return documentNotFound(surfaceId);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = updateDocumentContent(surfaceId, content, mode);
|
|
122
|
+
if (!result.success) {
|
|
123
|
+
return {
|
|
124
|
+
content: JSON.stringify({
|
|
125
|
+
success: false,
|
|
126
|
+
surface_id: surfaceId,
|
|
127
|
+
error: result.error,
|
|
128
|
+
}),
|
|
129
|
+
isError: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
89
132
|
|
|
90
133
|
// Send document_editor_update message to update the built-in RTE
|
|
91
134
|
if (context.sendToClient) {
|
|
@@ -117,3 +160,83 @@ export function executeDocumentUpdate(
|
|
|
117
160
|
isError: true,
|
|
118
161
|
};
|
|
119
162
|
}
|
|
163
|
+
|
|
164
|
+
export function executeDocumentRead(
|
|
165
|
+
input: Record<string, unknown>,
|
|
166
|
+
context: ToolContext,
|
|
167
|
+
): ToolExecutionResult {
|
|
168
|
+
const surfaceId = input.surface_id as string;
|
|
169
|
+
if (!canAccessDocument(surfaceId, context)) {
|
|
170
|
+
return documentNotFound(surfaceId);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const doc = getDocumentById(surfaceId);
|
|
174
|
+
if (!doc) {
|
|
175
|
+
return documentNotFound(surfaceId);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
content: JSON.stringify({
|
|
179
|
+
success: true,
|
|
180
|
+
surface_id: doc.surfaceId,
|
|
181
|
+
title: doc.title,
|
|
182
|
+
content: doc.content,
|
|
183
|
+
word_count: doc.wordCount,
|
|
184
|
+
updated_at: doc.updatedAt,
|
|
185
|
+
}),
|
|
186
|
+
isError: false,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function executeDocumentList(
|
|
191
|
+
input: Record<string, unknown>,
|
|
192
|
+
context: ToolContext,
|
|
193
|
+
): ToolExecutionResult {
|
|
194
|
+
const query =
|
|
195
|
+
typeof input.query === "string" && input.query.trim().length > 0
|
|
196
|
+
? input.query.trim()
|
|
197
|
+
: undefined;
|
|
198
|
+
const docs = query
|
|
199
|
+
? searchDocumentsByTitle(
|
|
200
|
+
query,
|
|
201
|
+
isPrivilegedDocumentActor(context)
|
|
202
|
+
? {}
|
|
203
|
+
: { conversationId: context.conversationId },
|
|
204
|
+
)
|
|
205
|
+
: getDocumentsForConversation(context.conversationId);
|
|
206
|
+
return {
|
|
207
|
+
content: JSON.stringify({
|
|
208
|
+
success: true,
|
|
209
|
+
documents: docs.map((d) => ({
|
|
210
|
+
surface_id: d.surfaceId,
|
|
211
|
+
title: d.title,
|
|
212
|
+
word_count: d.wordCount,
|
|
213
|
+
created_at: d.createdAt,
|
|
214
|
+
updated_at: d.updatedAt,
|
|
215
|
+
})),
|
|
216
|
+
}),
|
|
217
|
+
isError: false,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function executeDocumentDelete(
|
|
222
|
+
input: Record<string, unknown>,
|
|
223
|
+
context: ToolContext,
|
|
224
|
+
): ToolExecutionResult {
|
|
225
|
+
const surfaceId = input.surface_id as string;
|
|
226
|
+
if (!canAccessDocument(surfaceId, context)) {
|
|
227
|
+
return documentNotFound(surfaceId);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const deleted = deleteDocument(surfaceId);
|
|
231
|
+
if (!deleted) {
|
|
232
|
+
return documentNotFound(surfaceId);
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
content: JSON.stringify({
|
|
236
|
+
success: true,
|
|
237
|
+
surface_id: surfaceId,
|
|
238
|
+
message: "Document deleted",
|
|
239
|
+
}),
|
|
240
|
+
isError: false,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
@@ -41,7 +41,7 @@ class FileEditTool implements Tool {
|
|
|
41
41
|
activity: {
|
|
42
42
|
type: "string",
|
|
43
43
|
description:
|
|
44
|
-
"Brief non-technical explanation of what you are doing and why, shown
|
|
44
|
+
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
47
|
required: ["path", "old_string", "new_string", "activity"],
|
|
@@ -30,7 +30,7 @@ class FileListTool implements Tool {
|
|
|
30
30
|
activity: {
|
|
31
31
|
type: "string",
|
|
32
32
|
description:
|
|
33
|
-
"Brief non-technical explanation of what you are doing and why, shown
|
|
33
|
+
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
required: ["path", "activity"],
|
|
@@ -41,7 +41,7 @@ class FileReadTool implements Tool {
|
|
|
41
41
|
activity: {
|
|
42
42
|
type: "string",
|
|
43
43
|
description:
|
|
44
|
-
"Brief non-technical explanation of what you are doing and why, shown
|
|
44
|
+
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
47
|
required: ["path", "activity"],
|
|
@@ -56,7 +56,7 @@ class FileWriteTool implements Tool {
|
|
|
56
56
|
activity: {
|
|
57
57
|
type: "string",
|
|
58
58
|
description:
|
|
59
|
-
"Brief non-technical explanation of what you are doing and why, shown
|
|
59
|
+
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
60
60
|
},
|
|
61
61
|
},
|
|
62
62
|
required: ["path", "content", "activity"],
|
|
@@ -121,7 +121,10 @@ class FileWriteTool implements Tool {
|
|
|
121
121
|
// Indexing `pkb/*.json` (or any other extension) here would produce
|
|
122
122
|
// chunks the reconciler can't see, leading to orphaned vectors and
|
|
123
123
|
// pointless embedding work.
|
|
124
|
-
if (
|
|
124
|
+
if (
|
|
125
|
+
filePath.toLowerCase().endsWith(".md") &&
|
|
126
|
+
isInsidePkbRoot(filePath, pkbRoot)
|
|
127
|
+
) {
|
|
125
128
|
enqueuePkbIndexJob({
|
|
126
129
|
pkbRoot,
|
|
127
130
|
absPath: filePath,
|
|
@@ -13,7 +13,7 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
13
13
|
class HostFileTransferTool implements Tool {
|
|
14
14
|
name = "host_file_transfer";
|
|
15
15
|
description =
|
|
16
|
-
"Copy a file between the assistant's workspace and the
|
|
16
|
+
"Copy a file between the assistant's workspace and the host machine. Set direction to 'to_host' to send a workspace file to the host, or 'to_sandbox' to pull a host file into the workspace. When multiple clients support host_file, specify which one to use with target_client_id.";
|
|
17
17
|
category = "host-filesystem";
|
|
18
18
|
defaultRiskLevel = RiskLevel.Medium;
|
|
19
19
|
|
|
@@ -95,7 +95,7 @@ function buildHostBashProxyEnv(
|
|
|
95
95
|
class HostShellTool implements Tool {
|
|
96
96
|
name = "host_bash";
|
|
97
97
|
description =
|
|
98
|
-
"LAST RESORT — Execute a shell command directly on the
|
|
98
|
+
"LAST RESORT — Execute a shell command directly on the host machine. You MUST strongly prefer the regular `bash` tool for all commands. Only use `host_bash` when you are absolutely certain the command MUST run on the host machine and CANNOT run in the workspace (e.g., managing host-level system services, accessing host-only peripherals, or interacting with host paths outside the workspace). If in doubt, use `bash` instead. Approval-gated: each invocation must be explicitly approved. Do not use for commands that require injected credentials or secrets.";
|
|
99
99
|
category = "host-terminal";
|
|
100
100
|
// host_bash is a weaker-tier escape hatch under CES lockdown. It remains
|
|
101
101
|
// Medium risk by default but persistent approvals are disabled for
|
|
@@ -402,7 +402,7 @@ export class PermissionChecker {
|
|
|
402
402
|
const denialMessage =
|
|
403
403
|
contextualDenial.length > 0
|
|
404
404
|
? contextualDenial
|
|
405
|
-
: `Permission denied
|
|
405
|
+
: `Permission denied. The "${name}" tool was not allowed. Do NOT retry this tool call immediately. Instead, explain that the action was not performed because permission was denied, and ask whether to try again or take a different approach. Wait for an explicit response before retrying.`;
|
|
406
406
|
const denialReason =
|
|
407
407
|
contextualDenial.length > 0
|
|
408
408
|
? `Permission denied (${name}): contextual policy`
|