@vellumai/assistant 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +5 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +325 -3
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +60 -36
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +266 -10
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +55 -13
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +31 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/types.ts +108 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +329 -317
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +38 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/feature-flag-registry.json +41 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +7 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop.ts +169 -9
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +16 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +98 -23
- package/src/daemon/lifecycle.ts +45 -35
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +49 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +1 -1
- package/src/daemon/pkb-reminder-builder.ts +1 -1
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +21 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +41 -0
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +22 -0
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +110 -10
- package/src/memory/db-init.ts +6 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/conversation-graph-memory.ts +31 -15
- package/src/memory/graph/tools.ts +3 -3
- package/src/memory/indexer.ts +34 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/inference.ts +1 -3
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/injection.test.ts +98 -8
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/injection.ts +32 -6
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +35 -5
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/emit-signal.ts +20 -1
- package/src/notifications/home-feed-side-effect.ts +54 -0
- package/src/notifications/signal.ts +3 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +36 -3
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +105 -32
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +31 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +12 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -166
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/providers/__tests__/inference.test.ts +22 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/connection-resolution.ts +7 -0
- package/src/providers/inference/adapter-factory.ts +41 -4
- package/src/providers/inference/connections.ts +74 -29
- package/src/providers/inference/resolve-auth.ts +12 -4
- package/src/providers/model-catalog.ts +294 -12
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/registry.ts +22 -14
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +42 -14
- package/src/runtime/auth/route-policy.ts +8 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-types.ts +19 -0
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +40 -35
- package/src/runtime/routes/conversation-routes.ts +90 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +15 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem watcher for the external plugins directory.
|
|
3
|
+
*
|
|
4
|
+
* Watches `<workspaceDir>/plugins/` recursively using fs.watch (FSEvents on
|
|
5
|
+
* macOS). When a plugin directory is created or modified, debounces per
|
|
6
|
+
* top-level directory name (= the plugin name) and dispatches to the
|
|
7
|
+
* watcher's internal change handler so the daemon can register or reload
|
|
8
|
+
* the plugin without a restart.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors `app-source-watcher.ts` (same DebouncerMap shape, same start/stop
|
|
11
|
+
* lifecycle, same ensureStarted late-create hook), but exposes its lifecycle
|
|
12
|
+
* through a static singleton so tool side-effects can call
|
|
13
|
+
* `PluginSourceWatcher.getInstance().ensureStarted()` directly without an
|
|
14
|
+
* intermediate module-level injection.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type FSWatcher, mkdirSync, watch } from "node:fs";
|
|
18
|
+
|
|
19
|
+
import { DebouncerMap } from "../util/debounce.js";
|
|
20
|
+
import { getLogger } from "../util/logger.js";
|
|
21
|
+
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
22
|
+
import { reregisterExternalPlugin } from "./external-plugins-bootstrap.js";
|
|
23
|
+
|
|
24
|
+
const log = getLogger("plugin-source-watcher");
|
|
25
|
+
|
|
26
|
+
const PLUGIN_SOURCE_DEBOUNCE_MS = 500;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Extract the plugin's top-level directory name from a relative path within
|
|
30
|
+
* the plugins root. Returns null for a stray file directly in `plugins/`
|
|
31
|
+
* (not a plugin dir).
|
|
32
|
+
*/
|
|
33
|
+
function resolvePluginNameFromRelPath(relPath: string): string | null {
|
|
34
|
+
const slashIdx = relPath.indexOf("/");
|
|
35
|
+
if (slashIdx === -1) {
|
|
36
|
+
// Bare entry under plugins/ — fs.watch reports these when a new
|
|
37
|
+
// directory is first created. We treat the name as the plugin name and
|
|
38
|
+
// let the install path decide whether it's a real plugin.
|
|
39
|
+
return relPath.length > 0 ? relPath : null;
|
|
40
|
+
}
|
|
41
|
+
const dirName = relPath.slice(0, slashIdx);
|
|
42
|
+
return dirName.length > 0 ? dirName : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class PluginSourceWatcher {
|
|
46
|
+
/**
|
|
47
|
+
* Process-wide singleton. Callers reach the watcher via
|
|
48
|
+
* {@link PluginSourceWatcher.getInstance} rather than instantiating
|
|
49
|
+
* directly so tool side-effects (`assistant plugins install`) can call
|
|
50
|
+
* `ensureStarted()` on the same watcher the daemon `start()`/`stop()`
|
|
51
|
+
* lifecycle owns, without threading an instance through a registered
|
|
52
|
+
* module-level callback.
|
|
53
|
+
*/
|
|
54
|
+
private static singleton: PluginSourceWatcher | null = null;
|
|
55
|
+
|
|
56
|
+
static getInstance(): PluginSourceWatcher {
|
|
57
|
+
PluginSourceWatcher.singleton ??= new PluginSourceWatcher();
|
|
58
|
+
return PluginSourceWatcher.singleton;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Test-only — drops the singleton so the next `getInstance()` rebuilds. */
|
|
62
|
+
static resetForTests(): void {
|
|
63
|
+
PluginSourceWatcher.singleton?.stop();
|
|
64
|
+
PluginSourceWatcher.singleton = null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private watcher: FSWatcher | null = null;
|
|
68
|
+
private started = false;
|
|
69
|
+
private debouncer = new DebouncerMap({
|
|
70
|
+
defaultDelayMs: PLUGIN_SOURCE_DEBOUNCE_MS,
|
|
71
|
+
maxEntries: 50,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
start(): void {
|
|
75
|
+
this.started = true;
|
|
76
|
+
this.tryWatch();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Ensure the watcher is running. Idempotent — safe to call after a tool
|
|
81
|
+
* side-effect that may have just created the plugins directory.
|
|
82
|
+
* No-op if `start()` has not been called yet.
|
|
83
|
+
*/
|
|
84
|
+
ensureStarted(): void {
|
|
85
|
+
if (!this.started || this.watcher) return;
|
|
86
|
+
this.tryWatch();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
stop(): void {
|
|
90
|
+
this.started = false;
|
|
91
|
+
this.debouncer.cancelAll();
|
|
92
|
+
if (this.watcher) {
|
|
93
|
+
this.watcher.close();
|
|
94
|
+
this.watcher = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private onChange(pluginName: string): Promise<void> {
|
|
99
|
+
return reregisterExternalPlugin(pluginName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private tryWatch(): void {
|
|
103
|
+
if (this.watcher) return;
|
|
104
|
+
|
|
105
|
+
let pluginsDir: string;
|
|
106
|
+
try {
|
|
107
|
+
pluginsDir = getWorkspacePluginsDir();
|
|
108
|
+
} catch {
|
|
109
|
+
log.warn(
|
|
110
|
+
"Could not resolve plugins directory; plugin source watching disabled",
|
|
111
|
+
);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
mkdirSync(pluginsDir, { recursive: true });
|
|
117
|
+
} catch (err) {
|
|
118
|
+
log.warn(
|
|
119
|
+
{ err, pluginsDir },
|
|
120
|
+
"Could not create plugins directory; source watching disabled",
|
|
121
|
+
);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
this.watcher = watch(
|
|
127
|
+
pluginsDir,
|
|
128
|
+
{ recursive: true },
|
|
129
|
+
(_eventType, filename) => {
|
|
130
|
+
if (!filename) return;
|
|
131
|
+
const pluginName = resolvePluginNameFromRelPath(filename);
|
|
132
|
+
if (!pluginName) return;
|
|
133
|
+
this.debouncer.schedule(`plugin:${pluginName}`, () => {
|
|
134
|
+
void this.onChange(pluginName);
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
log.info({ pluginsDir }, "Plugin source watcher started");
|
|
139
|
+
} catch (err) {
|
|
140
|
+
log.warn(
|
|
141
|
+
{ err },
|
|
142
|
+
"Failed to watch plugins directory; source watching disabled",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -30,9 +30,13 @@ import {
|
|
|
30
30
|
import { updateMetaFile } from "../memory/conversation-disk-view.js";
|
|
31
31
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
32
32
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
33
|
+
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
33
34
|
import { getLogger } from "../util/logger.js";
|
|
34
35
|
import type { Conversation } from "./conversation.js";
|
|
35
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
buildSlackMetaForPersistence,
|
|
38
|
+
serializePersistedUserMessageContent,
|
|
39
|
+
} from "./conversation-messaging.js";
|
|
36
40
|
import { formatCompactResult } from "./conversation-process.js";
|
|
37
41
|
import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
|
|
38
42
|
import {
|
|
@@ -314,7 +318,11 @@ export async function processMessage(
|
|
|
314
318
|
const persisted = await addMessage(
|
|
315
319
|
conversationId,
|
|
316
320
|
"user",
|
|
317
|
-
|
|
321
|
+
serializePersistedUserMessageContent(
|
|
322
|
+
content,
|
|
323
|
+
attachments,
|
|
324
|
+
options?.displayContent,
|
|
325
|
+
),
|
|
318
326
|
userMetaWithSlack,
|
|
319
327
|
);
|
|
320
328
|
conversation.getMessages().push(llmMsg);
|
|
@@ -368,6 +376,7 @@ export async function processMessage(
|
|
|
368
376
|
serverChannelMeta,
|
|
369
377
|
);
|
|
370
378
|
conversation.getMessages().push(assistantMsg);
|
|
379
|
+
publishConversationMessagesChanged(conversationId);
|
|
371
380
|
return { messageId: persisted.id };
|
|
372
381
|
}
|
|
373
382
|
|
|
@@ -399,7 +408,11 @@ export async function processMessage(
|
|
|
399
408
|
const persisted = await addMessage(
|
|
400
409
|
conversationId,
|
|
401
410
|
"user",
|
|
402
|
-
|
|
411
|
+
serializePersistedUserMessageContent(
|
|
412
|
+
content,
|
|
413
|
+
attachments,
|
|
414
|
+
options?.displayContent,
|
|
415
|
+
),
|
|
403
416
|
compactUserMeta,
|
|
404
417
|
);
|
|
405
418
|
conversation.getMessages().push(cleanMsg);
|
|
@@ -421,6 +434,7 @@ export async function processMessage(
|
|
|
421
434
|
compactChannelMeta,
|
|
422
435
|
);
|
|
423
436
|
conversation.getMessages().push(assistantMsg);
|
|
437
|
+
publishConversationMessagesChanged(conversationId);
|
|
424
438
|
return { messageId: persisted.id };
|
|
425
439
|
}
|
|
426
440
|
|
|
@@ -435,7 +449,9 @@ export async function processMessage(
|
|
|
435
449
|
attachments,
|
|
436
450
|
requestId,
|
|
437
451
|
persistMetadata,
|
|
452
|
+
options?.displayContent,
|
|
438
453
|
);
|
|
454
|
+
publishConversationMessagesChanged(conversationId);
|
|
439
455
|
|
|
440
456
|
if (options?.isInteractive === true) {
|
|
441
457
|
conversation.updateClient(broadcastMessage, false);
|
|
@@ -499,7 +515,9 @@ export async function processMessageInBackground(
|
|
|
499
515
|
attachments,
|
|
500
516
|
requestId,
|
|
501
517
|
persistMetadata,
|
|
518
|
+
options?.displayContent,
|
|
502
519
|
);
|
|
520
|
+
publishConversationMessagesChanged(conversationId);
|
|
503
521
|
|
|
504
522
|
if (options?.isInteractive === true) {
|
|
505
523
|
conversation.updateClient(broadcastMessage, false);
|
package/src/daemon/server.ts
CHANGED
|
@@ -16,7 +16,9 @@ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
|
16
16
|
import { getSigningKeyFingerprint } from "../runtime/auth/token-service.js";
|
|
17
17
|
import {
|
|
18
18
|
publishAvatarChanged,
|
|
19
|
+
publishConfigChanged,
|
|
19
20
|
publishIdentityChanged,
|
|
21
|
+
publishSoundsConfigUpdated,
|
|
20
22
|
} from "../runtime/sync/resource-sync-events.js";
|
|
21
23
|
import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
|
|
22
24
|
import { getSubagentManager } from "../subagent/index.js";
|
|
@@ -43,6 +45,8 @@ import { refreshSurfacesForApp } from "./conversation-surfaces.js";
|
|
|
43
45
|
import { parseIdentityFields } from "./handlers/identity.js";
|
|
44
46
|
import type { ConversationCreateOptions } from "./handlers/shared.js";
|
|
45
47
|
import { setGlobalSkillIpcSender } from "./meet-host-supervisor.js";
|
|
48
|
+
import { PluginSourceWatcher } from "./plugin-source-watcher.js";
|
|
49
|
+
import { refreshSkillCapabilityMemories } from "./skill-memory-refresh.js";
|
|
46
50
|
|
|
47
51
|
const log = getLogger("server");
|
|
48
52
|
|
|
@@ -68,6 +72,7 @@ export class DaemonServer {
|
|
|
68
72
|
// Composed subsystems
|
|
69
73
|
private configWatcher = getConfigWatcher();
|
|
70
74
|
private appSourceWatcher = new AppSourceWatcher();
|
|
75
|
+
private pluginSourceWatcher = PluginSourceWatcher.getInstance();
|
|
71
76
|
private cliIpc = new AssistantIpcServer();
|
|
72
77
|
private skillIpc = new SkillIpcServer();
|
|
73
78
|
|
|
@@ -193,11 +198,11 @@ export class DaemonServer {
|
|
|
193
198
|
}
|
|
194
199
|
|
|
195
200
|
private broadcastConfigChanged(): void {
|
|
196
|
-
|
|
201
|
+
publishConfigChanged();
|
|
197
202
|
}
|
|
198
203
|
|
|
199
204
|
private broadcastSoundsConfigUpdated(): void {
|
|
200
|
-
|
|
205
|
+
publishSoundsConfigUpdated();
|
|
201
206
|
}
|
|
202
207
|
|
|
203
208
|
private broadcastAvatarUpdated(): void {
|
|
@@ -279,12 +284,15 @@ export class DaemonServer {
|
|
|
279
284
|
() => this.broadcastSoundsConfigUpdated(),
|
|
280
285
|
() => this.broadcastAvatarUpdated(),
|
|
281
286
|
() => this.broadcastConfigChanged(),
|
|
287
|
+
() => refreshSkillCapabilityMemories(getConfig()),
|
|
282
288
|
);
|
|
283
289
|
|
|
284
290
|
this.syncIdentityToPlatform();
|
|
285
291
|
|
|
286
292
|
this.appSourceWatcher.start((appId) => this.handleAppSourceChange(appId));
|
|
287
293
|
|
|
294
|
+
this.pluginSourceWatcher.start();
|
|
295
|
+
|
|
288
296
|
// Broadcast contacts_changed to all clients when any contact mutation occurs.
|
|
289
297
|
this.unsubscribeContactChange = onContactChange(() => {
|
|
290
298
|
broadcastMessage({ type: "contacts_changed" });
|
|
@@ -299,6 +307,7 @@ export class DaemonServer {
|
|
|
299
307
|
this.evictor.stop();
|
|
300
308
|
this.configWatcher.stop();
|
|
301
309
|
this.appSourceWatcher.stop();
|
|
310
|
+
this.pluginSourceWatcher.stop();
|
|
302
311
|
this.cliIpc.stop();
|
|
303
312
|
this.skillIpc.stop();
|
|
304
313
|
if (this.unsubscribeContactChange) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getConfig } from "../config/loader.js";
|
|
2
|
+
import type { AssistantConfig } from "../config/schema.js";
|
|
3
|
+
import {
|
|
4
|
+
seedSkillGraphNodes,
|
|
5
|
+
seedUninstalledCatalogSkillMemories,
|
|
6
|
+
} from "../memory/graph/capability-seed.js";
|
|
7
|
+
import { getLogger } from "../util/logger.js";
|
|
8
|
+
import { maybeSeedMemoryV2Skills } from "./memory-v2-startup.js";
|
|
9
|
+
|
|
10
|
+
const log = getLogger("skill-memory-refresh");
|
|
11
|
+
|
|
12
|
+
export function refreshSkillCapabilityMemories(
|
|
13
|
+
config: AssistantConfig = getConfig(),
|
|
14
|
+
): void {
|
|
15
|
+
seedSkillGraphNodes();
|
|
16
|
+
maybeSeedMemoryV2Skills(config);
|
|
17
|
+
void seedUninstalledCatalogSkillMemories()
|
|
18
|
+
.then(() => {
|
|
19
|
+
// Re-run after the async catalog fetch populates the cache so stale
|
|
20
|
+
// installed-skill nodes can be pruned without deleting catalog-only nodes.
|
|
21
|
+
seedSkillGraphNodes();
|
|
22
|
+
})
|
|
23
|
+
.catch((err) =>
|
|
24
|
+
log.warn(
|
|
25
|
+
{ err },
|
|
26
|
+
"Uninstalled catalog skill memory seeding failed — continuing",
|
|
27
|
+
),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -5,11 +5,26 @@
|
|
|
5
5
|
* background jobs (e.g. proactive artifact generation) can persist documents
|
|
6
6
|
* without going through the HTTP layer.
|
|
7
7
|
*/
|
|
8
|
-
import { rawGet, rawRun } from "../memory/raw-query.js";
|
|
8
|
+
import { rawAll, rawGet, rawRun } from "../memory/raw-query.js";
|
|
9
9
|
import { getLogger } from "../util/logger.js";
|
|
10
10
|
|
|
11
11
|
const log = getLogger("document-store");
|
|
12
12
|
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Shared types
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/** A document record with camelCase field names, mapped from the SQLite row. */
|
|
18
|
+
export interface DocumentRecord {
|
|
19
|
+
surfaceId: string;
|
|
20
|
+
conversationId: string;
|
|
21
|
+
title: string;
|
|
22
|
+
content: string;
|
|
23
|
+
wordCount: number;
|
|
24
|
+
createdAt: number;
|
|
25
|
+
updatedAt: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
// ---------------------------------------------------------------------------
|
|
14
29
|
// Junction table helper
|
|
15
30
|
// ---------------------------------------------------------------------------
|
|
@@ -27,6 +42,204 @@ export function addDocumentConversation(
|
|
|
27
42
|
);
|
|
28
43
|
}
|
|
29
44
|
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Shared query helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
interface DocumentRow {
|
|
50
|
+
surface_id: string;
|
|
51
|
+
conversation_id: string;
|
|
52
|
+
title: string;
|
|
53
|
+
content: string;
|
|
54
|
+
word_count: number;
|
|
55
|
+
created_at: number;
|
|
56
|
+
updated_at: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type DocumentListRow = Omit<DocumentRow, "content">;
|
|
60
|
+
|
|
61
|
+
function escapeSqlLikePattern(value: string): string {
|
|
62
|
+
return value.replace(/[\\%_]/g, "\\$&");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function mapRowToRecord(row: DocumentRow): DocumentRecord {
|
|
66
|
+
return {
|
|
67
|
+
surfaceId: row.surface_id,
|
|
68
|
+
conversationId: row.conversation_id,
|
|
69
|
+
title: row.title,
|
|
70
|
+
content: row.content,
|
|
71
|
+
wordCount: row.word_count,
|
|
72
|
+
createdAt: row.created_at,
|
|
73
|
+
updatedAt: row.updated_at,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Look up a single document by surface ID. Returns `null` when not found. */
|
|
78
|
+
export function getDocumentById(surfaceId: string): DocumentRecord | null {
|
|
79
|
+
try {
|
|
80
|
+
const row = rawGet<DocumentRow>(
|
|
81
|
+
/*sql*/ `SELECT surface_id, conversation_id, title, content, word_count, created_at, updated_at
|
|
82
|
+
FROM documents
|
|
83
|
+
WHERE surface_id = ?`,
|
|
84
|
+
surfaceId,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (!row) {
|
|
88
|
+
log.info({ surfaceId }, "Document not found");
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
log.info({ surfaceId }, "Loaded document");
|
|
93
|
+
return mapRowToRecord(row);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
log.error({ err: error, surfaceId }, "Load error");
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Return true when a document is associated with a conversation. */
|
|
101
|
+
export function isDocumentAssociatedWithConversation(
|
|
102
|
+
surfaceId: string,
|
|
103
|
+
conversationId: string,
|
|
104
|
+
): boolean {
|
|
105
|
+
try {
|
|
106
|
+
const row = rawGet<{ found: number }>(
|
|
107
|
+
/*sql*/ `
|
|
108
|
+
SELECT 1 AS found
|
|
109
|
+
FROM document_conversations
|
|
110
|
+
WHERE surface_id = ? AND conversation_id = ?
|
|
111
|
+
LIMIT 1
|
|
112
|
+
`,
|
|
113
|
+
surfaceId,
|
|
114
|
+
conversationId,
|
|
115
|
+
);
|
|
116
|
+
return row != null;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
log.error(
|
|
119
|
+
{ err: error, surfaceId, conversationId },
|
|
120
|
+
"Document association check error",
|
|
121
|
+
);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* List documents for a given conversation (via the junction table).
|
|
128
|
+
* Returns an empty array when the conversation has no documents or on error.
|
|
129
|
+
*/
|
|
130
|
+
export function getDocumentsForConversation(
|
|
131
|
+
conversationId: string,
|
|
132
|
+
): Omit<DocumentRecord, "content">[] {
|
|
133
|
+
try {
|
|
134
|
+
const rows = rawAll<DocumentListRow>(
|
|
135
|
+
/*sql*/ `
|
|
136
|
+
SELECT d.surface_id, dc.conversation_id AS conversation_id,
|
|
137
|
+
d.title, d.word_count, d.created_at, d.updated_at
|
|
138
|
+
FROM documents d
|
|
139
|
+
INNER JOIN document_conversations dc ON d.surface_id = dc.surface_id
|
|
140
|
+
WHERE dc.conversation_id = ?
|
|
141
|
+
ORDER BY d.updated_at DESC
|
|
142
|
+
`,
|
|
143
|
+
conversationId,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
log.info(
|
|
147
|
+
{ conversationId, count: rows.length },
|
|
148
|
+
"Listed documents for conversation",
|
|
149
|
+
);
|
|
150
|
+
return rows.map((row) => ({
|
|
151
|
+
surfaceId: row.surface_id,
|
|
152
|
+
conversationId: row.conversation_id,
|
|
153
|
+
title: row.title,
|
|
154
|
+
wordCount: row.word_count,
|
|
155
|
+
createdAt: row.created_at,
|
|
156
|
+
updatedAt: row.updated_at,
|
|
157
|
+
}));
|
|
158
|
+
} catch (error) {
|
|
159
|
+
log.error({ err: error, conversationId }, "List error");
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Search documents by title substring (case-insensitive).
|
|
166
|
+
* When `conversationId` is supplied, only documents associated with that
|
|
167
|
+
* conversation are returned.
|
|
168
|
+
* Returns documents ordered by most recently updated.
|
|
169
|
+
*/
|
|
170
|
+
export function searchDocumentsByTitle(
|
|
171
|
+
query: string,
|
|
172
|
+
options: { conversationId?: string } = {},
|
|
173
|
+
): Omit<DocumentRecord, "content">[] {
|
|
174
|
+
try {
|
|
175
|
+
const pattern = `%${escapeSqlLikePattern(query)}%`;
|
|
176
|
+
const rows = options.conversationId
|
|
177
|
+
? rawAll<DocumentListRow>(
|
|
178
|
+
/*sql*/ `
|
|
179
|
+
SELECT d.surface_id, dc.conversation_id AS conversation_id,
|
|
180
|
+
d.title, d.word_count, d.created_at, d.updated_at
|
|
181
|
+
FROM documents d
|
|
182
|
+
INNER JOIN document_conversations dc ON d.surface_id = dc.surface_id
|
|
183
|
+
WHERE dc.conversation_id = ?
|
|
184
|
+
AND d.title COLLATE NOCASE LIKE ? ESCAPE '\\'
|
|
185
|
+
ORDER BY d.updated_at DESC
|
|
186
|
+
LIMIT 20
|
|
187
|
+
`,
|
|
188
|
+
options.conversationId,
|
|
189
|
+
pattern,
|
|
190
|
+
)
|
|
191
|
+
: rawAll<DocumentListRow>(
|
|
192
|
+
/*sql*/ `
|
|
193
|
+
SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
|
|
194
|
+
FROM documents
|
|
195
|
+
WHERE title COLLATE NOCASE LIKE ? ESCAPE '\\'
|
|
196
|
+
ORDER BY updated_at DESC
|
|
197
|
+
LIMIT 20
|
|
198
|
+
`,
|
|
199
|
+
pattern,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
log.info(
|
|
203
|
+
{ query, conversationId: options.conversationId, count: rows.length },
|
|
204
|
+
"Searched documents by title",
|
|
205
|
+
);
|
|
206
|
+
return rows.map((row) => ({
|
|
207
|
+
surfaceId: row.surface_id,
|
|
208
|
+
conversationId: row.conversation_id,
|
|
209
|
+
title: row.title,
|
|
210
|
+
wordCount: row.word_count,
|
|
211
|
+
createdAt: row.created_at,
|
|
212
|
+
updatedAt: row.updated_at,
|
|
213
|
+
}));
|
|
214
|
+
} catch (error) {
|
|
215
|
+
log.error({ err: error, query }, "Search error");
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Delete a document and its conversation associations.
|
|
222
|
+
* Returns `true` if the document existed and was deleted, `false` otherwise.
|
|
223
|
+
*/
|
|
224
|
+
export function deleteDocument(surfaceId: string): boolean {
|
|
225
|
+
try {
|
|
226
|
+
const changes = rawRun(
|
|
227
|
+
/*sql*/ `DELETE FROM documents WHERE surface_id = ?`,
|
|
228
|
+
surfaceId,
|
|
229
|
+
);
|
|
230
|
+
rawRun(
|
|
231
|
+
/*sql*/ `DELETE FROM document_conversations WHERE surface_id = ?`,
|
|
232
|
+
surfaceId,
|
|
233
|
+
);
|
|
234
|
+
const existed = changes > 0;
|
|
235
|
+
log.info({ surfaceId, existed }, "Deleted document");
|
|
236
|
+
return existed;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
log.error({ err: error, surfaceId }, "Delete error");
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
30
243
|
// ---------------------------------------------------------------------------
|
|
31
244
|
// Document persistence
|
|
32
245
|
// ---------------------------------------------------------------------------
|
|
@@ -89,7 +302,7 @@ export function updateDocumentContent(
|
|
|
89
302
|
surfaceId: string,
|
|
90
303
|
markdown: string,
|
|
91
304
|
mode: string,
|
|
92
|
-
):
|
|
305
|
+
): { success: true } | { success: false; error: string } {
|
|
93
306
|
try {
|
|
94
307
|
const existing = rawGet<{ content: string }>(
|
|
95
308
|
/*sql*/ `SELECT content FROM documents WHERE surface_id = ?`,
|
|
@@ -97,7 +310,7 @@ export function updateDocumentContent(
|
|
|
97
310
|
);
|
|
98
311
|
if (!existing) {
|
|
99
312
|
log.info({ surfaceId }, "No persisted document to update");
|
|
100
|
-
return;
|
|
313
|
+
return { success: false, error: "Document not found" };
|
|
101
314
|
}
|
|
102
315
|
const sep = mode === "append" && existing.content.length > 0 ? "\n\n" : "";
|
|
103
316
|
const newContent =
|
|
@@ -113,7 +326,12 @@ export function updateDocumentContent(
|
|
|
113
326
|
surfaceId,
|
|
114
327
|
);
|
|
115
328
|
log.info({ surfaceId, mode }, "Updated document content");
|
|
329
|
+
return { success: true };
|
|
116
330
|
} catch (error) {
|
|
117
331
|
log.error({ err: error, surfaceId }, "Document content update error");
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
335
|
+
};
|
|
118
336
|
}
|
|
119
337
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded handle for `@vellumai/plugin-api`.
|
|
3
|
+
*
|
|
4
|
+
* Standard `import * as pluginApi from "../plugin-api/index.ts"` lets Bun's
|
|
5
|
+
* normal bundler walk the plugin-api module graph at build time — relative
|
|
6
|
+
* imports inside plugin-api (`./types.js`, future runtime siblings) are
|
|
7
|
+
* inlined naturally, with no separate build step. In `bun --compile`, this
|
|
8
|
+
* means plugin-api ships as part of the assistant binary's regular code
|
|
9
|
+
* graph; in JIT/Docker, it loads from source.
|
|
10
|
+
*
|
|
11
|
+
* The loaded namespace is then installed on `globalThis` under a versioned
|
|
12
|
+
* symbol. The boot-time shim writer (`ensurePluginApiShim`) enumerates
|
|
13
|
+
* {@link PLUGIN_API_EXPORTS} and generates a tiny ESM module at
|
|
14
|
+
* `<workspaceDir>/node_modules/@vellumai/plugin-api/index.js` that
|
|
15
|
+
* re-binds each runtime export from `globalThis`. User plugins that
|
|
16
|
+
* `import { ... } from "@vellumai/plugin-api"` walk up to that shim and
|
|
17
|
+
* pick up the bindings.
|
|
18
|
+
*
|
|
19
|
+
* Type-only exports erase before this module loads, so `Object.keys`
|
|
20
|
+
* sees only runtime exports. That's correct — types are a dev-time
|
|
21
|
+
* concern, resolved against plugin-api source via tsconfig path-mapping
|
|
22
|
+
* (or, post-PR-5, against a generated `.d.ts` next to the runtime
|
|
23
|
+
* shim).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import * as pluginApi from "../plugin-api/index.js";
|
|
27
|
+
|
|
28
|
+
/** Symbol key under which the plugin-api namespace is published on globalThis. */
|
|
29
|
+
export const PLUGIN_API_REGISTRY_KEY = Symbol.for("vellum.plugin-api.v1");
|
|
30
|
+
|
|
31
|
+
// Install on globalThis once at module-load time. The shim writer reads
|
|
32
|
+
// `PLUGIN_API_EXPORTS` to know which bindings to re-export; the shim's
|
|
33
|
+
// generated body then reads `globalThis[PLUGIN_API_REGISTRY_KEY]` to grab
|
|
34
|
+
// the live module namespace.
|
|
35
|
+
(globalThis as Record<symbol, unknown>)[PLUGIN_API_REGISTRY_KEY] = pluginApi;
|
|
36
|
+
|
|
37
|
+
/** Names of the runtime exports the workspace shim should re-bind. */
|
|
38
|
+
export const PLUGIN_API_EXPORTS: readonly string[] = Object.freeze(
|
|
39
|
+
Object.keys(pluginApi),
|
|
40
|
+
);
|