@vellumai/assistant 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docker-entrypoint.sh +0 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +610 -16
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +91 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +25 -7
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-chain.test.ts +2 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-resolver.test.ts +85 -1
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/openai-provider.test.ts +105 -0
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +51 -28
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +57 -20
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +24 -2
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +19 -0
- package/src/config/feature-flag-registry.json +99 -3
- package/src/config/llm-resolver.ts +16 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +4 -0
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-v2.ts +48 -1
- package/src/context/compactor.ts +8 -1
- package/src/context/token-estimator.ts +47 -4
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +153 -23
- package/src/daemon/conversation-agent-loop.ts +223 -54
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +135 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -5
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/config-a2a.ts +160 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +79 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +18 -4
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +69 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/trust-context.ts +6 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +6 -1
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +320 -6
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/db-init.ts +16 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +3 -2
- package/src/memory/memory-retrospective-job.ts +408 -18
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +17 -0
- package/src/memory/migrations/registry.ts +25 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +31 -14
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +21 -10
- package/src/memory/v2/page-index.ts +209 -7
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/messaging/providers/index.ts +7 -1
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/emit-signal.ts +9 -1
- package/src/notifications/home-feed-side-effect.ts +60 -30
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +82 -9
- package/src/prompts/__tests__/system-prompt.test.ts +46 -2
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -68
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +8 -0
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +53 -3
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/adapter-factory.ts +15 -1
- package/src/providers/inference/auth.ts +3 -3
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/resolve-auth.ts +49 -6
- package/src/providers/model-catalog.ts +48 -1
- package/src/providers/openai/chat-completions-provider.ts +57 -20
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +151 -56
- package/src/runtime/auth/route-policy.ts +7 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-types.ts +7 -4
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +55 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +60 -1
- package/src/runtime/routes/conversation-routes.ts +281 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +12 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
- package/src/runtime/routes/integrations/a2a.ts +60 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +4 -0
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -6,11 +6,23 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Two sources of prompts:
|
|
8
8
|
* - **Deterministic** — derived from missing OAuth connections.
|
|
9
|
+
* Computed inline (read-only, safe for GET).
|
|
9
10
|
* - **Assistant-generated** — contextual suggestions from the LLM
|
|
10
|
-
*
|
|
11
|
+
* based on what's relevant to the user. Read from an in-memory
|
|
12
|
+
* cache in the GET path; generation runs in the background via
|
|
13
|
+
* `refreshAssistantSuggestedPrompts`.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
|
-
import {
|
|
16
|
+
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
17
|
+
import { getConfig } from "../config/loader.js";
|
|
18
|
+
import { listProviders } from "../oauth/oauth-store.js";
|
|
19
|
+
import { resolvePersonaContext } from "../prompts/persona-resolver.js";
|
|
20
|
+
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
21
|
+
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
22
|
+
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
23
|
+
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
24
|
+
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
25
|
+
import { isOAuthProviderConnected } from "../schedule/integration-status.js";
|
|
14
26
|
import { getLogger } from "../util/logger.js";
|
|
15
27
|
import type { SuggestedPrompt } from "./feed-types.js";
|
|
16
28
|
|
|
@@ -72,27 +84,88 @@ const CONNECT_PROMPT_META: Record<
|
|
|
72
84
|
},
|
|
73
85
|
};
|
|
74
86
|
|
|
87
|
+
const LLM_SUGGESTIONS_TIMEOUT_MS = 5_000;
|
|
88
|
+
const LLM_CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// In-memory cache for LLM-generated suggestions
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
let cachedLLMPrompts: SuggestedPrompt[] = [];
|
|
95
|
+
let cachedLLMPromptsAt = 0;
|
|
96
|
+
|
|
75
97
|
/**
|
|
76
|
-
* Produce
|
|
77
|
-
*
|
|
78
|
-
*
|
|
98
|
+
* Produce suggested prompts from both deterministic and cached LLM sources.
|
|
99
|
+
* Deterministic prompts always come first; cached LLM-generated prompts are
|
|
100
|
+
* appended when available. No LLM calls happen in this path — safe for GET.
|
|
79
101
|
*/
|
|
80
102
|
export async function getSuggestedPrompts(): Promise<SuggestedPrompt[]> {
|
|
81
103
|
const prompts: SuggestedPrompt[] = [];
|
|
82
104
|
|
|
105
|
+
let deterministicPrompts: SuggestedPrompt[] = [];
|
|
83
106
|
try {
|
|
84
|
-
|
|
107
|
+
deterministicPrompts = await getDeterministicPrompts();
|
|
85
108
|
prompts.push(...deterministicPrompts);
|
|
86
109
|
} catch (err) {
|
|
87
110
|
log.warn({ err }, "Failed to compute deterministic suggested prompts");
|
|
88
111
|
}
|
|
89
112
|
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
|
|
114
|
+
prompts.push(...cachedLLMPrompts);
|
|
115
|
+
}
|
|
92
116
|
|
|
93
117
|
return prompts;
|
|
94
118
|
}
|
|
95
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Drops the in-memory LLM suggestion cache so the next call to
|
|
122
|
+
* `getSuggestedPrompts()` returns only the fresh deterministic list (and
|
|
123
|
+
* a follow-up background refresh repopulates the LLM half).
|
|
124
|
+
*
|
|
125
|
+
* Called from OAuth connect/disconnect paths so a freshly-connected
|
|
126
|
+
* provider stops surfacing as a "Connect X" pill within one reload — the
|
|
127
|
+
* 30-minute TTL would otherwise pin a stale suggestion until the next
|
|
128
|
+
* periodic refresh.
|
|
129
|
+
*/
|
|
130
|
+
export function invalidateAssistantSuggestedPromptsCache(): void {
|
|
131
|
+
cachedLLMPrompts = [];
|
|
132
|
+
cachedLLMPromptsAt = 0;
|
|
133
|
+
assistantEventHub
|
|
134
|
+
.publish(
|
|
135
|
+
buildAssistantEvent({
|
|
136
|
+
type: "home_feed_updated",
|
|
137
|
+
updatedAt: new Date().toISOString(),
|
|
138
|
+
newItemCount: 0,
|
|
139
|
+
}),
|
|
140
|
+
)
|
|
141
|
+
.catch((err) => {
|
|
142
|
+
log.warn(
|
|
143
|
+
{ err },
|
|
144
|
+
"Failed to publish home_feed_updated after prompt cache invalidation",
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate LLM-based suggestion prompts and write them to the in-memory
|
|
151
|
+
* cache. No-ops when the cache is still fresh. Intended for background
|
|
152
|
+
* invocation (daemon startup / periodic refresh), not the GET path.
|
|
153
|
+
*/
|
|
154
|
+
export async function refreshAssistantSuggestedPrompts(): Promise<void> {
|
|
155
|
+
if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const deterministicPrompts = await getDeterministicPrompts();
|
|
161
|
+
const llmPrompts = await generateAssistantPrompts(deterministicPrompts);
|
|
162
|
+
cachedLLMPrompts = llmPrompts;
|
|
163
|
+
cachedLLMPromptsAt = Date.now();
|
|
164
|
+
} catch (err) {
|
|
165
|
+
log.warn({ err }, "Failed to refresh assistant suggested prompts");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
96
169
|
/**
|
|
97
170
|
* Check which well-known OAuth providers are not connected and return
|
|
98
171
|
* a "Connect X" prompt for each. For connected providers that have
|
|
@@ -107,7 +180,7 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
|
|
|
107
180
|
const meta = CONNECT_PROMPT_META[provider.provider];
|
|
108
181
|
if (!meta) continue;
|
|
109
182
|
|
|
110
|
-
const connected = await
|
|
183
|
+
const connected = await isOAuthProviderConnected(provider.provider);
|
|
111
184
|
|
|
112
185
|
if (!connected) {
|
|
113
186
|
prompts.push({
|
|
@@ -135,3 +208,98 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
|
|
|
135
208
|
|
|
136
209
|
return prompts;
|
|
137
210
|
}
|
|
211
|
+
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// LLM-generated suggestions
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
interface LLMSuggestion {
|
|
217
|
+
label: string;
|
|
218
|
+
prompt: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Ask the LLM to generate contextual conversation-starter suggestions
|
|
223
|
+
* based on the assistant's persona and the user's connected services.
|
|
224
|
+
* Returns an empty array on failure so deterministic prompts still show.
|
|
225
|
+
*/
|
|
226
|
+
async function generateAssistantPrompts(
|
|
227
|
+
deterministicPrompts: SuggestedPrompt[],
|
|
228
|
+
): Promise<SuggestedPrompt[]> {
|
|
229
|
+
const config = getConfig();
|
|
230
|
+
const resolved = resolveCallSiteConfig("homeSuggestedPrompts", config.llm);
|
|
231
|
+
|
|
232
|
+
const provider = await getConfiguredProvider("homeSuggestedPrompts");
|
|
233
|
+
if (!provider) {
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
|
|
238
|
+
undefined,
|
|
239
|
+
undefined,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const systemPrompt = buildSystemPrompt({
|
|
243
|
+
excludeBootstrap: true,
|
|
244
|
+
excludeCustomPrefix: true,
|
|
245
|
+
userPersona,
|
|
246
|
+
channelPersona,
|
|
247
|
+
userSlug,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const existingLabels = deterministicPrompts.map((p) => p.label).join(", ");
|
|
251
|
+
const contextNote = existingLabels
|
|
252
|
+
? `The user already has these suggestions: ${existingLabels}. Do NOT duplicate them.`
|
|
253
|
+
: "";
|
|
254
|
+
|
|
255
|
+
const result = await runBtwSidechain({
|
|
256
|
+
content:
|
|
257
|
+
"Suggest 2-3 short, actionable conversation starters for the home page. " +
|
|
258
|
+
"Each should be something specific and helpful you can do for the user right now. " +
|
|
259
|
+
`${contextNote} ` +
|
|
260
|
+
'Return ONLY a JSON array of objects with "label" (max 5 words) and "prompt" (the full message to send). ' +
|
|
261
|
+
"No markdown fences, no explanation.",
|
|
262
|
+
provider,
|
|
263
|
+
systemPrompt,
|
|
264
|
+
messages: [],
|
|
265
|
+
tools: [],
|
|
266
|
+
callSite: "homeSuggestedPrompts",
|
|
267
|
+
maxTokens: resolved.maxTokens,
|
|
268
|
+
timeoutMs: LLM_SUGGESTIONS_TIMEOUT_MS,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const text = result.text.trim();
|
|
272
|
+
if (!text) {
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const parsed = parseLLMSuggestions(text);
|
|
277
|
+
return parsed.map((s, i) => ({
|
|
278
|
+
id: `assistant-${i}-${s.label.toLowerCase().replace(/\s+/g, "-")}`,
|
|
279
|
+
label: s.label,
|
|
280
|
+
prompt: s.prompt,
|
|
281
|
+
source: "assistant" as const,
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function parseLLMSuggestions(text: string): LLMSuggestion[] {
|
|
286
|
+
try {
|
|
287
|
+
const cleaned = text
|
|
288
|
+
.replace(/^```(?:json)?\n?/m, "")
|
|
289
|
+
.replace(/\n?```$/m, "");
|
|
290
|
+
const parsed = JSON.parse(cleaned);
|
|
291
|
+
if (!Array.isArray(parsed)) {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
return parsed.filter(
|
|
295
|
+
(item): item is LLMSuggestion =>
|
|
296
|
+
typeof item === "object" &&
|
|
297
|
+
item !== null &&
|
|
298
|
+
typeof item.label === "string" &&
|
|
299
|
+
typeof item.prompt === "string",
|
|
300
|
+
);
|
|
301
|
+
} catch {
|
|
302
|
+
log.warn("Failed to parse LLM suggestions response");
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Tests use a temp workspace pinned via `VELLUM_WORKSPACE_DIR` so the DB
|
|
20
20
|
* lives under `tmpdir()` and `~/.vellum/` is never touched.
|
|
21
21
|
*/
|
|
22
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
22
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
23
23
|
import { tmpdir } from "node:os";
|
|
24
24
|
import { join } from "node:path";
|
|
25
25
|
import {
|
|
@@ -66,7 +66,7 @@ const { initializeDb } = await import("../db-init.js");
|
|
|
66
66
|
const { resetTestTables } = await import("../raw-query.js");
|
|
67
67
|
const { memoryJobs } = await import("../schema.js");
|
|
68
68
|
const { applyNestedDefaults } = await import("../../config/loader.js");
|
|
69
|
-
const { setMemoryCheckpoint, deleteMemoryCheckpoint } =
|
|
69
|
+
const { getMemoryCheckpoint, setMemoryCheckpoint, deleteMemoryCheckpoint } =
|
|
70
70
|
await import("../checkpoints.js");
|
|
71
71
|
const { maybeEnqueueGraphMaintenanceJobs } = await import("../jobs-worker.js");
|
|
72
72
|
|
|
@@ -75,6 +75,7 @@ const CONSOLIDATE_CHECKPOINT_KEY = "memory_v2_consolidate_last_run";
|
|
|
75
75
|
function buildConfig(overrides: {
|
|
76
76
|
v2Enabled?: boolean;
|
|
77
77
|
intervalHours?: number;
|
|
78
|
+
maxBufferLines?: number | null;
|
|
78
79
|
}) {
|
|
79
80
|
const partial = applyNestedDefaults({});
|
|
80
81
|
if (overrides.v2Enabled !== undefined) {
|
|
@@ -83,9 +84,26 @@ function buildConfig(overrides: {
|
|
|
83
84
|
if (overrides.intervalHours !== undefined) {
|
|
84
85
|
partial.memory.v2.consolidation_interval_hours = overrides.intervalHours;
|
|
85
86
|
}
|
|
87
|
+
if (overrides.maxBufferLines !== undefined) {
|
|
88
|
+
partial.memory.v2.consolidation_max_buffer_lines = overrides.maxBufferLines;
|
|
89
|
+
}
|
|
86
90
|
return partial;
|
|
87
91
|
}
|
|
88
92
|
|
|
93
|
+
function writeBuffer(lineCount: number): void {
|
|
94
|
+
const memoryDir = join(tmpWorkspace, "memory");
|
|
95
|
+
mkdirSync(memoryDir, { recursive: true });
|
|
96
|
+
const entries = Array.from(
|
|
97
|
+
{ length: lineCount },
|
|
98
|
+
(_, i) => `- [Jan 15, 2:${String(i).padStart(2, "0")} PM] note ${i}`,
|
|
99
|
+
);
|
|
100
|
+
writeFileSync(join(memoryDir, "buffer.md"), entries.join("\n") + "\n");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function removeBuffer(): void {
|
|
104
|
+
rmSync(join(tmpWorkspace, "memory", "buffer.md"), { force: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
89
107
|
function countPendingJobs(type: string): number {
|
|
90
108
|
return getDb()
|
|
91
109
|
.select()
|
|
@@ -216,3 +234,118 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
216
234
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
217
235
|
});
|
|
218
236
|
});
|
|
237
|
+
|
|
238
|
+
describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
|
|
239
|
+
test("default threshold (100 lines) fires once the buffer reaches it", () => {
|
|
240
|
+
const config = buildConfig({ v2Enabled: true, intervalHours: 1 });
|
|
241
|
+
|
|
242
|
+
const now = Date.now();
|
|
243
|
+
// Recent checkpoint so the time-based trigger does not fire.
|
|
244
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
245
|
+
writeBuffer(100);
|
|
246
|
+
|
|
247
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
248
|
+
|
|
249
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("explicit null disables the size trigger", () => {
|
|
253
|
+
const config = buildConfig({
|
|
254
|
+
v2Enabled: true,
|
|
255
|
+
intervalHours: 1,
|
|
256
|
+
maxBufferLines: null,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const now = Date.now();
|
|
260
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
261
|
+
writeBuffer(500);
|
|
262
|
+
|
|
263
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
264
|
+
|
|
265
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("enqueues when buffer reaches the threshold even if interval not elapsed", () => {
|
|
269
|
+
const config = buildConfig({
|
|
270
|
+
v2Enabled: true,
|
|
271
|
+
intervalHours: 1,
|
|
272
|
+
maxBufferLines: 5,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const now = Date.now();
|
|
276
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
277
|
+
writeBuffer(10);
|
|
278
|
+
|
|
279
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
280
|
+
|
|
281
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
282
|
+
// Checkpoint refreshed so the next tick doesn't immediately re-fire.
|
|
283
|
+
expect(getMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY)).toBe(String(now));
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("does not enqueue when buffer is under the threshold", () => {
|
|
287
|
+
const config = buildConfig({
|
|
288
|
+
v2Enabled: true,
|
|
289
|
+
intervalHours: 1,
|
|
290
|
+
maxBufferLines: 5,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const now = Date.now();
|
|
294
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
295
|
+
writeBuffer(3);
|
|
296
|
+
|
|
297
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
298
|
+
|
|
299
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test("treats missing buffer file as zero lines", () => {
|
|
303
|
+
const config = buildConfig({
|
|
304
|
+
v2Enabled: true,
|
|
305
|
+
intervalHours: 1,
|
|
306
|
+
maxBufferLines: 1,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const now = Date.now();
|
|
310
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
311
|
+
removeBuffer();
|
|
312
|
+
|
|
313
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
314
|
+
|
|
315
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("does not double-enqueue when both triggers would fire", () => {
|
|
319
|
+
const config = buildConfig({
|
|
320
|
+
v2Enabled: true,
|
|
321
|
+
intervalHours: 1,
|
|
322
|
+
maxBufferLines: 5,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const now = Date.now();
|
|
326
|
+
// Stale checkpoint so time-based fires, AND buffer over threshold.
|
|
327
|
+
setMemoryCheckpoint(
|
|
328
|
+
CONSOLIDATE_CHECKPOINT_KEY,
|
|
329
|
+
String(now - 2 * 60 * 60 * 1000),
|
|
330
|
+
);
|
|
331
|
+
writeBuffer(10);
|
|
332
|
+
|
|
333
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
334
|
+
|
|
335
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("size trigger inert when v2 is disabled", () => {
|
|
339
|
+
const config = buildConfig({
|
|
340
|
+
v2Enabled: false,
|
|
341
|
+
intervalHours: 1,
|
|
342
|
+
maxBufferLines: 1,
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
writeBuffer(100);
|
|
346
|
+
|
|
347
|
+
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
348
|
+
|
|
349
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
350
|
+
});
|
|
351
|
+
});
|