@vellumai/assistant 0.8.2 → 0.8.4
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 +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- 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 +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { getConfig } from "../../config/loader.js";
|
|
2
|
+
import type {
|
|
3
|
+
WebSearchMetadata,
|
|
4
|
+
WebSearchResultItem,
|
|
5
|
+
} from "../../daemon/message-types/web-activity.js";
|
|
2
6
|
import { RiskLevel } from "../../permissions/types.js";
|
|
3
7
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
4
8
|
import { getProviderKeyAsync } from "../../security/secure-keys.js";
|
|
5
9
|
import { wrapUntrustedContent } from "../../security/untrusted-content.js";
|
|
10
|
+
import { faviconUrlForDomain } from "../../util/favicon.js";
|
|
6
11
|
import { getLogger } from "../../util/logger.js";
|
|
7
12
|
import {
|
|
8
13
|
DEFAULT_BASE_DELAY_MS,
|
|
@@ -12,6 +17,7 @@ import {
|
|
|
12
17
|
} from "../../util/retry.js";
|
|
13
18
|
import { registerTool } from "../registry.js";
|
|
14
19
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
20
|
+
import { extractDomain } from "./domain-normalize.js";
|
|
15
21
|
|
|
16
22
|
const log = getLogger("web-search");
|
|
17
23
|
|
|
@@ -201,6 +207,85 @@ function formatTavilyResults(
|
|
|
201
207
|
return lines.join("\n");
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
function buildBraveMetadata(
|
|
211
|
+
results: BraveSearchResult[],
|
|
212
|
+
query: string,
|
|
213
|
+
durationMs: number,
|
|
214
|
+
): WebSearchMetadata {
|
|
215
|
+
const items: WebSearchResultItem[] = results.map((r, i) => {
|
|
216
|
+
const domain = extractDomain(r.url);
|
|
217
|
+
return {
|
|
218
|
+
rank: i + 1,
|
|
219
|
+
title: r.title,
|
|
220
|
+
url: r.url,
|
|
221
|
+
domain,
|
|
222
|
+
faviconUrl: faviconUrlForDomain(domain),
|
|
223
|
+
snippet: r.description,
|
|
224
|
+
age: r.age,
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
query,
|
|
229
|
+
provider: "brave",
|
|
230
|
+
resultCount: items.length,
|
|
231
|
+
durationMs,
|
|
232
|
+
results: items,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function buildPerplexityMetadata(
|
|
237
|
+
data: PerplexityResponse,
|
|
238
|
+
query: string,
|
|
239
|
+
durationMs: number,
|
|
240
|
+
): WebSearchMetadata {
|
|
241
|
+
const citations = data.citations ?? [];
|
|
242
|
+
const items: WebSearchResultItem[] = citations.map((url, i) => {
|
|
243
|
+
const domain = extractDomain(url);
|
|
244
|
+
return {
|
|
245
|
+
rank: i + 1,
|
|
246
|
+
title: "",
|
|
247
|
+
url,
|
|
248
|
+
domain,
|
|
249
|
+
faviconUrl: faviconUrlForDomain(domain),
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
return {
|
|
253
|
+
query,
|
|
254
|
+
provider: "perplexity",
|
|
255
|
+
resultCount: items.length,
|
|
256
|
+
durationMs,
|
|
257
|
+
results: items,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function buildTavilyMetadata(
|
|
262
|
+
data: TavilySearchResponse,
|
|
263
|
+
query: string,
|
|
264
|
+
durationMs: number,
|
|
265
|
+
): WebSearchMetadata {
|
|
266
|
+
const results = data.results ?? [];
|
|
267
|
+
const items: WebSearchResultItem[] = results.map((r, i) => {
|
|
268
|
+
const url = r.url ?? "";
|
|
269
|
+
const domain = extractDomain(url);
|
|
270
|
+
return {
|
|
271
|
+
rank: i + 1,
|
|
272
|
+
title: r.title?.trim() || url.trim() || "Untitled result",
|
|
273
|
+
url,
|
|
274
|
+
domain,
|
|
275
|
+
faviconUrl: r.favicon ?? faviconUrlForDomain(domain),
|
|
276
|
+
snippet: r.content,
|
|
277
|
+
score: r.score,
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
return {
|
|
281
|
+
query,
|
|
282
|
+
provider: "tavily",
|
|
283
|
+
resultCount: items.length,
|
|
284
|
+
durationMs,
|
|
285
|
+
results: items,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
204
289
|
function tavilyTimeRangeForFreshness(
|
|
205
290
|
freshness: string | undefined,
|
|
206
291
|
): "day" | "week" | "month" | "year" | undefined {
|
|
@@ -218,6 +303,28 @@ function tavilyTimeRangeForFreshness(
|
|
|
218
303
|
}
|
|
219
304
|
}
|
|
220
305
|
|
|
306
|
+
function errorResult(
|
|
307
|
+
query: string,
|
|
308
|
+
provider: WebSearchProvider,
|
|
309
|
+
startedAt: number,
|
|
310
|
+
errorMessage: string,
|
|
311
|
+
): ToolExecutionResult {
|
|
312
|
+
return {
|
|
313
|
+
content: `Error: ${errorMessage}`,
|
|
314
|
+
isError: true,
|
|
315
|
+
activityMetadata: {
|
|
316
|
+
webSearch: {
|
|
317
|
+
query,
|
|
318
|
+
provider,
|
|
319
|
+
resultCount: 0,
|
|
320
|
+
durationMs: Date.now() - startedAt,
|
|
321
|
+
results: [],
|
|
322
|
+
errorMessage,
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
221
328
|
async function executeBraveSearch(
|
|
222
329
|
query: string,
|
|
223
330
|
count: number,
|
|
@@ -238,6 +345,7 @@ async function executeBraveSearch(
|
|
|
238
345
|
}
|
|
239
346
|
|
|
240
347
|
const url = `${BRAVE_API_URL}?${params.toString()}`;
|
|
348
|
+
const startedAt = Date.now();
|
|
241
349
|
|
|
242
350
|
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
243
351
|
const response = await fetch(url, {
|
|
@@ -252,6 +360,7 @@ async function executeBraveSearch(
|
|
|
252
360
|
if (response.ok) {
|
|
253
361
|
const data = (await response.json()) as BraveSearchResponse;
|
|
254
362
|
const results = data.web?.results ?? [];
|
|
363
|
+
const durationMs = Date.now() - startedAt;
|
|
255
364
|
return {
|
|
256
365
|
content:
|
|
257
366
|
wrapUntrustedContent(formatBraveResults(results, query), {
|
|
@@ -259,16 +368,21 @@ async function executeBraveSearch(
|
|
|
259
368
|
sourceDetail: "brave",
|
|
260
369
|
}) + CITATION_INSTRUCTION,
|
|
261
370
|
isError: false,
|
|
371
|
+
activityMetadata: {
|
|
372
|
+
webSearch: buildBraveMetadata(results, query, durationMs),
|
|
373
|
+
},
|
|
262
374
|
};
|
|
263
375
|
}
|
|
264
376
|
|
|
265
377
|
await response.text();
|
|
266
378
|
|
|
267
379
|
if (response.status === 401 || response.status === 403) {
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
380
|
+
return errorResult(
|
|
381
|
+
query,
|
|
382
|
+
"brave",
|
|
383
|
+
startedAt,
|
|
384
|
+
"Invalid or expired Brave Search API key",
|
|
385
|
+
);
|
|
272
386
|
}
|
|
273
387
|
|
|
274
388
|
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
@@ -286,24 +400,22 @@ async function executeBraveSearch(
|
|
|
286
400
|
}
|
|
287
401
|
|
|
288
402
|
log.warn({ status: response.status }, "Brave Search API error");
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
content: `Error: Brave Search API returned status ${response.status}`,
|
|
298
|
-
isError: true,
|
|
299
|
-
};
|
|
403
|
+
return errorResult(
|
|
404
|
+
query,
|
|
405
|
+
"brave",
|
|
406
|
+
startedAt,
|
|
407
|
+
response.status === 429
|
|
408
|
+
? "Brave Search rate limit exceeded after retries. Try again shortly."
|
|
409
|
+
: `Brave Search API returned status ${response.status}`,
|
|
410
|
+
);
|
|
300
411
|
}
|
|
301
412
|
|
|
302
|
-
return
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
413
|
+
return errorResult(
|
|
414
|
+
query,
|
|
415
|
+
"brave",
|
|
416
|
+
startedAt,
|
|
417
|
+
"Brave Search rate limit exceeded after retries. Try again shortly.",
|
|
418
|
+
);
|
|
307
419
|
}
|
|
308
420
|
|
|
309
421
|
async function executePerplexitySearch(
|
|
@@ -311,6 +423,7 @@ async function executePerplexitySearch(
|
|
|
311
423
|
apiKey: string,
|
|
312
424
|
signal?: AbortSignal,
|
|
313
425
|
): Promise<ToolExecutionResult> {
|
|
426
|
+
const startedAt = Date.now();
|
|
314
427
|
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
315
428
|
const response = await fetch(PERPLEXITY_API_URL, {
|
|
316
429
|
method: "POST",
|
|
@@ -327,6 +440,7 @@ async function executePerplexitySearch(
|
|
|
327
440
|
|
|
328
441
|
if (response.ok) {
|
|
329
442
|
const data = (await response.json()) as PerplexityResponse;
|
|
443
|
+
const durationMs = Date.now() - startedAt;
|
|
330
444
|
return {
|
|
331
445
|
content:
|
|
332
446
|
wrapUntrustedContent(formatPerplexityResults(data, query), {
|
|
@@ -334,16 +448,21 @@ async function executePerplexitySearch(
|
|
|
334
448
|
sourceDetail: "perplexity",
|
|
335
449
|
}) + CITATION_INSTRUCTION,
|
|
336
450
|
isError: false,
|
|
451
|
+
activityMetadata: {
|
|
452
|
+
webSearch: buildPerplexityMetadata(data, query, durationMs),
|
|
453
|
+
},
|
|
337
454
|
};
|
|
338
455
|
}
|
|
339
456
|
|
|
340
457
|
await response.text();
|
|
341
458
|
|
|
342
459
|
if (response.status === 401 || response.status === 403) {
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
460
|
+
return errorResult(
|
|
461
|
+
query,
|
|
462
|
+
"perplexity",
|
|
463
|
+
startedAt,
|
|
464
|
+
"Invalid or expired Perplexity API key",
|
|
465
|
+
);
|
|
347
466
|
}
|
|
348
467
|
|
|
349
468
|
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
@@ -361,24 +480,22 @@ async function executePerplexitySearch(
|
|
|
361
480
|
}
|
|
362
481
|
|
|
363
482
|
log.warn({ status: response.status }, "Perplexity API error");
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
content: `Error: Perplexity API returned status ${response.status}`,
|
|
373
|
-
isError: true,
|
|
374
|
-
};
|
|
483
|
+
return errorResult(
|
|
484
|
+
query,
|
|
485
|
+
"perplexity",
|
|
486
|
+
startedAt,
|
|
487
|
+
response.status === 429
|
|
488
|
+
? "Perplexity rate limit exceeded after retries. Try again shortly."
|
|
489
|
+
: `Perplexity API returned status ${response.status}`,
|
|
490
|
+
);
|
|
375
491
|
}
|
|
376
492
|
|
|
377
|
-
return
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
493
|
+
return errorResult(
|
|
494
|
+
query,
|
|
495
|
+
"perplexity",
|
|
496
|
+
startedAt,
|
|
497
|
+
"Perplexity rate limit exceeded after retries. Try again shortly.",
|
|
498
|
+
);
|
|
382
499
|
}
|
|
383
500
|
|
|
384
501
|
async function executeTavilySearch(
|
|
@@ -398,6 +515,8 @@ async function executeTavilySearch(
|
|
|
398
515
|
body.time_range = timeRange;
|
|
399
516
|
}
|
|
400
517
|
|
|
518
|
+
const startedAt = Date.now();
|
|
519
|
+
|
|
401
520
|
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
402
521
|
const response = await fetch(TAVILY_API_URL, {
|
|
403
522
|
method: "POST",
|
|
@@ -412,6 +531,7 @@ async function executeTavilySearch(
|
|
|
412
531
|
|
|
413
532
|
if (response.ok) {
|
|
414
533
|
const data = (await response.json()) as TavilySearchResponse;
|
|
534
|
+
const durationMs = Date.now() - startedAt;
|
|
415
535
|
return {
|
|
416
536
|
content:
|
|
417
537
|
wrapUntrustedContent(formatTavilyResults(data, query), {
|
|
@@ -419,16 +539,21 @@ async function executeTavilySearch(
|
|
|
419
539
|
sourceDetail: "tavily",
|
|
420
540
|
}) + CITATION_INSTRUCTION,
|
|
421
541
|
isError: false,
|
|
542
|
+
activityMetadata: {
|
|
543
|
+
webSearch: buildTavilyMetadata(data, query, durationMs),
|
|
544
|
+
},
|
|
422
545
|
};
|
|
423
546
|
}
|
|
424
547
|
|
|
425
548
|
await response.text();
|
|
426
549
|
|
|
427
550
|
if (response.status === 401 || response.status === 403) {
|
|
428
|
-
return
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
551
|
+
return errorResult(
|
|
552
|
+
query,
|
|
553
|
+
"tavily",
|
|
554
|
+
startedAt,
|
|
555
|
+
"Invalid or expired Tavily API key",
|
|
556
|
+
);
|
|
432
557
|
}
|
|
433
558
|
|
|
434
559
|
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
@@ -446,24 +571,22 @@ async function executeTavilySearch(
|
|
|
446
571
|
}
|
|
447
572
|
|
|
448
573
|
log.warn({ status: response.status }, "Tavily Search API error");
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
content: `Error: Tavily Search API returned status ${response.status}`,
|
|
458
|
-
isError: true,
|
|
459
|
-
};
|
|
574
|
+
return errorResult(
|
|
575
|
+
query,
|
|
576
|
+
"tavily",
|
|
577
|
+
startedAt,
|
|
578
|
+
response.status === 429
|
|
579
|
+
? "Tavily Search rate limit exceeded after retries. Try again shortly."
|
|
580
|
+
: `Tavily Search API returned status ${response.status}`,
|
|
581
|
+
);
|
|
460
582
|
}
|
|
461
583
|
|
|
462
|
-
return
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
584
|
+
return errorResult(
|
|
585
|
+
query,
|
|
586
|
+
"tavily",
|
|
587
|
+
startedAt,
|
|
588
|
+
"Tavily Search rate limit exceeded after retries. Try again shortly.",
|
|
589
|
+
);
|
|
467
590
|
}
|
|
468
591
|
|
|
469
592
|
// ----------------------------------------------------------------------------
|
|
@@ -573,6 +696,7 @@ class WebSearchTool implements Tool {
|
|
|
573
696
|
};
|
|
574
697
|
}
|
|
575
698
|
|
|
699
|
+
const startedAt = Date.now();
|
|
576
700
|
let provider = getWebSearchProvider();
|
|
577
701
|
let apiKey = await getApiKey(provider);
|
|
578
702
|
|
|
@@ -594,11 +718,12 @@ class WebSearchTool implements Tool {
|
|
|
594
718
|
}
|
|
595
719
|
|
|
596
720
|
if (!apiKey) {
|
|
597
|
-
return
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
721
|
+
return errorResult(
|
|
722
|
+
query,
|
|
723
|
+
provider,
|
|
724
|
+
startedAt,
|
|
725
|
+
"No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, or `keys set tavily <key>`, or configure it from the Settings page under API Keys.",
|
|
726
|
+
);
|
|
602
727
|
}
|
|
603
728
|
}
|
|
604
729
|
|
|
@@ -627,7 +752,7 @@ class WebSearchTool implements Tool {
|
|
|
627
752
|
} catch (err) {
|
|
628
753
|
const msg = err instanceof Error ? err.message : String(err);
|
|
629
754
|
log.error({ err }, "Web search failed");
|
|
630
|
-
return
|
|
755
|
+
return errorResult(query, provider, startedAt, `Web search failed: ${msg}`);
|
|
631
756
|
}
|
|
632
757
|
}
|
|
633
758
|
}
|
package/src/tools/registry.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { hostFileWriteTool } from "./host-filesystem/write.js";
|
|
|
10
10
|
import { hostShellTool } from "./host-terminal/host-shell.js";
|
|
11
11
|
import { toProviderSafeToolName } from "./provider-tool-name.js";
|
|
12
12
|
import { registerSystemTools } from "./system/register.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { LoadedPluginTool, Tool } from "./types.js";
|
|
14
14
|
import { allUiSurfaceTools } from "./ui-surface/definitions.js";
|
|
15
15
|
import { registerUiSurfaceTools } from "./ui-surface/registry.js";
|
|
16
16
|
|
|
@@ -193,7 +193,7 @@ export function registerSkillTools(newTools: Tool[]): Tool[] {
|
|
|
193
193
|
*/
|
|
194
194
|
export function registerPluginTools(
|
|
195
195
|
pluginName: string,
|
|
196
|
-
newTools:
|
|
196
|
+
newTools: LoadedPluginTool[],
|
|
197
197
|
): Tool[] {
|
|
198
198
|
const stamped: Tool[] = newTools.map((pluginTool) => {
|
|
199
199
|
const { input_schema, ...rest } = pluginTool;
|
|
@@ -61,12 +61,13 @@ export const SAFE_ENV_VARS = [
|
|
|
61
61
|
] as const;
|
|
62
62
|
|
|
63
63
|
export const KATA_SAFE_ENV_VARS = [
|
|
64
|
-
"LD_LIBRARY_PATH",
|
|
65
64
|
"VELLUM_APT_DATA_ROOT",
|
|
66
65
|
"VELLUM_APT_DATA_SUITE",
|
|
67
66
|
"VELLUM_APT_DATA_MIRROR",
|
|
68
67
|
] as const;
|
|
69
68
|
|
|
69
|
+
export const KATA_INJECTED_ENV_VARS = ["LD_LIBRARY_PATH"] as const;
|
|
70
|
+
|
|
70
71
|
const KATA_APT_DATA_ROOT = "/data/system";
|
|
71
72
|
|
|
72
73
|
function kataAptPaths(dataRoot: string): string[] {
|
|
@@ -132,7 +133,7 @@ export function buildSanitizedEnv(): Record<string, string> {
|
|
|
132
133
|
env.VELLUM_APT_DATA_ROOT = kataAptDataRoot;
|
|
133
134
|
env.PATH = appendUniquePathEntries(env.PATH, kataAptPaths(kataAptDataRoot));
|
|
134
135
|
env.LD_LIBRARY_PATH = appendUniquePathEntries(
|
|
135
|
-
|
|
136
|
+
undefined,
|
|
136
137
|
kataAptLibraryPaths(kataAptDataRoot),
|
|
137
138
|
);
|
|
138
139
|
}
|
|
@@ -334,9 +334,19 @@ export class ToolApprovalHandler {
|
|
|
334
334
|
return { allowed: false, result: { content: msg, isError: true } };
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
337
|
+
// Look up the tool before the allowedToolNames gate so a name no skill
|
|
338
|
+
// provides surfaces as "Unknown tool" (with the real list) instead of
|
|
339
|
+
// the misleading "load the skill" hint.
|
|
340
|
+
const tool = getTool(name);
|
|
341
|
+
if (!tool) {
|
|
342
|
+
const allowedToolNames = context.allowedToolNames;
|
|
343
|
+
const available = getAllTools()
|
|
344
|
+
.filter((t) => t.executionMode !== "proxy" || context.proxyToolResolver)
|
|
345
|
+
.map((t) => t.name)
|
|
346
|
+
.filter((n) => !allowedToolNames || allowedToolNames.has(n))
|
|
347
|
+
.sort()
|
|
348
|
+
.join(", ");
|
|
349
|
+
const msg = `Unknown tool: ${name}. Available tools: ${available}`;
|
|
340
350
|
const durationMs = Date.now() - startTime;
|
|
341
351
|
emitLifecycleEvent({
|
|
342
352
|
type: "error",
|
|
@@ -356,15 +366,12 @@ export class ToolApprovalHandler {
|
|
|
356
366
|
return { allowed: false, result: { content: msg, isError: true } };
|
|
357
367
|
}
|
|
358
368
|
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
.sort()
|
|
366
|
-
.join(", ");
|
|
367
|
-
const msg = `Unknown tool: ${name}. Available tools: ${available}`;
|
|
369
|
+
// Gate tools not active for the current turn
|
|
370
|
+
if (context.allowedToolNames && !context.allowedToolNames.has(name)) {
|
|
371
|
+
const loadHint = tool.ownerSkillId
|
|
372
|
+
? `Load the "${tool.ownerSkillId}" skill that provides this tool first.`
|
|
373
|
+
: `Load the skill that provides this tool first.`;
|
|
374
|
+
const msg = `Tool "${name}" is not currently active. ${loadHint}`;
|
|
368
375
|
const durationMs = Date.now() - startTime;
|
|
369
376
|
emitLifecycleEvent({
|
|
370
377
|
type: "error",
|
package/src/tools/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
|
|
15
15
|
import type { InterfaceId } from "../channels/types.js";
|
|
16
16
|
import type { CesClient } from "../credential-execution/client.js";
|
|
17
|
+
import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
|
|
17
18
|
import type { SecretPromptResult } from "../permissions/secret-prompter.js";
|
|
18
19
|
import type { ContentBlock } from "../providers/types.js";
|
|
19
20
|
import type { TrustClass } from "../runtime/actor-trust-resolver.js";
|
|
@@ -163,6 +164,9 @@ export interface ToolExecutionResult extends PluginToolExecutionResult {
|
|
|
163
164
|
* approval flow transparently.
|
|
164
165
|
*/
|
|
165
166
|
cesApprovalRequired?: ApprovalRequired;
|
|
167
|
+
/** Structured activity metadata for client rendering (web search, web fetch, etc).
|
|
168
|
+
* Populated by daemon-internal tools; plugins must not set this. */
|
|
169
|
+
activityMetadata?: ToolActivityMetadata;
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
export type ProxyToolResolver = (
|
|
@@ -376,16 +380,51 @@ export interface Tool {
|
|
|
376
380
|
|
|
377
381
|
/**
|
|
378
382
|
* Plugin-facing tool shape. The narrow surface plugin authors implement;
|
|
379
|
-
* differs from {@link Tool} in
|
|
383
|
+
* differs from {@link Tool} in four ways:
|
|
380
384
|
* - Plugins declare `input_schema` as a top-level field instead of
|
|
381
385
|
* implementing `getDefinition()`. The registration boundary synthesizes
|
|
382
386
|
* `getDefinition()` from `{name, description, input_schema}` before the
|
|
383
387
|
* tool enters the internal registry.
|
|
388
|
+
* - `name` is derived from the tool file's basename by the external plugin
|
|
389
|
+
* loader.
|
|
384
390
|
* - `category` is registry-owned and stamped to `"plugin"` when the tool is
|
|
385
391
|
* registered.
|
|
386
392
|
* - All ownership stamps (`origin`, `ownerPluginId`, etc.) are set
|
|
387
393
|
* authoritatively by the bootstrap; plugin authors leave them blank.
|
|
394
|
+
*
|
|
395
|
+
* Every author-visible field is optional. The loader fills the four
|
|
396
|
+
* normally-required slots (`description`, `defaultRiskLevel`,
|
|
397
|
+
* `input_schema`, `execute`) with documented defaults when a plugin omits
|
|
398
|
+
* them — see `applyPluginToolDefaults` in `external-plugin-loader.ts`.
|
|
399
|
+
* A nameless, body-less `export default {}` is a valid (if useless) tool;
|
|
400
|
+
* misconfigured tools surface at call time rather than blocking plugin
|
|
401
|
+
* load.
|
|
402
|
+
*/
|
|
403
|
+
export type PluginTool = Omit<
|
|
404
|
+
Tool,
|
|
405
|
+
"category" | "getDefinition" | "name" | "description" | "defaultRiskLevel"
|
|
406
|
+
> & {
|
|
407
|
+
description?: string;
|
|
408
|
+
defaultRiskLevel?: RiskLevel;
|
|
409
|
+
input_schema?: object;
|
|
410
|
+
execute?: (
|
|
411
|
+
input: Record<string, unknown>,
|
|
412
|
+
context: ToolContext,
|
|
413
|
+
) => Promise<ToolExecutionResult>;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Plugin tool after the external loader has derived its registry name and
|
|
418
|
+
* filled defaults for any author-omitted fields. All four normally-required
|
|
419
|
+
* slots are guaranteed present.
|
|
388
420
|
*/
|
|
389
|
-
export type
|
|
421
|
+
export type LoadedPluginTool = PluginTool & {
|
|
422
|
+
name: string;
|
|
423
|
+
description: string;
|
|
424
|
+
defaultRiskLevel: RiskLevel;
|
|
390
425
|
input_schema: object;
|
|
426
|
+
execute: (
|
|
427
|
+
input: Record<string, unknown>,
|
|
428
|
+
context: ToolContext,
|
|
429
|
+
) => Promise<ToolExecutionResult>;
|
|
391
430
|
};
|
|
@@ -36,7 +36,8 @@ export const uiShowTool: Tool = {
|
|
|
36
36
|
'- list: { items: [{ id, title, subtitle?, icon?, selected? }], selectionMode: "single"|"multiple"|"none" }\n' +
|
|
37
37
|
"- confirmation: { message, detail?, confirmLabel?, confirmedLabel?, cancelLabel?, destructive? }\n" +
|
|
38
38
|
"- dynamic_page: { html, width?, height?, preview?: { title, subtitle?, description?, icon?, metrics?: [{ label, value }] } }\n" +
|
|
39
|
-
"- file_upload: { prompt, acceptedTypes?, maxFiles? }\n
|
|
39
|
+
"- file_upload: { prompt, acceptedTypes?, maxFiles? }\n" +
|
|
40
|
+
"- task_preferences: {} (no data needed — categories are rendered client-side)\n\n" +
|
|
40
41
|
"Proactively show a task_progress card before multi-step or long-running work (web searches, file operations, research). Show it before your first tool call, then update steps as work progresses.",
|
|
41
42
|
category: "ui-surface",
|
|
42
43
|
defaultRiskLevel: RiskLevel.Low,
|
|
@@ -59,6 +60,7 @@ export const uiShowTool: Tool = {
|
|
|
59
60
|
"confirmation",
|
|
60
61
|
"dynamic_page",
|
|
61
62
|
"file_upload",
|
|
63
|
+
"task_preferences",
|
|
62
64
|
],
|
|
63
65
|
description: "The type of surface to display",
|
|
64
66
|
},
|
|
@@ -4,6 +4,10 @@ export interface OnboardingContext {
|
|
|
4
4
|
tone: string;
|
|
5
5
|
userName?: string;
|
|
6
6
|
assistantName?: string;
|
|
7
|
+
priorAssistants?: string[];
|
|
7
8
|
googleConnected?: boolean;
|
|
8
9
|
googleScopes?: string[];
|
|
10
|
+
cohort?: string;
|
|
11
|
+
websiteUrl?: string;
|
|
12
|
+
contentSourceUrl?: string;
|
|
9
13
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { faviconUrlForDomain } from "../favicon.js";
|
|
4
|
+
|
|
5
|
+
describe("faviconUrlForDomain", () => {
|
|
6
|
+
test("returns a properly encoded s2 URL for a valid host", () => {
|
|
7
|
+
expect(faviconUrlForDomain("example.com")).toBe(
|
|
8
|
+
"https://www.google.com/s2/favicons?domain=example.com&sz=64",
|
|
9
|
+
);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("lowercases mixed-case hosts before encoding", () => {
|
|
13
|
+
expect(faviconUrlForDomain("Example.COM")).toBe(
|
|
14
|
+
"https://www.google.com/s2/favicons?domain=example.com&sz=64",
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("returns undefined for empty input", () => {
|
|
19
|
+
expect(faviconUrlForDomain("")).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("returns undefined for whitespace-only input", () => {
|
|
23
|
+
expect(faviconUrlForDomain(" ")).toBeUndefined();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("returns undefined for hosts containing a slash", () => {
|
|
27
|
+
expect(faviconUrlForDomain("example.com/path")).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("returns undefined for hosts containing a space", () => {
|
|
31
|
+
expect(faviconUrlForDomain("example .com")).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("URL-encodes unicode/IDN hosts", () => {
|
|
35
|
+
// Punycode-style raw unicode host should be percent-encoded by encodeURIComponent.
|
|
36
|
+
const result = faviconUrlForDomain("münchen.de");
|
|
37
|
+
expect(result).toBe(
|
|
38
|
+
`https://www.google.com/s2/favicons?domain=${encodeURIComponent("münchen.de")}&sz=64`,
|
|
39
|
+
);
|
|
40
|
+
// Sanity check: the encoded form contains percent-encoded bytes for "ü".
|
|
41
|
+
expect(result).toContain("m%C3%BCnchen.de");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("returns undefined for localhost", () => {
|
|
45
|
+
expect(faviconUrlForDomain("localhost")).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("returns undefined for private IPv4 hosts", () => {
|
|
49
|
+
expect(faviconUrlForDomain("127.0.0.1")).toBeUndefined();
|
|
50
|
+
expect(faviconUrlForDomain("10.0.0.5")).toBeUndefined();
|
|
51
|
+
expect(faviconUrlForDomain("192.168.1.1")).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("returns undefined for any raw IPv4 literal — private or public", () => {
|
|
55
|
+
// We can't tell from the host alone whether an IP belongs to a routable
|
|
56
|
+
// public host or an internal one, so all IP literals are rejected to avoid
|
|
57
|
+
// leaking the address to Google when the client renders the icon.
|
|
58
|
+
expect(faviconUrlForDomain("172.16.0.1")).toBeUndefined();
|
|
59
|
+
expect(faviconUrlForDomain("8.8.8.8")).toBeUndefined();
|
|
60
|
+
expect(faviconUrlForDomain("1.1.1.1")).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("returns undefined for raw IPv6 literals (bracketed or bare)", () => {
|
|
64
|
+
expect(faviconUrlForDomain("2001:db8::1")).toBeUndefined();
|
|
65
|
+
expect(faviconUrlForDomain("[2001:db8::1]")).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("strips :port before the private-host check (host:port → undefined for private)", () => {
|
|
69
|
+
expect(faviconUrlForDomain("localhost:3000")).toBeUndefined();
|
|
70
|
+
expect(faviconUrlForDomain("127.0.0.1:8080")).toBeUndefined();
|
|
71
|
+
expect(faviconUrlForDomain("192.168.1.1:443")).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("strips :port and encodes only the host (public host with port)", () => {
|
|
75
|
+
const result = faviconUrlForDomain("example.com:8080");
|
|
76
|
+
expect(result).toBe(
|
|
77
|
+
"https://www.google.com/s2/favicons?domain=example.com&sz=64",
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("handles bracketed IPv6 hosts with ports", () => {
|
|
82
|
+
expect(faviconUrlForDomain("[::1]:8080")).toBeUndefined();
|
|
83
|
+
});
|
|
84
|
+
});
|