@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
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
loadRawConfig,
|
|
29
29
|
saveRawConfig,
|
|
30
30
|
setNestedValue,
|
|
31
|
+
withSuppressedConfigDiskWrites,
|
|
32
|
+
withSuppressedConfigDiskWritesSync,
|
|
31
33
|
} from "../../config/loader.js";
|
|
32
34
|
import { AssistantConfigSchema } from "../../config/schema.js";
|
|
33
35
|
import { getSchemaAtPath } from "../../config/schema-utils.js";
|
|
@@ -229,7 +231,7 @@ function getModelSetContext(): ModelSetContext {
|
|
|
229
231
|
watcher.suppressConfigReload = value;
|
|
230
232
|
},
|
|
231
233
|
updateConfigFingerprint() {
|
|
232
|
-
watcher.updateFingerprint();
|
|
234
|
+
withSuppressedConfigDiskWritesSync(() => watcher.updateFingerprint());
|
|
233
235
|
},
|
|
234
236
|
debounceTimers: watcher.timers,
|
|
235
237
|
};
|
|
@@ -471,15 +473,14 @@ async function commitConfigWrite(
|
|
|
471
473
|
|
|
472
474
|
clearEmbeddingBackendCache();
|
|
473
475
|
invalidateConfigCache();
|
|
474
|
-
// Reinitialize providers so the live registry reflects the new config
|
|
475
|
-
//
|
|
476
|
-
//
|
|
477
|
-
// Only advance the config fingerprint on success - if reinit failed, leave
|
|
478
|
-
// it stale so the watcher can detect the saved config on the next event
|
|
479
|
-
// and retry provider initialization.
|
|
476
|
+
// Reinitialize providers so the live registry reflects the new config.
|
|
477
|
+
// Suppress disk writes inside loadConfig() — we just wrote the raw config
|
|
478
|
+
// and the first-launch seed path would overwrite it with full defaults.
|
|
480
479
|
try {
|
|
481
|
-
await
|
|
482
|
-
|
|
480
|
+
await withSuppressedConfigDiskWrites(async () => {
|
|
481
|
+
await initializeProviders(getConfig());
|
|
482
|
+
configWatcher.updateFingerprint();
|
|
483
|
+
});
|
|
483
484
|
} catch (err) {
|
|
484
485
|
const message = err instanceof Error ? err.message : String(err);
|
|
485
486
|
log.error({ err }, `${opLabel} config: provider reinit failed: ${message}`);
|
|
@@ -577,7 +578,7 @@ function handleValidateAllowlist() {
|
|
|
577
578
|
}
|
|
578
579
|
}
|
|
579
580
|
|
|
580
|
-
function handleReplaceInferenceProfile({
|
|
581
|
+
async function handleReplaceInferenceProfile({
|
|
581
582
|
pathParams = {},
|
|
582
583
|
body,
|
|
583
584
|
}: RouteHandlerArgs) {
|
|
@@ -616,32 +617,36 @@ function handleReplaceInferenceProfile({
|
|
|
616
617
|
);
|
|
617
618
|
}
|
|
618
619
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
);
|
|
638
|
-
}
|
|
639
|
-
saveRawConfig(raw);
|
|
640
|
-
return { ok: true };
|
|
641
|
-
} catch (err) {
|
|
642
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
643
|
-
throw new InternalError(`Failed to replace inference profile: ${message}`);
|
|
620
|
+
const raw = loadRawConfig();
|
|
621
|
+
if (isManaged) {
|
|
622
|
+
// Partial overlay: keep every existing key intact, only update label
|
|
623
|
+
// and/or status from the fragment. Using `replaceInferenceProfileConfig`
|
|
624
|
+
// here would wipe the UI-owned seed fields (provider, model, advanced
|
|
625
|
+
// params) because that function assumes the body carries the full UI
|
|
626
|
+
// surface.
|
|
627
|
+
patchManagedProfileFields(
|
|
628
|
+
raw,
|
|
629
|
+
name,
|
|
630
|
+
parsed.data as Record<string, unknown>,
|
|
631
|
+
);
|
|
632
|
+
} else {
|
|
633
|
+
replaceInferenceProfileConfig(
|
|
634
|
+
raw,
|
|
635
|
+
name,
|
|
636
|
+
parsed.data as Record<string, unknown>,
|
|
637
|
+
);
|
|
644
638
|
}
|
|
639
|
+
// Route through `commitConfigWrite` so profile edits flow through the
|
|
640
|
+
// post-write side effects shared with `handlePatchConfig` /
|
|
641
|
+
// `handleSetConfig`: file-watcher suppression so the in-process reload
|
|
642
|
+
// doesn't race the explicit reinit, embedding backend cache clear,
|
|
643
|
+
// in-process `getConfig` cache invalidation, and provider registry
|
|
644
|
+
// reinitialization. `status: "disabled"` on a managed profile (and any
|
|
645
|
+
// `provider` / `model` / `provider_connection` change on a custom
|
|
646
|
+
// profile) must take effect immediately rather than waiting for the
|
|
647
|
+
// next watcher tick.
|
|
648
|
+
await commitConfigWrite(raw, "replace inference profile");
|
|
649
|
+
return { ok: true };
|
|
645
650
|
}
|
|
646
651
|
|
|
647
652
|
/**
|
|
@@ -90,6 +90,12 @@ import {
|
|
|
90
90
|
getOrCreateConversation,
|
|
91
91
|
} from "../../memory/conversation-key-store.js";
|
|
92
92
|
import { searchConversations } from "../../memory/conversation-queries.js";
|
|
93
|
+
import { recordOnboardingEvent } from "../../memory/onboarding-events-store.js";
|
|
94
|
+
import { buildSlackMessageDeepLinks } from "../../messaging/providers/slack/deep-link.js";
|
|
95
|
+
import {
|
|
96
|
+
readSlackMetadataFromMessageMetadata,
|
|
97
|
+
type SlackMessageMetadata,
|
|
98
|
+
} from "../../messaging/providers/slack/message-metadata.js";
|
|
93
99
|
import { normalizeOnboardingContext } from "../../prompts/normalize-onboarding.js";
|
|
94
100
|
import { writeOnboardingSection } from "../../prompts/persona-resolver.js";
|
|
95
101
|
import { getConfiguredProvider } from "../../providers/provider-send-message.js";
|
|
@@ -101,7 +107,6 @@ import {
|
|
|
101
107
|
getWorkspacePromptPath,
|
|
102
108
|
} from "../../util/platform.js";
|
|
103
109
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
104
|
-
import { buildAssistantEvent } from "../assistant-event.js";
|
|
105
110
|
import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
|
|
106
111
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
107
112
|
import { routeGuardianReply } from "../guardian-reply-router.js";
|
|
@@ -114,6 +119,10 @@ import type {
|
|
|
114
119
|
} from "../http-types.js";
|
|
115
120
|
import { resolveLocalTrustContext } from "../local-actor-identity.js";
|
|
116
121
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
122
|
+
import {
|
|
123
|
+
publishConversationListAndMetadataChanged,
|
|
124
|
+
publishConversationMessagesChanged,
|
|
125
|
+
} from "../sync/resource-sync-events.js";
|
|
117
126
|
import {
|
|
118
127
|
resolveTrustContext,
|
|
119
128
|
withSourceChannel,
|
|
@@ -138,6 +147,36 @@ function isValidRiskThreshold(value: unknown): value is RiskThreshold {
|
|
|
138
147
|
);
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
function buildSlackHistoryMessage(
|
|
151
|
+
slackMeta: SlackMessageMetadata | null,
|
|
152
|
+
): RuntimeMessagePayload["slackMessage"] | undefined {
|
|
153
|
+
if (!slackMeta) return undefined;
|
|
154
|
+
|
|
155
|
+
const slackConfig = getConfig().slack;
|
|
156
|
+
const messageLink = buildSlackMessageDeepLinks({
|
|
157
|
+
teamId: slackConfig?.teamId,
|
|
158
|
+
teamUrl: slackConfig?.teamUrl,
|
|
159
|
+
channelId: slackMeta.channelId,
|
|
160
|
+
messageTs: slackMeta.channelTs,
|
|
161
|
+
});
|
|
162
|
+
const threadLink = slackMeta.threadTs
|
|
163
|
+
? buildSlackMessageDeepLinks({
|
|
164
|
+
teamId: slackConfig?.teamId,
|
|
165
|
+
teamUrl: slackConfig?.teamUrl,
|
|
166
|
+
channelId: slackMeta.channelId,
|
|
167
|
+
messageTs: slackMeta.threadTs,
|
|
168
|
+
})
|
|
169
|
+
: undefined;
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
channelId: slackMeta.channelId,
|
|
173
|
+
channelTs: slackMeta.channelTs,
|
|
174
|
+
...(slackMeta.threadTs ? { threadTs: slackMeta.threadTs } : {}),
|
|
175
|
+
...(messageLink ? { messageLink } : {}),
|
|
176
|
+
...(threadLink ? { threadLink } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
141
180
|
function collectCanonicalGuardianRequestHintIds(
|
|
142
181
|
conversationId: string,
|
|
143
182
|
sourceChannel: string,
|
|
@@ -339,6 +378,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
339
378
|
});
|
|
340
379
|
onEvent({ type: "message_complete", conversationId: conversationId });
|
|
341
380
|
}
|
|
381
|
+
publishConversationMessagesChanged(conversationId);
|
|
342
382
|
} catch (err) {
|
|
343
383
|
log.warn(
|
|
344
384
|
{ err, conversationId },
|
|
@@ -506,6 +546,9 @@ export function handleListMessages(
|
|
|
506
546
|
...(typeof n.conversationId === "string"
|
|
507
547
|
? { conversationId: n.conversationId }
|
|
508
548
|
: {}),
|
|
549
|
+
...(typeof n.objective === "string"
|
|
550
|
+
? { objective: n.objective }
|
|
551
|
+
: {}),
|
|
509
552
|
};
|
|
510
553
|
}
|
|
511
554
|
}
|
|
@@ -513,6 +556,9 @@ export function handleListMessages(
|
|
|
513
556
|
// Ignore malformed metadata
|
|
514
557
|
}
|
|
515
558
|
}
|
|
559
|
+
const slackMessage = buildSlackHistoryMessage(
|
|
560
|
+
readSlackMetadataFromMessageMetadata(msg.metadata),
|
|
561
|
+
);
|
|
516
562
|
|
|
517
563
|
// Strip <no_response/> markers from assistant messages so web/API
|
|
518
564
|
// clients never see the raw sentinel. Only assistant messages produce
|
|
@@ -552,6 +598,7 @@ export function handleListMessages(
|
|
|
552
598
|
textSegments: filteredSegments,
|
|
553
599
|
contentOrder: filteredContentOrder,
|
|
554
600
|
surfaces: rendered.surfaces,
|
|
601
|
+
slackMessage,
|
|
555
602
|
...(rendered.thinkingSegments.length > 0
|
|
556
603
|
? { thinkingSegments: rendered.thinkingSegments }
|
|
557
604
|
: {}),
|
|
@@ -570,6 +617,7 @@ export function handleListMessages(
|
|
|
570
617
|
textSegments: rendered.textSegments,
|
|
571
618
|
contentOrder: rendered.contentOrder,
|
|
572
619
|
surfaces: rendered.surfaces,
|
|
620
|
+
slackMessage,
|
|
573
621
|
...(rendered.thinkingSegments.length > 0
|
|
574
622
|
? { thinkingSegments: rendered.thinkingSegments }
|
|
575
623
|
: {}),
|
|
@@ -678,6 +726,7 @@ export function handleListMessages(
|
|
|
678
726
|
...(m.subagentNotification
|
|
679
727
|
? { subagentNotification: m.subagentNotification }
|
|
680
728
|
: {}),
|
|
729
|
+
...(m.slackMessage ? { slackMessage: m.slackMessage } : {}),
|
|
681
730
|
};
|
|
682
731
|
});
|
|
683
732
|
|
|
@@ -1117,6 +1166,8 @@ export async function handleSendMessage(
|
|
|
1117
1166
|
tone: string;
|
|
1118
1167
|
userName?: string;
|
|
1119
1168
|
assistantName?: string;
|
|
1169
|
+
googleConnected?: boolean;
|
|
1170
|
+
googleScopes?: string[];
|
|
1120
1171
|
};
|
|
1121
1172
|
};
|
|
1122
1173
|
|
|
@@ -1293,16 +1344,10 @@ export async function handleSendMessage(
|
|
|
1293
1344
|
// that other clients don't yet know about.
|
|
1294
1345
|
if (mapping.conversationType === "standard") {
|
|
1295
1346
|
if (!hasMessages(mapping.conversationId)) {
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
reason: "created",
|
|
1301
|
-
}),
|
|
1302
|
-
)
|
|
1303
|
-
.catch((err) => {
|
|
1304
|
-
log.warn({ err }, "Failed to publish conversation_list_invalidated");
|
|
1305
|
-
});
|
|
1347
|
+
publishConversationListAndMetadataChanged(
|
|
1348
|
+
"created",
|
|
1349
|
+
mapping.conversationId,
|
|
1350
|
+
);
|
|
1306
1351
|
}
|
|
1307
1352
|
}
|
|
1308
1353
|
|
|
@@ -1509,6 +1554,18 @@ export async function handleSendMessage(
|
|
|
1509
1554
|
|
|
1510
1555
|
if (isFirstOnboarding) {
|
|
1511
1556
|
persistOnboardingArtifacts(body.onboarding!);
|
|
1557
|
+
try {
|
|
1558
|
+
recordOnboardingEvent({
|
|
1559
|
+
screen: "complete",
|
|
1560
|
+
tools: body.onboarding!.tools,
|
|
1561
|
+
tasks: body.onboarding!.tasks,
|
|
1562
|
+
tone: body.onboarding!.tone,
|
|
1563
|
+
googleConnected: body.onboarding!.googleConnected,
|
|
1564
|
+
googleScopes: body.onboarding!.googleScopes,
|
|
1565
|
+
});
|
|
1566
|
+
} catch (err) {
|
|
1567
|
+
log.warn({ err }, "Failed to record onboarding telemetry event");
|
|
1568
|
+
}
|
|
1512
1569
|
}
|
|
1513
1570
|
|
|
1514
1571
|
setTimeout(() => {
|
|
@@ -1525,6 +1582,7 @@ export async function handleSendMessage(
|
|
|
1525
1582
|
conversationId,
|
|
1526
1583
|
});
|
|
1527
1584
|
broadcastMessage({ type: "message_complete", conversationId });
|
|
1585
|
+
publishConversationMessagesChanged(conversationId);
|
|
1528
1586
|
conversation.processing = false;
|
|
1529
1587
|
silentlyWithLog(
|
|
1530
1588
|
conversation.drainQueue(),
|
|
@@ -1550,6 +1608,18 @@ export async function handleSendMessage(
|
|
|
1550
1608
|
|
|
1551
1609
|
if (isFirstOnboarding) {
|
|
1552
1610
|
persistOnboardingArtifacts(body.onboarding!);
|
|
1611
|
+
try {
|
|
1612
|
+
recordOnboardingEvent({
|
|
1613
|
+
screen: "complete",
|
|
1614
|
+
tools: body.onboarding!.tools,
|
|
1615
|
+
tasks: body.onboarding!.tasks,
|
|
1616
|
+
tone: body.onboarding!.tone,
|
|
1617
|
+
googleConnected: body.onboarding!.googleConnected,
|
|
1618
|
+
googleScopes: body.onboarding!.googleScopes,
|
|
1619
|
+
});
|
|
1620
|
+
} catch (err) {
|
|
1621
|
+
log.warn({ err }, "Failed to record onboarding telemetry event");
|
|
1622
|
+
}
|
|
1553
1623
|
}
|
|
1554
1624
|
|
|
1555
1625
|
const attachments = hasAttachments
|
|
@@ -1828,6 +1898,7 @@ export async function handleSendMessage(
|
|
|
1828
1898
|
type: "message_complete",
|
|
1829
1899
|
conversationId: conversationId,
|
|
1830
1900
|
});
|
|
1901
|
+
publishConversationMessagesChanged(conversationId);
|
|
1831
1902
|
conversation.processing = false;
|
|
1832
1903
|
silentlyWithLog(conversation.drainQueue(), "slash-command queue drain");
|
|
1833
1904
|
}, 0);
|
|
@@ -1869,6 +1940,7 @@ export async function handleSendMessage(
|
|
|
1869
1940
|
// forceCompact() makes an LLM call that can exceed the client's
|
|
1870
1941
|
// HTTP timeout on large contexts, causing a false "Failed to send".
|
|
1871
1942
|
(async () => {
|
|
1943
|
+
let assistantMessagePersisted = false;
|
|
1872
1944
|
try {
|
|
1873
1945
|
broadcastMessage({
|
|
1874
1946
|
type: "user_message_echo",
|
|
@@ -1877,6 +1949,7 @@ export async function handleSendMessage(
|
|
|
1877
1949
|
messageId: persisted.id,
|
|
1878
1950
|
clientMessageId,
|
|
1879
1951
|
});
|
|
1952
|
+
publishConversationMessagesChanged(conversationId);
|
|
1880
1953
|
conversation.emitActivityState(
|
|
1881
1954
|
"thinking",
|
|
1882
1955
|
"context_compacting",
|
|
@@ -1894,6 +1967,7 @@ export async function handleSendMessage(
|
|
|
1894
1967
|
JSON.stringify(assistantMsg.content),
|
|
1895
1968
|
channelMeta,
|
|
1896
1969
|
);
|
|
1970
|
+
assistantMessagePersisted = true;
|
|
1897
1971
|
conversation.getMessages().push(assistantMsg);
|
|
1898
1972
|
|
|
1899
1973
|
broadcastMessage({
|
|
@@ -1902,7 +1976,11 @@ export async function handleSendMessage(
|
|
|
1902
1976
|
conversationId,
|
|
1903
1977
|
});
|
|
1904
1978
|
broadcastMessage({ type: "message_complete", conversationId });
|
|
1979
|
+
publishConversationMessagesChanged(conversationId);
|
|
1905
1980
|
} catch (err) {
|
|
1981
|
+
if (assistantMessagePersisted) {
|
|
1982
|
+
publishConversationMessagesChanged(conversationId);
|
|
1983
|
+
}
|
|
1906
1984
|
log.error({ err, conversationId }, "Compact command failed");
|
|
1907
1985
|
broadcastMessage({
|
|
1908
1986
|
type: "conversation_error",
|
|
@@ -1950,6 +2028,7 @@ export async function handleSendMessage(
|
|
|
1950
2028
|
requestId,
|
|
1951
2029
|
clientMessageId,
|
|
1952
2030
|
});
|
|
2031
|
+
publishConversationMessagesChanged(mapping.conversationId);
|
|
1953
2032
|
|
|
1954
2033
|
// Fire-and-forget the agent loop; events flow to the hub via broadcastMessage.
|
|
1955
2034
|
conversation
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
getDocumentById,
|
|
11
|
+
getDocumentsForConversation,
|
|
12
|
+
saveDocument,
|
|
13
|
+
} from "../../documents/document-store.js";
|
|
14
|
+
import { rawAll } from "../../memory/raw-query.js";
|
|
11
15
|
import { getLogger } from "../../util/logger.js";
|
|
12
16
|
import { renderMarkdownToPDF } from "./document-pdf-renderer.js";
|
|
13
17
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
@@ -16,65 +20,16 @@ import { RouteResponse } from "./types.js";
|
|
|
16
20
|
|
|
17
21
|
const log = getLogger("documents-routes");
|
|
18
22
|
|
|
19
|
-
interface
|
|
23
|
+
interface DocumentListRow {
|
|
20
24
|
surface_id: string;
|
|
21
25
|
conversation_id: string;
|
|
22
26
|
title: string;
|
|
23
|
-
content: string;
|
|
24
27
|
word_count: number;
|
|
25
28
|
created_at: number;
|
|
26
29
|
updated_at: number;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
function loadDocument(surfaceId: string):
|
|
32
|
-
| {
|
|
33
|
-
success: true;
|
|
34
|
-
surfaceId: string;
|
|
35
|
-
conversationId: string;
|
|
36
|
-
title: string;
|
|
37
|
-
content: string;
|
|
38
|
-
wordCount: number;
|
|
39
|
-
createdAt: number;
|
|
40
|
-
updatedAt: number;
|
|
41
|
-
}
|
|
42
|
-
| { success: false; error: string } {
|
|
43
|
-
try {
|
|
44
|
-
const result = rawGet<DocumentRow>(
|
|
45
|
-
/*sql*/ `
|
|
46
|
-
SELECT surface_id, conversation_id, title, content, word_count, created_at, updated_at
|
|
47
|
-
FROM documents
|
|
48
|
-
WHERE surface_id = ?
|
|
49
|
-
`,
|
|
50
|
-
surfaceId,
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
if (result) {
|
|
54
|
-
log.info({ surfaceId }, "Loaded document");
|
|
55
|
-
return {
|
|
56
|
-
success: true,
|
|
57
|
-
surfaceId: result.surface_id,
|
|
58
|
-
conversationId: result.conversation_id,
|
|
59
|
-
title: result.title,
|
|
60
|
-
content: result.content,
|
|
61
|
-
wordCount: result.word_count,
|
|
62
|
-
createdAt: result.created_at,
|
|
63
|
-
updatedAt: result.updated_at,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
log.info({ surfaceId }, "Document not found");
|
|
67
|
-
return { success: false, error: "Document not found" };
|
|
68
|
-
} catch (error) {
|
|
69
|
-
log.error({ err: error, surfaceId }, "Load error");
|
|
70
|
-
return {
|
|
71
|
-
success: false,
|
|
72
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function listDocuments(conversationId?: string): Array<{
|
|
32
|
+
function listAllDocuments(): Array<{
|
|
78
33
|
surfaceId: string;
|
|
79
34
|
conversationId: string;
|
|
80
35
|
title: string;
|
|
@@ -83,29 +38,11 @@ function listDocuments(conversationId?: string): Array<{
|
|
|
83
38
|
updatedAt: number;
|
|
84
39
|
}> {
|
|
85
40
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
results = rawAll<DocumentListRow>(
|
|
92
|
-
/*sql*/ `
|
|
93
|
-
SELECT d.surface_id, dc.conversation_id AS conversation_id,
|
|
94
|
-
d.title, d.word_count, d.created_at, d.updated_at
|
|
95
|
-
FROM documents d
|
|
96
|
-
INNER JOIN document_conversations dc ON d.surface_id = dc.surface_id
|
|
97
|
-
WHERE dc.conversation_id = ?
|
|
98
|
-
ORDER BY d.updated_at DESC
|
|
99
|
-
`,
|
|
100
|
-
conversationId,
|
|
101
|
-
);
|
|
102
|
-
} else {
|
|
103
|
-
results = rawAll<DocumentListRow>(/*sql*/ `
|
|
104
|
-
SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
|
|
105
|
-
FROM documents
|
|
106
|
-
ORDER BY updated_at DESC
|
|
107
|
-
`);
|
|
108
|
-
}
|
|
41
|
+
const results = rawAll<DocumentListRow>(/*sql*/ `
|
|
42
|
+
SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
|
|
43
|
+
FROM documents
|
|
44
|
+
ORDER BY updated_at DESC
|
|
45
|
+
`);
|
|
109
46
|
|
|
110
47
|
log.info({ count: results.length }, "Listed documents");
|
|
111
48
|
return results.map((row) => ({
|
|
@@ -148,7 +85,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
148
85
|
}),
|
|
149
86
|
handler: ({ queryParams }) => {
|
|
150
87
|
const conversationId = queryParams?.conversationId ?? undefined;
|
|
151
|
-
const documents =
|
|
88
|
+
const documents = conversationId
|
|
89
|
+
? getDocumentsForConversation(conversationId)
|
|
90
|
+
: listAllDocuments();
|
|
152
91
|
return { documents };
|
|
153
92
|
},
|
|
154
93
|
},
|
|
@@ -173,11 +112,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
173
112
|
updatedAt: z.number(),
|
|
174
113
|
}),
|
|
175
114
|
handler: ({ pathParams }) => {
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
178
|
-
throw new NotFoundError(
|
|
115
|
+
const doc = getDocumentById(pathParams!.id);
|
|
116
|
+
if (!doc) {
|
|
117
|
+
throw new NotFoundError("Document not found");
|
|
179
118
|
}
|
|
180
|
-
return
|
|
119
|
+
return { success: true, ...doc };
|
|
181
120
|
},
|
|
182
121
|
},
|
|
183
122
|
|
|
@@ -252,13 +191,13 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
252
191
|
description: "Render a document to PDF and return the binary content.",
|
|
253
192
|
tags: ["documents"],
|
|
254
193
|
handler: async ({ pathParams }) => {
|
|
255
|
-
const
|
|
256
|
-
if (!
|
|
257
|
-
throw new NotFoundError(
|
|
194
|
+
const doc = getDocumentById(pathParams!.id);
|
|
195
|
+
if (!doc) {
|
|
196
|
+
throw new NotFoundError("Document not found");
|
|
258
197
|
}
|
|
259
|
-
const pdfBuffer = await renderMarkdownToPDF(
|
|
198
|
+
const pdfBuffer = await renderMarkdownToPDF(doc.title, doc.content);
|
|
260
199
|
const filename =
|
|
261
|
-
|
|
200
|
+
doc.title
|
|
262
201
|
.replace(/[^a-zA-Z0-9_-]/g, "-")
|
|
263
202
|
.replace(/-+/g, "-")
|
|
264
203
|
.replace(/^-|-$/g, "") || "document";
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
reorderGroups,
|
|
19
19
|
updateGroup,
|
|
20
20
|
} from "../../memory/group-crud.js";
|
|
21
|
+
import { publishConversationListChanged } from "../sync/resource-sync-events.js";
|
|
21
22
|
import { BadRequestError, ForbiddenError, NotFoundError } from "./errors.js";
|
|
22
23
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
23
24
|
|
|
@@ -47,6 +48,7 @@ function handleCreateGroup({ body = {} }: RouteHandlerArgs) {
|
|
|
47
48
|
}
|
|
48
49
|
try {
|
|
49
50
|
const group = createGroup(name);
|
|
51
|
+
publishConversationListChanged("created");
|
|
50
52
|
return serializeGroup(group);
|
|
51
53
|
} catch (err) {
|
|
52
54
|
if (
|
|
@@ -90,6 +92,7 @@ function handleUpdateGroup({ pathParams = {}, body = {} }: RouteHandlerArgs) {
|
|
|
90
92
|
if (!updated) {
|
|
91
93
|
throw new NotFoundError("Group not found");
|
|
92
94
|
}
|
|
95
|
+
publishConversationListChanged("reordered");
|
|
93
96
|
return serializeGroup(updated);
|
|
94
97
|
}
|
|
95
98
|
|
|
@@ -103,6 +106,7 @@ function handleDeleteGroup({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
103
106
|
throw new ForbiddenError("System groups cannot be deleted");
|
|
104
107
|
}
|
|
105
108
|
deleteGroup(groupId);
|
|
109
|
+
publishConversationListChanged("reordered");
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
function handleReorderGroups({ body = {} }: RouteHandlerArgs) {
|
|
@@ -131,6 +135,7 @@ function handleReorderGroups({ body = {} }: RouteHandlerArgs) {
|
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
reorderGroups(updates);
|
|
138
|
+
publishConversationListChanged("reordered");
|
|
134
139
|
return { ok: true };
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Channel conversation deletion handler.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
deleteConversationKey,
|
|
6
|
+
getOrCreateConversation,
|
|
7
|
+
} from "../../memory/conversation-key-store.js";
|
|
8
|
+
import { buildScopedConversationKey } from "../../memory/delivery-crud.js";
|
|
9
|
+
import {
|
|
10
|
+
deleteBindingByChannelChat,
|
|
11
|
+
deleteBindingByChannelChatThread,
|
|
12
|
+
} from "../../memory/external-conversation-store.js";
|
|
7
13
|
import { BadRequestError } from "./errors.js";
|
|
8
14
|
import type { RouteHandlerArgs } from "./types.js";
|
|
9
15
|
|
|
10
16
|
export function handleDeleteConversation({ body = {} }: RouteHandlerArgs) {
|
|
11
|
-
const { sourceChannel, conversationExternalId } = body as {
|
|
17
|
+
const { sourceChannel, conversationExternalId, sourceThreadId } = body as {
|
|
12
18
|
sourceChannel?: string;
|
|
13
19
|
conversationExternalId?: string;
|
|
20
|
+
sourceThreadId?: string;
|
|
14
21
|
};
|
|
15
22
|
|
|
16
23
|
if (!sourceChannel || typeof sourceChannel !== "string") {
|
|
@@ -20,14 +27,27 @@ export function handleDeleteConversation({ body = {} }: RouteHandlerArgs) {
|
|
|
20
27
|
throw new BadRequestError("conversationExternalId is required");
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
const
|
|
30
|
+
const normalizedThreadId = sourceThreadId?.trim() || undefined;
|
|
24
31
|
|
|
25
|
-
const scopedKey =
|
|
32
|
+
const scopedKey = buildScopedConversationKey(
|
|
33
|
+
sourceChannel,
|
|
34
|
+
conversationExternalId,
|
|
35
|
+
normalizedThreadId,
|
|
36
|
+
);
|
|
26
37
|
deleteConversationKey(scopedKey);
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
const legacyKey = `${sourceChannel}:${conversationExternalId}`;
|
|
39
|
+
if (!normalizedThreadId) {
|
|
29
40
|
deleteConversationKey(legacyKey);
|
|
30
41
|
deleteBindingByChannelChat(sourceChannel, conversationExternalId);
|
|
42
|
+
} else {
|
|
43
|
+
if (sourceChannel === "slack") {
|
|
44
|
+
getOrCreateConversation(scopedKey);
|
|
45
|
+
}
|
|
46
|
+
deleteBindingByChannelChatThread(
|
|
47
|
+
sourceChannel,
|
|
48
|
+
conversationExternalId,
|
|
49
|
+
normalizedThreadId,
|
|
50
|
+
);
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
return { ok: true };
|