@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,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the GET /v1/acp/sessions list handler — specifically the SQL
|
|
3
|
+
* pad amount applied to acp_session_history when in-memory sessions are
|
|
4
|
+
* also present. We mock the DB layer so the limit value passed to the
|
|
5
|
+
* query builder can be asserted directly.
|
|
6
|
+
*
|
|
7
|
+
* Regression for codex P2 feedback on PR #29993: padding by the global
|
|
8
|
+
* inMemory.length over-fetched when many unrelated sessions were live
|
|
9
|
+
* but only one conversation was being queried.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { afterAll, describe, expect, mock, test } from "bun:test";
|
|
13
|
+
|
|
14
|
+
import type { AcpSessionState } from "../../acp/index.js";
|
|
15
|
+
|
|
16
|
+
const inMemoryStates = new Map<string, AcpSessionState>();
|
|
17
|
+
|
|
18
|
+
mock.module("../../acp/index.js", () => ({
|
|
19
|
+
getAcpSessionManager: () => ({
|
|
20
|
+
getStatus: (id?: string) => {
|
|
21
|
+
if (id === undefined) return Array.from(inMemoryStates.values());
|
|
22
|
+
const state = inMemoryStates.get(id);
|
|
23
|
+
if (!state) throw new Error(`ACP session "${id}" not found`);
|
|
24
|
+
return state;
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
// Spy on the drizzle limit() call to assert the exact value the handler
|
|
30
|
+
// passes to SQL. The stub mirrors only the chained methods used by
|
|
31
|
+
// listMergedSessions; calls fall through to a final `.all()` returning [].
|
|
32
|
+
const capturedLimits: number[] = [];
|
|
33
|
+
|
|
34
|
+
mock.module("../../memory/db-connection.js", () => {
|
|
35
|
+
const builder: any = {};
|
|
36
|
+
builder.select = () => builder;
|
|
37
|
+
builder.from = () => builder;
|
|
38
|
+
builder.where = () => builder;
|
|
39
|
+
builder.orderBy = () => builder;
|
|
40
|
+
builder.limit = (n: number) => {
|
|
41
|
+
capturedLimits.push(n);
|
|
42
|
+
return builder;
|
|
43
|
+
};
|
|
44
|
+
builder.all = () => [];
|
|
45
|
+
return {
|
|
46
|
+
getDb: () => builder,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const { ROUTES } = await import("./acp-routes.js");
|
|
51
|
+
|
|
52
|
+
function getListHandler() {
|
|
53
|
+
const route = ROUTES.find(
|
|
54
|
+
(r: { endpoint: string; method: string }) =>
|
|
55
|
+
r.endpoint === "acp/sessions" && r.method === "GET",
|
|
56
|
+
);
|
|
57
|
+
if (!route) throw new Error("GET acp/sessions route not registered");
|
|
58
|
+
return route.handler;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function makeInMemoryState(
|
|
62
|
+
id: string,
|
|
63
|
+
parentConversationId: string,
|
|
64
|
+
): AcpSessionState {
|
|
65
|
+
return {
|
|
66
|
+
id,
|
|
67
|
+
agentId: "claude",
|
|
68
|
+
acpSessionId: `proto-${id}`,
|
|
69
|
+
parentConversationId,
|
|
70
|
+
status: "running",
|
|
71
|
+
startedAt: 1_700_000_000_000,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
afterAll(() => {
|
|
76
|
+
inMemoryStates.clear();
|
|
77
|
+
capturedLimits.length = 0;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("GET /v1/acp/sessions — SQL pad amount", () => {
|
|
81
|
+
test("pads SQL limit by the conversation-filtered in-memory count, not the global one", async () => {
|
|
82
|
+
inMemoryStates.clear();
|
|
83
|
+
capturedLimits.length = 0;
|
|
84
|
+
|
|
85
|
+
// Many in-memory sessions for an unrelated conversation, plus one
|
|
86
|
+
// that matches the target conversation.
|
|
87
|
+
for (let i = 0; i < 25; i++) {
|
|
88
|
+
inMemoryStates.set(
|
|
89
|
+
`other-${i}`,
|
|
90
|
+
makeInMemoryState(`other-${i}`, "conv-other"),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
inMemoryStates.set(
|
|
94
|
+
"target-mem",
|
|
95
|
+
makeInMemoryState("target-mem", "conv-target"),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const handler = getListHandler();
|
|
99
|
+
await handler({
|
|
100
|
+
queryParams: { conversationId: "conv-target", limit: "10" },
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(capturedLimits).toHaveLength(1);
|
|
104
|
+
// pad = filtered in-memory count (1), not global (26).
|
|
105
|
+
expect(capturedLimits[0]).toBe(11);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("pads by zero when no in-memory sessions match the target conversation", async () => {
|
|
109
|
+
inMemoryStates.clear();
|
|
110
|
+
capturedLimits.length = 0;
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < 10; i++) {
|
|
113
|
+
inMemoryStates.set(
|
|
114
|
+
`other-${i}`,
|
|
115
|
+
makeInMemoryState(`other-${i}`, "conv-other"),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const handler = getListHandler();
|
|
120
|
+
await handler({
|
|
121
|
+
queryParams: { conversationId: "conv-target", limit: "5" },
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(capturedLimits).toEqual([5]);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("pads by the full in-memory count when no conversation filter is supplied", async () => {
|
|
128
|
+
inMemoryStates.clear();
|
|
129
|
+
capturedLimits.length = 0;
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < 4; i++) {
|
|
132
|
+
inMemoryStates.set(
|
|
133
|
+
`sess-${i}`,
|
|
134
|
+
makeInMemoryState(`sess-${i}`, `conv-${i}`),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const handler = getListHandler();
|
|
139
|
+
await handler({ queryParams: { limit: "20" } });
|
|
140
|
+
|
|
141
|
+
expect(capturedLimits).toEqual([24]);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -373,11 +373,13 @@ function listMergedSessions(opts: {
|
|
|
373
373
|
: baseQuery;
|
|
374
374
|
// Fetch only enough rows to fill the requested page after merging with
|
|
375
375
|
// in-memory sessions. In-memory entries take precedence on id collision,
|
|
376
|
-
// so we pad by
|
|
377
|
-
// distinct rows even when every
|
|
376
|
+
// so we pad by the count that survived the conversation filter to
|
|
377
|
+
// guarantee we still surface `limit` distinct rows even when every
|
|
378
|
+
// in-memory session shadows a DB row — without over-fetching when many
|
|
379
|
+
// unrelated sessions are in memory.
|
|
378
380
|
const historyRows = filtered
|
|
379
381
|
.orderBy(desc(acpSessionHistory.startedAt))
|
|
380
|
-
.limit(opts.limit +
|
|
382
|
+
.limit(opts.limit + merged.size)
|
|
381
383
|
.all();
|
|
382
384
|
|
|
383
385
|
for (const row of historyRows) {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
getPlatformOrganizationId,
|
|
13
13
|
getPlatformUserId,
|
|
14
14
|
} from "../../config/env.js";
|
|
15
|
-
import { resolveManagedProxyContext } from "../../providers/
|
|
15
|
+
import { resolveManagedProxyContext } from "../../providers/platform-proxy/context.js";
|
|
16
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
17
17
|
|
|
18
18
|
interface AuthInfoResult {
|
|
@@ -79,9 +79,11 @@ function handleCreateBookmark({
|
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
const result = createBookmark(getDb(), { messageId });
|
|
83
|
+
if (result.inserted) {
|
|
84
|
+
publishBookmarkCreated(result.bookmark);
|
|
85
|
+
}
|
|
86
|
+
return result.bookmark;
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
function handleDeleteBookmarkByMessage({ pathParams = {} }: RouteHandlerArgs): {
|
|
@@ -16,6 +16,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
16
16
|
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
|
|
19
|
+
import { getConfig } from "../../config/loader.js";
|
|
19
20
|
import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
|
|
20
21
|
import { getOrCreateConversation } from "../../daemon/conversation-store.js";
|
|
21
22
|
import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
|
|
@@ -92,7 +93,10 @@ async function handleBtw({
|
|
|
92
93
|
|
|
93
94
|
// ----- Greeting context enrichment -----
|
|
94
95
|
let effectiveContent = trimmedContent;
|
|
95
|
-
if (
|
|
96
|
+
if (
|
|
97
|
+
conversationKey === GREETING_KEY &&
|
|
98
|
+
getConfig().memory.retrieval.scratchpadInjection.enabled
|
|
99
|
+
) {
|
|
96
100
|
const now = readNowScratchpad();
|
|
97
101
|
if (now) {
|
|
98
102
|
effectiveContent = `${trimmedContent}\n\n<context>\n${now}\n</context>`;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handler for channel availability.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/channels/available — return the channels this assistant can
|
|
5
|
+
* surface to clients (Contacts / GuardianChannels views, etc.) along with
|
|
6
|
+
* their display metadata (label, subtitle, icon, verification capability,
|
|
7
|
+
* setup-message copy). Today this is a fixed base list plus `email` when
|
|
8
|
+
* an inbox is registered; eventually the list will be driven by
|
|
9
|
+
* plugins/skills the assistant has loaded. Clients should treat the
|
|
10
|
+
* response as authoritative and stop carrying their own per-channel
|
|
11
|
+
* switches.
|
|
12
|
+
*
|
|
13
|
+
* Distinct from `/v1/channels/readiness` (which answers "is this channel
|
|
14
|
+
* configured and working?"). Availability answers "could this channel be
|
|
15
|
+
* surfaced for setup/verification at all?".
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
CHANNEL_IDS,
|
|
22
|
+
CHANNEL_METADATA,
|
|
23
|
+
type ChannelId,
|
|
24
|
+
type ChannelInfo,
|
|
25
|
+
} from "../../channels/types.js";
|
|
26
|
+
import { VellumPlatformClient } from "../../platform/client.js";
|
|
27
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
28
|
+
|
|
29
|
+
// Base list every assistant currently surfaces. Order is the display
|
|
30
|
+
// order clients should render. Keep stable — clients sort by index.
|
|
31
|
+
const BASE_AVAILABLE_CHANNELS: readonly ChannelId[] = [
|
|
32
|
+
"slack",
|
|
33
|
+
"telegram",
|
|
34
|
+
"phone",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
interface EmailAddressListResponse {
|
|
38
|
+
count?: number;
|
|
39
|
+
results?: Array<{ id: string; address: string }>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Best-effort check that an inbox address is registered for this
|
|
44
|
+
* assistant. A platform fetch failure is treated as "no inbox" — we
|
|
45
|
+
* prefer to under-report than block the entire Contacts page when the
|
|
46
|
+
* platform is briefly unreachable.
|
|
47
|
+
*/
|
|
48
|
+
async function hasRegisteredInbox(): Promise<boolean> {
|
|
49
|
+
const client = await VellumPlatformClient.create();
|
|
50
|
+
if (!client?.platformAssistantId) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const response = await client.fetch(
|
|
56
|
+
`/v1/assistants/${client.platformAssistantId}/email-addresses/`,
|
|
57
|
+
);
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const data = (await response.json()) as EmailAddressListResponse;
|
|
62
|
+
if (typeof data.count === "number") {
|
|
63
|
+
return data.count > 0;
|
|
64
|
+
}
|
|
65
|
+
return Array.isArray(data.results) && data.results.length > 0;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function handleGetChannelAvailability(
|
|
72
|
+
_args: RouteHandlerArgs,
|
|
73
|
+
): Promise<{ channels: ChannelInfo[] }> {
|
|
74
|
+
const ids: ChannelId[] = [...BASE_AVAILABLE_CHANNELS];
|
|
75
|
+
if (await hasRegisteredInbox()) {
|
|
76
|
+
ids.push("email");
|
|
77
|
+
}
|
|
78
|
+
// CHANNEL_METADATA is `Partial<Record<ChannelId, ChannelInfo>>` because
|
|
79
|
+
// unsurfaced channels deliberately have no metadata. `ids` only ever
|
|
80
|
+
// contains channels that BASE_AVAILABLE_CHANNELS / the email branch
|
|
81
|
+
// explicitly chose, so the lookup is always defined — filter to satisfy
|
|
82
|
+
// the type system without a non-null assertion.
|
|
83
|
+
const channels = ids
|
|
84
|
+
.map((id) => CHANNEL_METADATA[id])
|
|
85
|
+
.filter((info): info is ChannelInfo => info !== undefined);
|
|
86
|
+
return { channels };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const channelInfoSchema = z.object({
|
|
90
|
+
id: z.enum(CHANNEL_IDS),
|
|
91
|
+
label: z.string(),
|
|
92
|
+
subtitle: z.string(),
|
|
93
|
+
icon: z.string(),
|
|
94
|
+
supportsVerification: z.boolean(),
|
|
95
|
+
setupMessages: z.object({
|
|
96
|
+
guardian: z.string(),
|
|
97
|
+
contact: z.string(),
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export const ROUTES: RouteDefinition[] = [
|
|
102
|
+
{
|
|
103
|
+
operationId: "channels_available_get",
|
|
104
|
+
endpoint: "channels/available",
|
|
105
|
+
method: "GET",
|
|
106
|
+
summary: "Get available channels",
|
|
107
|
+
description:
|
|
108
|
+
"Return the channels this assistant can surface to clients, with " +
|
|
109
|
+
"display metadata (label, icon, verification capability, setup " +
|
|
110
|
+
"copy). Today this is a fixed base list plus `email` when an inbox " +
|
|
111
|
+
"is registered; will become plugin/skill-driven in future.",
|
|
112
|
+
tags: ["channels"],
|
|
113
|
+
requirePolicyEnforcement: true,
|
|
114
|
+
handler: handleGetChannelAvailability,
|
|
115
|
+
responseBody: z.object({
|
|
116
|
+
channels: z
|
|
117
|
+
.array(channelInfoSchema)
|
|
118
|
+
.describe("Available channels in display order"),
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
];
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
* used by the macOS / web clients.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { v4 as uuid } from "uuid";
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
|
|
11
12
|
import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
|
|
12
13
|
import { formatJson, formatMarkdown } from "../../export/formatter.js";
|
|
13
14
|
import {
|
|
15
|
+
addMessage,
|
|
14
16
|
createConversation,
|
|
15
17
|
getConversation,
|
|
16
18
|
getMessages,
|
|
17
19
|
} from "../../memory/conversation-crud.js";
|
|
20
|
+
import { setConversationKey } from "../../memory/conversation-key-store.js";
|
|
18
21
|
import { listConversations } from "../../memory/conversation-queries.js";
|
|
19
22
|
import { getLogger } from "../../util/logger.js";
|
|
20
23
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
@@ -45,12 +48,43 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
|
|
|
45
48
|
// create (CLI)
|
|
46
49
|
// ---------------------------------------------------------------------------
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
const seededConversationMessageSchema = z.object({
|
|
52
|
+
role: z.enum(["user", "assistant"]),
|
|
53
|
+
content: z.string(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
type SeededConversationMessage = z.infer<
|
|
57
|
+
typeof seededConversationMessageSchema
|
|
58
|
+
>;
|
|
59
|
+
|
|
60
|
+
function textContentJson(text: string): string {
|
|
61
|
+
return JSON.stringify([{ type: "text", text }]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function handleCreateCli({ body = {} }: RouteHandlerArgs) {
|
|
49
65
|
const title = body.title as string | undefined;
|
|
66
|
+
const messages =
|
|
67
|
+
(body.messages as SeededConversationMessage[] | undefined) ?? [];
|
|
68
|
+
|
|
50
69
|
const conversation = createConversation(title);
|
|
70
|
+
const conversationKey = uuid();
|
|
71
|
+
setConversationKey(conversationKey, conversation.id);
|
|
72
|
+
|
|
73
|
+
for (const message of messages) {
|
|
74
|
+
await addMessage(
|
|
75
|
+
conversation.id,
|
|
76
|
+
message.role,
|
|
77
|
+
textContentJson(message.content),
|
|
78
|
+
undefined,
|
|
79
|
+
{ skipIndexing: true },
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
51
83
|
return {
|
|
52
84
|
id: conversation.id,
|
|
53
85
|
title: conversation.title ?? "New Conversation",
|
|
86
|
+
conversationKey,
|
|
87
|
+
messagesInserted: messages.length,
|
|
54
88
|
};
|
|
55
89
|
}
|
|
56
90
|
|
|
@@ -109,7 +143,10 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
|
|
|
109
143
|
async function handleClearCli(_args: RouteHandlerArgs) {
|
|
110
144
|
// Tear down in-memory conversation state before DB clear.
|
|
111
145
|
const cleared = clearAllActive();
|
|
112
|
-
log.info(
|
|
146
|
+
log.info(
|
|
147
|
+
{ cleared },
|
|
148
|
+
"CLI conversations clear: active conversations torn down",
|
|
149
|
+
);
|
|
113
150
|
return { cleared };
|
|
114
151
|
}
|
|
115
152
|
|
|
@@ -146,14 +183,18 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
146
183
|
endpoint: "conversations/cli/create",
|
|
147
184
|
method: "POST",
|
|
148
185
|
summary: "Create a conversation (CLI)",
|
|
149
|
-
description:
|
|
186
|
+
description:
|
|
187
|
+
"Create a new conversation with an optional title and seeded messages.",
|
|
150
188
|
tags: ["conversations"],
|
|
151
189
|
requestBody: z.object({
|
|
152
190
|
title: z.string().optional(),
|
|
191
|
+
messages: z.array(seededConversationMessageSchema).optional(),
|
|
153
192
|
}),
|
|
154
193
|
responseBody: z.object({
|
|
155
194
|
id: z.string(),
|
|
156
195
|
title: z.string(),
|
|
196
|
+
conversationKey: z.string(),
|
|
197
|
+
messagesInserted: z.number().int().nonnegative(),
|
|
157
198
|
}),
|
|
158
199
|
handler: handleCreateCli,
|
|
159
200
|
},
|
|
@@ -28,12 +28,11 @@ import { getBindingsForConversations } from "../../memory/external-conversation-
|
|
|
28
28
|
import { listGroups } from "../../memory/group-crud.js";
|
|
29
29
|
import { UserError } from "../../util/errors.js";
|
|
30
30
|
import { getLogger } from "../../util/logger.js";
|
|
31
|
-
import { buildAssistantEvent } from "../assistant-event.js";
|
|
32
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
33
31
|
import {
|
|
34
32
|
buildConversationDetailResponse,
|
|
35
33
|
serializeConversationSummary,
|
|
36
34
|
} from "../services/conversation-serializer.js";
|
|
35
|
+
import { publishConversationListAndMetadataChanged } from "../sync/resource-sync-events.js";
|
|
37
36
|
import {
|
|
38
37
|
BadRequestError,
|
|
39
38
|
InternalError,
|
|
@@ -54,22 +53,6 @@ function resolveOrThrow(rawId: string): string {
|
|
|
54
53
|
return id;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
function publishListInvalidated(): void {
|
|
58
|
-
assistantEventHub
|
|
59
|
-
.publish(
|
|
60
|
-
buildAssistantEvent({
|
|
61
|
-
type: "conversation_list_invalidated",
|
|
62
|
-
reason: "seen_changed",
|
|
63
|
-
}),
|
|
64
|
-
)
|
|
65
|
-
.catch((err) => {
|
|
66
|
-
log.warn(
|
|
67
|
-
{ err },
|
|
68
|
-
"Failed to publish conversation_list_invalidated (seen_changed)",
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
56
|
// ---------------------------------------------------------------------------
|
|
74
57
|
// Handlers
|
|
75
58
|
// ---------------------------------------------------------------------------
|
|
@@ -159,7 +142,7 @@ function handleRecordSeen({ body = {} }: RouteHandlerArgs) {
|
|
|
159
142
|
});
|
|
160
143
|
|
|
161
144
|
if (wasUnseen) {
|
|
162
|
-
|
|
145
|
+
publishConversationListAndMetadataChanged("seen_changed", conversationId);
|
|
163
146
|
}
|
|
164
147
|
|
|
165
148
|
return { ok: true };
|
|
@@ -179,7 +162,7 @@ function handleMarkUnread({ body = {} }: RouteHandlerArgs) {
|
|
|
179
162
|
try {
|
|
180
163
|
const changed = markConversationUnread(conversationId);
|
|
181
164
|
if (changed) {
|
|
182
|
-
|
|
165
|
+
publishConversationListAndMetadataChanged("seen_changed", conversationId);
|
|
183
166
|
}
|
|
184
167
|
return { ok: true };
|
|
185
168
|
} catch (err) {
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
switchConversation,
|
|
28
28
|
undoLastMessage,
|
|
29
29
|
} from "../../daemon/handlers/conversations.js";
|
|
30
|
-
import type { ConversationListInvalidatedReason } from "../../daemon/message-types/conversations.js";
|
|
31
30
|
import { normalizeConversationType } from "../../daemon/message-types/shared.js";
|
|
32
31
|
import {
|
|
33
32
|
archiveConversation,
|
|
@@ -49,9 +48,12 @@ import { enqueueMemoryJob } from "../../memory/jobs-store.js";
|
|
|
49
48
|
import { deleteSchedule } from "../../schedule/schedule-store.js";
|
|
50
49
|
import { UserError } from "../../util/errors.js";
|
|
51
50
|
import { getLogger } from "../../util/logger.js";
|
|
52
|
-
import { buildAssistantEvent } from "../assistant-event.js";
|
|
53
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
54
51
|
import { buildConversationDetailResponse } from "../services/conversation-serializer.js";
|
|
52
|
+
import {
|
|
53
|
+
publishConversationListAndMetadataChanged,
|
|
54
|
+
publishConversationListChanged,
|
|
55
|
+
publishConversationTitleChanged,
|
|
56
|
+
} from "../sync/resource-sync-events.js";
|
|
55
57
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
56
58
|
import { setInferenceProfileSession } from "./inference-profile-session-handler.js";
|
|
57
59
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
@@ -68,24 +70,6 @@ function resolveOrThrow(rawId: string): string {
|
|
|
68
70
|
return id;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
function publishListInvalidated(
|
|
72
|
-
reason: ConversationListInvalidatedReason,
|
|
73
|
-
): void {
|
|
74
|
-
assistantEventHub
|
|
75
|
-
.publish(
|
|
76
|
-
buildAssistantEvent({
|
|
77
|
-
type: "conversation_list_invalidated",
|
|
78
|
-
reason,
|
|
79
|
-
}),
|
|
80
|
-
)
|
|
81
|
-
.catch((err) => {
|
|
82
|
-
log.warn(
|
|
83
|
-
{ err },
|
|
84
|
-
`Failed to publish conversation_list_invalidated (${reason})`,
|
|
85
|
-
);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
73
|
function cancelScheduleIfLast(conversationId: string): void {
|
|
90
74
|
const conv = getConversation(conversationId);
|
|
91
75
|
if (
|
|
@@ -108,6 +92,7 @@ function handleCreateConversation({ body = {} }: RouteHandlerArgs) {
|
|
|
108
92
|
});
|
|
109
93
|
if (result.created) {
|
|
110
94
|
updateConversationTitle(result.conversationId, "New Conversation");
|
|
95
|
+
publishConversationListAndMetadataChanged("created", result.conversationId);
|
|
111
96
|
}
|
|
112
97
|
log.info(
|
|
113
98
|
{
|
|
@@ -151,6 +136,7 @@ async function handleForkConversation({ body = {} }: RouteHandlerArgs) {
|
|
|
151
136
|
`Forked conversation ${forkedConversation.id} could not be loaded`,
|
|
152
137
|
);
|
|
153
138
|
}
|
|
139
|
+
publishConversationListAndMetadataChanged("created", forkedConversation.id);
|
|
154
140
|
return { conversation: detail.conversation };
|
|
155
141
|
} catch (err) {
|
|
156
142
|
if (err instanceof UserError) {
|
|
@@ -217,25 +203,7 @@ function handleRenameConversation({
|
|
|
217
203
|
}
|
|
218
204
|
updateConversationTitle(pathParams.id!, name, 0);
|
|
219
205
|
|
|
220
|
-
|
|
221
|
-
.publish(
|
|
222
|
-
buildAssistantEvent(
|
|
223
|
-
{
|
|
224
|
-
type: "conversation_title_updated",
|
|
225
|
-
conversationId: pathParams.id!,
|
|
226
|
-
title: name,
|
|
227
|
-
},
|
|
228
|
-
pathParams.id!,
|
|
229
|
-
),
|
|
230
|
-
)
|
|
231
|
-
.catch((err) => {
|
|
232
|
-
log.warn(
|
|
233
|
-
{ err, conversationId: pathParams.id },
|
|
234
|
-
"Failed to publish conversation_title_updated",
|
|
235
|
-
);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
publishListInvalidated("renamed");
|
|
206
|
+
publishConversationTitleChanged(pathParams.id!, name);
|
|
239
207
|
|
|
240
208
|
return { ok: true };
|
|
241
209
|
}
|
|
@@ -249,6 +217,7 @@ function handleClearAllConversations({ headers = {} }: RouteHandlerArgs) {
|
|
|
249
217
|
);
|
|
250
218
|
}
|
|
251
219
|
clearAllConversations();
|
|
220
|
+
publishConversationListChanged("deleted");
|
|
252
221
|
return undefined;
|
|
253
222
|
}
|
|
254
223
|
|
|
@@ -279,6 +248,7 @@ function handleWipeConversation({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
279
248
|
},
|
|
280
249
|
"Wiped conversation and reverted memory changes",
|
|
281
250
|
);
|
|
251
|
+
publishConversationListAndMetadataChanged("deleted", resolvedId);
|
|
282
252
|
return {
|
|
283
253
|
wiped: true,
|
|
284
254
|
unsupersededItems: 0,
|
|
@@ -308,7 +278,7 @@ function handleDeleteConversation({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
308
278
|
}
|
|
309
279
|
log.info({ conversationId: resolvedId }, "Deleted conversation");
|
|
310
280
|
|
|
311
|
-
|
|
281
|
+
publishConversationListAndMetadataChanged("deleted", resolvedId);
|
|
312
282
|
|
|
313
283
|
return undefined;
|
|
314
284
|
}
|
|
@@ -319,6 +289,7 @@ function handleArchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
319
289
|
if (!archived) {
|
|
320
290
|
throw new NotFoundError(`Conversation ${pathParams.id} not found`);
|
|
321
291
|
}
|
|
292
|
+
publishConversationListAndMetadataChanged("reordered", resolvedId);
|
|
322
293
|
return { ok: true, conversationId: resolvedId };
|
|
323
294
|
}
|
|
324
295
|
|
|
@@ -328,6 +299,7 @@ function handleUnarchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
328
299
|
if (!unarchived) {
|
|
329
300
|
throw new NotFoundError(`Conversation ${pathParams.id} not found`);
|
|
330
301
|
}
|
|
302
|
+
publishConversationListAndMetadataChanged("reordered", resolvedId);
|
|
331
303
|
return { ok: true, conversationId: resolvedId };
|
|
332
304
|
}
|
|
333
305
|
|
|
@@ -387,7 +359,10 @@ function handleReorderConversations({ body = {} }: RouteHandlerArgs) {
|
|
|
387
359
|
groupId: u.groupId,
|
|
388
360
|
})),
|
|
389
361
|
);
|
|
390
|
-
|
|
362
|
+
publishConversationListAndMetadataChanged(
|
|
363
|
+
"reordered",
|
|
364
|
+
updates.map((u) => u.conversationId),
|
|
365
|
+
);
|
|
391
366
|
return { ok: true };
|
|
392
367
|
}
|
|
393
368
|
|