@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
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* | `memory-v2-static` | 38 | after-memory-prefix |
|
|
21
21
|
* | `now-md` | 40 | after-memory-prefix |
|
|
22
22
|
* | `active-documents` | 45 | prepend-user-tail |
|
|
23
|
+
* | `document-comments` | 46 | prepend-user-tail |
|
|
23
24
|
* | `subagent-status` | 50 | append-user-tail |
|
|
24
25
|
* | `slack-messages` | 60 | replace-run-messages |
|
|
25
26
|
* | `thread-focus` | 70 | append-user-tail |
|
|
@@ -51,6 +52,7 @@ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-fl
|
|
|
51
52
|
import { getConfig } from "../../config/loader.js";
|
|
52
53
|
import { getInContextPkbPaths } from "../../daemon/pkb-context-tracker.js";
|
|
53
54
|
import { buildPkbReminder } from "../../daemon/pkb-reminder-builder.js";
|
|
55
|
+
import { listComments } from "../../documents/document-comments-store.js";
|
|
54
56
|
import { searchPkbFiles } from "../../memory/pkb/pkb-search.js";
|
|
55
57
|
import { getLogger } from "../../util/logger.js";
|
|
56
58
|
import { registerPlugin } from "../registry.js";
|
|
@@ -87,12 +89,14 @@ const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
|
|
|
87
89
|
export const DEFAULT_INJECTOR_ORDER = {
|
|
88
90
|
diskPressureWarning: 5,
|
|
89
91
|
workspaceContext: 10,
|
|
92
|
+
backgroundTurn: 15,
|
|
90
93
|
unifiedTurnContext: 20,
|
|
91
94
|
pkbContext: 30,
|
|
92
95
|
pkbReminder: 35,
|
|
93
96
|
memoryV2Static: 38,
|
|
94
97
|
nowMd: 40,
|
|
95
98
|
activeDocuments: 45,
|
|
99
|
+
documentComments: 46,
|
|
96
100
|
subagentStatus: 50,
|
|
97
101
|
slackMessages: 60,
|
|
98
102
|
threadFocus: 70,
|
|
@@ -132,12 +136,11 @@ const diskPressureWarningInjector: Injector = {
|
|
|
132
136
|
};
|
|
133
137
|
|
|
134
138
|
/**
|
|
135
|
-
* v2 read-side cutover guard.
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* state independent of PKB and fires unchanged.
|
|
139
|
+
* v2 read-side cutover guard. Under v2 both `pkb-context` and `pkb-reminder`
|
|
140
|
+
* silence themselves entirely — the `<knowledge_base>` content and the
|
|
141
|
+
* generic recall/remember nudge are both supplanted by the v2 static
|
|
142
|
+
* `<memory>` block. NOW.md is workspace state independent of PKB and fires
|
|
143
|
+
* unchanged.
|
|
141
144
|
*/
|
|
142
145
|
function isPkbInjectionSilencedByV2(): boolean {
|
|
143
146
|
return getConfig().memory.v2.enabled;
|
|
@@ -171,6 +174,39 @@ const workspaceContextInjector: Injector = {
|
|
|
171
174
|
},
|
|
172
175
|
};
|
|
173
176
|
|
|
177
|
+
/**
|
|
178
|
+
* `background-turn` injector — order 15, prepend-user-tail.
|
|
179
|
+
*
|
|
180
|
+
* Wraps the tail user message with a `<background_turn>` block that tells
|
|
181
|
+
* the assistant the guardian isn't watching and that anything noteworthy
|
|
182
|
+
* should be surfaced via the `notifications` skill. Fires only when (a) the
|
|
183
|
+
* conversation's type is "background" or "scheduled" (see
|
|
184
|
+
* `isBackgroundConversationType`) AND (b) no client is currently connected
|
|
185
|
+
* (`isNonInteractive`). The second gate is what prevents the reminder from
|
|
186
|
+
* firing on a manual follow-up the guardian sends into a background thread
|
|
187
|
+
* — at that point the guardian IS watching, so the framing doesn't apply.
|
|
188
|
+
*
|
|
189
|
+
* The inner text is read from `config.conversations.backgroundInjection`, so
|
|
190
|
+
* operators can edit the reminder without a code change. Setting it to the
|
|
191
|
+
* empty string disables the injection entirely.
|
|
192
|
+
*/
|
|
193
|
+
const backgroundTurnInjector: Injector = {
|
|
194
|
+
name: "background-turn",
|
|
195
|
+
order: DEFAULT_INJECTOR_ORDER.backgroundTurn,
|
|
196
|
+
async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
|
|
197
|
+
const inputs = readInjectionInputs(ctx);
|
|
198
|
+
if (!inputs.isBackgroundConversation) return null;
|
|
199
|
+
if (!inputs.isNonInteractive) return null;
|
|
200
|
+
const inner = getConfig().conversations.backgroundInjection;
|
|
201
|
+
if (!inner) return null;
|
|
202
|
+
return {
|
|
203
|
+
id: "background-turn",
|
|
204
|
+
text: `<background_turn>\n${inner}\n</background_turn>`,
|
|
205
|
+
placement: "prepend-user-tail",
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
|
|
174
210
|
/**
|
|
175
211
|
* `unified-turn-context` injector — order 20, prepend-user-tail.
|
|
176
212
|
*
|
|
@@ -253,24 +289,8 @@ const pkbReminderInjector: Injector = {
|
|
|
253
289
|
const mode = inputs.mode ?? "full";
|
|
254
290
|
if (mode !== "full") return null;
|
|
255
291
|
if (!inputs.pkbActive) return null;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
// calls miss. When that backstop is on, the per-turn pressure to call
|
|
259
|
-
// `remember` softens to a judgment framing. When it's off, the original
|
|
260
|
-
// high-pressure BODY is used so users without the retrospective still
|
|
261
|
-
// get aggressive capture in-conversation.
|
|
262
|
-
let relaxed = false;
|
|
263
|
-
try {
|
|
264
|
-
relaxed = isAssistantFeatureFlagEnabled(
|
|
265
|
-
"memory-retrospective",
|
|
266
|
-
getConfig(),
|
|
267
|
-
);
|
|
268
|
-
} catch {
|
|
269
|
-
// Best-effort — fall back to the default (non-relaxed) BODY.
|
|
270
|
-
}
|
|
271
|
-
const reminder = isPkbInjectionSilencedByV2()
|
|
272
|
-
? buildPkbReminder([], relaxed)
|
|
273
|
-
: await buildPkbReminderWithHints(inputs, relaxed);
|
|
292
|
+
if (isPkbInjectionSilencedByV2()) return null;
|
|
293
|
+
const reminder = await buildPkbReminderWithHints(inputs);
|
|
274
294
|
return {
|
|
275
295
|
id: "pkb-reminder",
|
|
276
296
|
text: reminder,
|
|
@@ -300,7 +320,6 @@ function buildPkbContextBlock(content: string): string {
|
|
|
300
320
|
*/
|
|
301
321
|
async function buildPkbReminderWithHints(
|
|
302
322
|
inputs: TurnInjectionInputs,
|
|
303
|
-
relaxed: boolean,
|
|
304
323
|
): Promise<string> {
|
|
305
324
|
let hints: string[] = [];
|
|
306
325
|
const queryVector = inputs.pkbQueryVector;
|
|
@@ -361,7 +380,7 @@ async function buildPkbReminderWithHints(
|
|
|
361
380
|
hints = [];
|
|
362
381
|
}
|
|
363
382
|
}
|
|
364
|
-
return buildPkbReminder(hints
|
|
383
|
+
return buildPkbReminder(hints);
|
|
365
384
|
}
|
|
366
385
|
|
|
367
386
|
/**
|
|
@@ -473,6 +492,77 @@ const activeDocumentsInjector: Injector = {
|
|
|
473
492
|
},
|
|
474
493
|
};
|
|
475
494
|
|
|
495
|
+
/** Maximum open comments surfaced per document to limit context bloat. */
|
|
496
|
+
const DOCUMENT_COMMENTS_CAP = 10;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Escape closing `</document_comments>` inside user-controlled strings so
|
|
500
|
+
* they cannot break out of the XML wrapper — same pattern as
|
|
501
|
+
* {@link buildPkbContextBlock} and {@link buildMemoryV2StaticBlock}.
|
|
502
|
+
*/
|
|
503
|
+
function escapeDocCommentTag(s: string): string {
|
|
504
|
+
return s.replace(/<\/document_comments\s*>/gi, "</document_comments>");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* `document-comments` injector — order 46, prepend-user-tail.
|
|
509
|
+
*
|
|
510
|
+
* Surfaces open top-level comments on active documents so the assistant
|
|
511
|
+
* knows what feedback to address. For each active document, queries the
|
|
512
|
+
* comment store for open top-level comments (capped at
|
|
513
|
+
* {@link DOCUMENT_COMMENTS_CAP} most recent per document). Inline comments
|
|
514
|
+
* include the quoted anchor text; doc-level comments are labelled as such.
|
|
515
|
+
*
|
|
516
|
+
* Gating:
|
|
517
|
+
* - `mode === "full"`.
|
|
518
|
+
* - `activeDocuments` has at least one entry.
|
|
519
|
+
* - At least one document has open comments (returns null otherwise).
|
|
520
|
+
*/
|
|
521
|
+
const documentCommentsInjector: Injector = {
|
|
522
|
+
name: "document-comments",
|
|
523
|
+
order: DEFAULT_INJECTOR_ORDER.documentComments,
|
|
524
|
+
async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
|
|
525
|
+
const inputs = readInjectionInputs(ctx);
|
|
526
|
+
const mode = inputs.mode ?? "full";
|
|
527
|
+
if (mode !== "full") return null;
|
|
528
|
+
const docs = inputs.activeDocuments;
|
|
529
|
+
if (!docs || docs.length === 0) return null;
|
|
530
|
+
|
|
531
|
+
const sections: string[] = [];
|
|
532
|
+
for (const doc of docs) {
|
|
533
|
+
const comments = listComments(doc.surfaceId, {
|
|
534
|
+
status: "open",
|
|
535
|
+
topLevelOnly: true,
|
|
536
|
+
}).slice(-DOCUMENT_COMMENTS_CAP);
|
|
537
|
+
if (comments.length === 0) continue;
|
|
538
|
+
|
|
539
|
+
const lines = comments.map((c) => {
|
|
540
|
+
const anchor =
|
|
541
|
+
c.anchorText != null ? escapeDocCommentTag(c.anchorText) : null;
|
|
542
|
+
const label =
|
|
543
|
+
anchor != null ? `inline, anchored to "${anchor}"` : "doc-level";
|
|
544
|
+
return `- Comment #${c.id} (${label}): "${escapeDocCommentTag(c.content)}"`;
|
|
545
|
+
});
|
|
546
|
+
sections.push(
|
|
547
|
+
`Document: "${escapeDocCommentTag(doc.title)}" (surface_id: "${doc.surfaceId}")\n${lines.join("\n")}`,
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (sections.length === 0) return null;
|
|
552
|
+
|
|
553
|
+
const text = `<document_comments>
|
|
554
|
+
Open comments on your documents. Address these by editing the document, then use comment_resolve to mark each resolved.
|
|
555
|
+
|
|
556
|
+
${sections.join("\n\n")}
|
|
557
|
+
</document_comments>`;
|
|
558
|
+
return {
|
|
559
|
+
id: "document-comments",
|
|
560
|
+
text,
|
|
561
|
+
placement: "prepend-user-tail",
|
|
562
|
+
};
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
|
|
476
566
|
/**
|
|
477
567
|
* `subagent-status` injector — order 50, append-user-tail.
|
|
478
568
|
*
|
|
@@ -601,12 +691,14 @@ export const defaultInjectorsPlugin: Plugin = {
|
|
|
601
691
|
injectors: [
|
|
602
692
|
diskPressureWarningInjector,
|
|
603
693
|
workspaceContextInjector,
|
|
694
|
+
backgroundTurnInjector,
|
|
604
695
|
unifiedTurnContextInjector,
|
|
605
696
|
pkbContextInjector,
|
|
606
697
|
pkbReminderInjector,
|
|
607
698
|
memoryV2StaticInjector,
|
|
608
699
|
nowMdInjector,
|
|
609
700
|
activeDocumentsInjector,
|
|
701
|
+
documentCommentsInjector,
|
|
610
702
|
subagentStatusInjector,
|
|
611
703
|
slackMessagesInjector,
|
|
612
704
|
threadFocusInjector,
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
* other filenames sit in the map for
|
|
24
24
|
* forward compatibility)
|
|
25
25
|
* tools/
|
|
26
|
-
* *.ts ← each
|
|
26
|
+
* *.ts ← each default export → plugin.tools[];
|
|
27
|
+
* runtime name derives from the filename
|
|
28
|
+
* basename
|
|
27
29
|
* src/ ← internal helpers, ignored by the loader
|
|
28
30
|
*
|
|
29
31
|
* Per-surface, `.js` is preferred over `.ts` (compiled-binary semantics).
|
|
@@ -47,6 +49,12 @@ import semver from "semver";
|
|
|
47
49
|
import { z } from "zod";
|
|
48
50
|
|
|
49
51
|
import assistantPkg from "../../package.json" with { type: "json" };
|
|
52
|
+
import type {
|
|
53
|
+
LoadedPluginTool,
|
|
54
|
+
PluginTool,
|
|
55
|
+
RiskLevel,
|
|
56
|
+
ToolExecutionResult,
|
|
57
|
+
} from "../tools/types.js";
|
|
50
58
|
import { getLogger } from "../util/logger.js";
|
|
51
59
|
import { registerPlugin } from "./registry.js";
|
|
52
60
|
import type {
|
|
@@ -106,6 +114,72 @@ function stripScope(name: string): string {
|
|
|
106
114
|
return match ? match[1]! : name;
|
|
107
115
|
}
|
|
108
116
|
|
|
117
|
+
function toToolNameSegment(value: string): string {
|
|
118
|
+
return value.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "tool";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function deriveToolName(toolFileBaseName: string): string {
|
|
122
|
+
return toToolNameSegment(toolFileBaseName);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Defaults applied by {@link applyPluginToolDefaults} when a plugin tool
|
|
127
|
+
* omits one of the normally-required fields. Exported as a constant so
|
|
128
|
+
* tests and callers can reference the same source of truth.
|
|
129
|
+
*
|
|
130
|
+
* The default `execute` returns an error result so the model sees a clear
|
|
131
|
+
* "this tool isn't wired up" signal at call time. The plugin still loads
|
|
132
|
+
* cleanly — broken individual tools must never block daemon boot.
|
|
133
|
+
*/
|
|
134
|
+
export const PLUGIN_TOOL_DEFAULTS = Object.freeze({
|
|
135
|
+
description: "",
|
|
136
|
+
defaultRiskLevel: "medium" as RiskLevel,
|
|
137
|
+
input_schema: Object.freeze({
|
|
138
|
+
type: "object",
|
|
139
|
+
properties: {},
|
|
140
|
+
additionalProperties: false,
|
|
141
|
+
}) as object,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Fill the four normally-required {@link PluginTool} fields with documented
|
|
146
|
+
* defaults when the author omitted them. Returns a {@link LoadedPluginTool}
|
|
147
|
+
* that is safe to register.
|
|
148
|
+
*/
|
|
149
|
+
function applyPluginToolDefaults(
|
|
150
|
+
tool: PluginTool,
|
|
151
|
+
name: string,
|
|
152
|
+
): LoadedPluginTool {
|
|
153
|
+
const description =
|
|
154
|
+
typeof tool.description === "string"
|
|
155
|
+
? tool.description
|
|
156
|
+
: PLUGIN_TOOL_DEFAULTS.description;
|
|
157
|
+
const defaultRiskLevel =
|
|
158
|
+
typeof tool.defaultRiskLevel === "string"
|
|
159
|
+
? tool.defaultRiskLevel
|
|
160
|
+
: PLUGIN_TOOL_DEFAULTS.defaultRiskLevel;
|
|
161
|
+
const input_schema =
|
|
162
|
+
tool.input_schema !== null &&
|
|
163
|
+
typeof tool.input_schema === "object"
|
|
164
|
+
? tool.input_schema
|
|
165
|
+
: PLUGIN_TOOL_DEFAULTS.input_schema;
|
|
166
|
+
const execute =
|
|
167
|
+
typeof tool.execute === "function"
|
|
168
|
+
? tool.execute
|
|
169
|
+
: async (): Promise<ToolExecutionResult> => ({
|
|
170
|
+
content: `plugin tool ${name} has no execute implementation`,
|
|
171
|
+
isError: true,
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
...tool,
|
|
175
|
+
name,
|
|
176
|
+
description,
|
|
177
|
+
defaultRiskLevel,
|
|
178
|
+
input_schema,
|
|
179
|
+
execute,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
109
183
|
/**
|
|
110
184
|
* Dynamic-import `absolutePath` and return its default export. Throws when
|
|
111
185
|
* the module has no default export — callers attribute the error.
|
|
@@ -266,18 +340,16 @@ async function buildPluginFromDir(pluginDir: string): Promise<Plugin> {
|
|
|
266
340
|
if (hooks !== undefined) plugin.hooks = hooks;
|
|
267
341
|
|
|
268
342
|
const tools: PluginToolRegistration[] = [];
|
|
269
|
-
for (const { path: toolPath } of listSurfaceDir(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
typeof (tool as { name?: unknown }).name !== "string"
|
|
275
|
-
) {
|
|
343
|
+
for (const { name: toolName, path: toolPath } of listSurfaceDir(
|
|
344
|
+
join(pluginDir, "tools"),
|
|
345
|
+
)) {
|
|
346
|
+
const tool = await importDefault<PluginTool>(toolPath);
|
|
347
|
+
if (tool === null || typeof tool !== "object") {
|
|
276
348
|
throw new Error(
|
|
277
|
-
`external plugin ${name}: ${toolPath} default export must be
|
|
349
|
+
`external plugin ${name}: ${toolPath} default export must be an object`,
|
|
278
350
|
);
|
|
279
351
|
}
|
|
280
|
-
tools.push(tool);
|
|
352
|
+
tools.push(applyPluginToolDefaults(tool, deriveToolName(toolName)));
|
|
281
353
|
}
|
|
282
354
|
if (tools.length > 0) plugin.tools = tools;
|
|
283
355
|
|
package/src/plugins/types.ts
CHANGED
|
@@ -43,7 +43,7 @@ import type {
|
|
|
43
43
|
} from "../providers/types.js";
|
|
44
44
|
import type { SkillRoute } from "../runtime/skill-route-registry.js";
|
|
45
45
|
import type {
|
|
46
|
-
|
|
46
|
+
LoadedPluginTool,
|
|
47
47
|
ToolContext,
|
|
48
48
|
ToolExecutionResult,
|
|
49
49
|
} from "../tools/types.js";
|
|
@@ -839,6 +839,13 @@ export interface TurnInjectionInputs {
|
|
|
839
839
|
* knows no human is present to answer clarification questions.
|
|
840
840
|
*/
|
|
841
841
|
readonly isNonInteractive?: boolean;
|
|
842
|
+
/**
|
|
843
|
+
* True when the active conversation's type is "background" or "scheduled"
|
|
844
|
+
* (see `isBackgroundConversationType`). Read by the `background-turn`
|
|
845
|
+
* injector to wrap the tail user message with a contextual reminder when
|
|
846
|
+
* the turn is also non-interactive.
|
|
847
|
+
*/
|
|
848
|
+
readonly isBackgroundConversation?: boolean;
|
|
842
849
|
/**
|
|
843
850
|
* Active documents open in this conversation — surfaced by the
|
|
844
851
|
* `active-documents` injector so the assistant can target existing docs
|
|
@@ -1002,15 +1009,17 @@ export interface Injector {
|
|
|
1002
1009
|
|
|
1003
1010
|
/**
|
|
1004
1011
|
* Tool registration contributed by a plugin. Uses the narrow
|
|
1005
|
-
* {@link
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1012
|
+
* {@link LoadedPluginTool} shape. External plugin authors declare the
|
|
1013
|
+
* nameless `PluginTool` file shape; the loader derives `name` from the
|
|
1014
|
+
* `tools/<name>.ts` basename before storing it on `plugin.tools`. Authors
|
|
1015
|
+
* also leave category / ownership metadata to the bootstrap, which stamps
|
|
1016
|
+
* `category: "plugin"`, `origin: "plugin"`, and
|
|
1017
|
+
* `ownerPluginId: <plugin.name>` before handing the batch to
|
|
1018
|
+
* `registerPluginTools`. The registration boundary synthesizes
|
|
1010
1019
|
* `getDefinition()` from `{name, description, input_schema}` so the canonical
|
|
1011
1020
|
* {@link Tool} interface used by the internal registry stays unchanged.
|
|
1012
1021
|
*/
|
|
1013
|
-
export type PluginToolRegistration =
|
|
1022
|
+
export type PluginToolRegistration = LoadedPluginTool;
|
|
1014
1023
|
/**
|
|
1015
1024
|
* HTTP route registration contributed by a plugin. Plugins express routes as
|
|
1016
1025
|
* {@link SkillRoute} values — the same shape the skill-route registry
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
* absent unless the flag is explicitly true.
|
|
2
|
+
* Smoke tests for buildSystemPrompt — covers tool-routing-guidance
|
|
3
|
+
* exclusions and other call-shape invariants. Background-conversation
|
|
4
|
+
* guidance is no longer rendered into the system prompt; see
|
|
5
|
+
* `__tests__/injector-background-turn.test.ts` for the per-turn
|
|
6
|
+
* user-message injection that replaced it.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
|
-
import { mkdirSync } from "node:fs";
|
|
9
|
+
import { copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
11
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
12
12
|
|
|
13
13
|
const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
|
|
@@ -58,60 +58,59 @@ mock.module("../../config/loader.js", () => ({
|
|
|
58
58
|
setNestedValue: () => {},
|
|
59
59
|
}));
|
|
60
60
|
|
|
61
|
-
const { buildSystemPrompt,
|
|
61
|
+
const { buildSystemPrompt, maybeReseedBootstrapForCohort } =
|
|
62
62
|
await import("../system-prompt.js");
|
|
63
63
|
|
|
64
|
-
describe("buildSystemPrompt —
|
|
64
|
+
describe("buildSystemPrompt — tool routing guidance", () => {
|
|
65
65
|
beforeEach(() => {
|
|
66
66
|
mkdirSync(TEST_DIR, { recursive: true });
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
test("
|
|
70
|
-
const result = buildSystemPrompt({
|
|
71
|
-
expect(result).toContain("##
|
|
72
|
-
expect(result).toContain("
|
|
73
|
-
expect(result).toContain("assistant notifications send");
|
|
69
|
+
test("does not include ask_question routing guidance", () => {
|
|
70
|
+
const result = buildSystemPrompt({});
|
|
71
|
+
expect(result).not.toContain("## Clarifying questions");
|
|
72
|
+
expect(result).not.toContain("ask_question");
|
|
74
73
|
});
|
|
74
|
+
});
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
expect(result).not.toContain("## Background Conversation");
|
|
79
|
-
});
|
|
76
|
+
describe("maybeReseedBootstrapForCohort — content-automation template", () => {
|
|
77
|
+
const templatesDir = join(import.meta.dirname!, "..", "templates");
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
beforeEach(() => {
|
|
80
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
81
|
+
// Seed the workspace with the generic BOOTSTRAP.md so the cohort
|
|
82
|
+
// reseed detects it as an unmodified template and overwrites it.
|
|
83
|
+
copyFileSync(
|
|
84
|
+
join(templatesDir, "BOOTSTRAP.md"),
|
|
85
|
+
join(TEST_DIR, "BOOTSTRAP.md"),
|
|
86
|
+
);
|
|
84
87
|
});
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
function reseedAndRead(): string {
|
|
90
|
+
maybeReseedBootstrapForCohort("content-automation");
|
|
91
|
+
return readFileSync(join(TEST_DIR, "BOOTSTRAP.md"), "utf-8");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
test("loads the geo-writing skill on first turn", () => {
|
|
95
|
+
const content = reseedAndRead();
|
|
96
|
+
expect(content).toContain("geo-writing");
|
|
89
97
|
});
|
|
90
98
|
|
|
91
|
-
test("
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const result = buildSystemPrompt({ isBackgroundConversation: true });
|
|
96
|
-
const boundaryIdx = result.indexOf(SYSTEM_PROMPT_CACHE_BOUNDARY);
|
|
97
|
-
expect(boundaryIdx).toBeGreaterThan(-1);
|
|
98
|
-
const staticBlock = result.slice(0, boundaryIdx);
|
|
99
|
-
const dynamicBlock = result.slice(
|
|
100
|
-
boundaryIdx + SYSTEM_PROMPT_CACHE_BOUNDARY.length,
|
|
101
|
-
);
|
|
102
|
-
expect(staticBlock).toContain("## Background Conversation");
|
|
103
|
-
expect(dynamicBlock).not.toContain("## Background Conversation");
|
|
99
|
+
test("uses skill-first onboarding approach", () => {
|
|
100
|
+
const content = reseedAndRead();
|
|
101
|
+
expect(content).toContain("Skill-First Onboarding");
|
|
102
|
+
expect(content).toContain("The skill is the onboarding");
|
|
104
103
|
});
|
|
105
|
-
});
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
test("includes comment-driven edit loop", () => {
|
|
106
|
+
const content = reseedAndRead();
|
|
107
|
+
expect(content).toContain("comment-driven");
|
|
108
|
+
expect(content).toContain("comment_resolve");
|
|
109
|
+
expect(content).toContain("document_update");
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
test("
|
|
113
|
-
const
|
|
114
|
-
expect(
|
|
115
|
-
expect(result).not.toContain("ask_question");
|
|
112
|
+
test("references VOICE.md for voice capture", () => {
|
|
113
|
+
const content = reseedAndRead();
|
|
114
|
+
expect(content).toContain("VOICE.md");
|
|
116
115
|
});
|
|
117
116
|
});
|
|
@@ -74,18 +74,14 @@ describe("task_progress hint in parallel-tool-calls section", () => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
test("renders regardless of options passed", () => {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
const withoutBackground = buildSystemPrompt({
|
|
81
|
-
isBackgroundConversation: false,
|
|
82
|
-
});
|
|
77
|
+
const withClientFlag = buildSystemPrompt({ hasNoClient: true });
|
|
78
|
+
const withoutClientFlag = buildSystemPrompt({ hasNoClient: false });
|
|
83
79
|
const withExcludePrefix = buildSystemPrompt({
|
|
84
80
|
excludeCustomPrefix: true,
|
|
85
81
|
});
|
|
86
82
|
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
83
|
+
expect(withClientFlag).toContain("task_progress");
|
|
84
|
+
expect(withoutClientFlag).toContain("task_progress");
|
|
89
85
|
expect(withExcludePrefix).toContain("task_progress");
|
|
90
86
|
});
|
|
91
87
|
|
|
@@ -19,6 +19,20 @@ export const TOOL_DISPLAY_NAMES: Record<string, string> = {
|
|
|
19
19
|
"apple-notes": "Apple Notes",
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Map of known prior-assistant IDs (from the client onboarding UI) to display names.
|
|
24
|
+
* Unknown IDs pass through with first-letter capitalization via `normalizePriorAssistants`.
|
|
25
|
+
*/
|
|
26
|
+
export const PRIOR_ASSISTANT_DISPLAY_NAMES: Record<string, string> = {
|
|
27
|
+
chatgpt: "ChatGPT",
|
|
28
|
+
claude: "Claude",
|
|
29
|
+
openclaw: "OpenClaw",
|
|
30
|
+
hermes: "Hermes",
|
|
31
|
+
manus: "Manus",
|
|
32
|
+
gemini: "Gemini",
|
|
33
|
+
copilot: "Copilot",
|
|
34
|
+
};
|
|
35
|
+
|
|
22
36
|
/**
|
|
23
37
|
* Map of known task IDs to plain-language labels describing what the assistant
|
|
24
38
|
* does for each task category.
|
|
@@ -56,14 +70,28 @@ export function normalizeTasks(tasks: string[]): string[] {
|
|
|
56
70
|
return tasks.map((id) => TASK_DISPLAY_LABELS[id] ?? id);
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Maps each prior-assistant ID through `PRIOR_ASSISTANT_DISPLAY_NAMES`,
|
|
75
|
+
* falling back to first-letter capitalization for unknown IDs.
|
|
76
|
+
*/
|
|
77
|
+
export function normalizePriorAssistants(assistants: string[]): string[] {
|
|
78
|
+
return assistants.map(
|
|
79
|
+
(id) => PRIOR_ASSISTANT_DISPLAY_NAMES[id] ?? capitalizeFirst(id),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
export interface NormalizedOnboarding {
|
|
60
84
|
preferredName?: string;
|
|
61
85
|
commonWork: string[];
|
|
62
86
|
dailyTools: string[];
|
|
63
87
|
tone?: string;
|
|
64
88
|
assistantName?: string;
|
|
89
|
+
priorAssistants?: string[];
|
|
65
90
|
googleConnected?: boolean;
|
|
66
91
|
googleServices?: string[];
|
|
92
|
+
cohort?: string;
|
|
93
|
+
websiteUrl?: string;
|
|
94
|
+
contentSourceUrl?: string;
|
|
67
95
|
}
|
|
68
96
|
|
|
69
97
|
const SCOPE_SERVICE_MAP: Record<string, string> = {
|
|
@@ -103,5 +131,17 @@ export function normalizeOnboardingContext(
|
|
|
103
131
|
googleServices: ctx.googleConnected
|
|
104
132
|
? deriveGoogleServices(ctx.googleScopes)
|
|
105
133
|
: undefined,
|
|
134
|
+
priorAssistants: ctx.priorAssistants?.length
|
|
135
|
+
? normalizePriorAssistants(ctx.priorAssistants)
|
|
136
|
+
: undefined,
|
|
137
|
+
cohort: ctx.cohort,
|
|
138
|
+
websiteUrl:
|
|
139
|
+
typeof ctx.websiteUrl === "string"
|
|
140
|
+
? ctx.websiteUrl.trim().replace(/[\r\n\t]/g, "") || undefined
|
|
141
|
+
: undefined,
|
|
142
|
+
contentSourceUrl:
|
|
143
|
+
typeof ctx.contentSourceUrl === "string"
|
|
144
|
+
? ctx.contentSourceUrl.trim().replace(/[\r\n\t]/g, "") || undefined
|
|
145
|
+
: undefined,
|
|
106
146
|
};
|
|
107
147
|
}
|