@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
package/src/memory/v2/router.ts
CHANGED
|
@@ -47,7 +47,15 @@ import type {
|
|
|
47
47
|
ToolDefinition,
|
|
48
48
|
} from "../../providers/types.js";
|
|
49
49
|
import { getLogger } from "../../util/logger.js";
|
|
50
|
-
import {
|
|
50
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
51
|
+
import { computeInjectionScores } from "./injection-events.js";
|
|
52
|
+
import type { PageIndex } from "./page-index.js";
|
|
53
|
+
import {
|
|
54
|
+
getPageIndex,
|
|
55
|
+
partitionPageIndex,
|
|
56
|
+
splitTier1,
|
|
57
|
+
splitTier2,
|
|
58
|
+
} from "./page-index.js";
|
|
51
59
|
import { resolveRouterPrompt } from "./prompts/router.js";
|
|
52
60
|
import type { EverInjectedEntry } from "./types.js";
|
|
53
61
|
|
|
@@ -66,14 +74,28 @@ export type RouterFailureReason =
|
|
|
66
74
|
| "api_error"
|
|
67
75
|
| "empty_index";
|
|
68
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Tags which batch a router-selected slug came from. Tier 3 carries the
|
|
79
|
+
* batch index so the inspector can distinguish e.g. `tier3:0` from
|
|
80
|
+
* `tier3:3` — useful for debugging hash bucketing and batch-quality
|
|
81
|
+
* regressions per tier 3 bucket.
|
|
82
|
+
*/
|
|
83
|
+
export type RouterSource = "tier1" | "tier2" | `tier3:${number}`;
|
|
84
|
+
|
|
69
85
|
/**
|
|
70
86
|
* Result of a single router call. `selectedSlugs` preserves the order the
|
|
71
87
|
* model returned and is already capped at `config.memory.v2.router.max_page_ids`
|
|
72
|
-
* with out-of-range IDs dropped.
|
|
88
|
+
* with out-of-range IDs dropped. `sourceBySlug` attributes each selection
|
|
89
|
+
* to the batch it came from for inspector display.
|
|
73
90
|
*/
|
|
74
91
|
export interface RouterResult {
|
|
75
92
|
/** Selected page slugs in the order the model returned them. */
|
|
76
93
|
selectedSlugs: string[];
|
|
94
|
+
/**
|
|
95
|
+
* Per-slug provenance covering every entry in `selectedSlugs`. Empty when
|
|
96
|
+
* `failureReason !== null` or no batch returned any selections.
|
|
97
|
+
*/
|
|
98
|
+
sourceBySlug: ReadonlyMap<string, RouterSource>;
|
|
77
99
|
/** `null` on success; one of the failure reasons above otherwise. */
|
|
78
100
|
failureReason: RouterFailureReason | null;
|
|
79
101
|
}
|
|
@@ -112,8 +134,24 @@ const RouterResultSchema = z.object({
|
|
|
112
134
|
page_ids: z.array(z.number().int()),
|
|
113
135
|
});
|
|
114
136
|
|
|
115
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* Per-batch internal result. The orchestrator stamps provenance during the
|
|
139
|
+
* union so individual batches never need to know their own tier tag.
|
|
140
|
+
*/
|
|
141
|
+
interface RouterBatchResult {
|
|
142
|
+
selectedSlugs: string[];
|
|
143
|
+
failureReason: RouterFailureReason | null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Empty orchestrator result. */
|
|
116
147
|
function emptyResult(reason: RouterFailureReason | null): RouterResult {
|
|
148
|
+
return { selectedSlugs: [], sourceBySlug: new Map(), failureReason: reason };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Empty batch result — slimmer shape; orchestrator builds provenance. */
|
|
152
|
+
function emptyBatchResult(
|
|
153
|
+
reason: RouterFailureReason | null,
|
|
154
|
+
): RouterBatchResult {
|
|
117
155
|
return { selectedSlugs: [], failureReason: reason };
|
|
118
156
|
}
|
|
119
157
|
|
|
@@ -127,46 +165,42 @@ interface RunRouterParams {
|
|
|
127
165
|
priorEverInjected: readonly EverInjectedEntry[];
|
|
128
166
|
config: AssistantConfig;
|
|
129
167
|
signal?: AbortSignal;
|
|
168
|
+
/**
|
|
169
|
+
* Database handle for reading EMA scores when `tier2_size` is set. When
|
|
170
|
+
* absent, tier 2 is silently skipped (pages flow tier 1 → tier 3). The
|
|
171
|
+
* production caller (`injectViaRouter`) always passes it; tests that
|
|
172
|
+
* only exercise tier 1 / tier 3 paths can omit it.
|
|
173
|
+
*/
|
|
174
|
+
database?: DrizzleDb;
|
|
130
175
|
}
|
|
131
176
|
|
|
132
177
|
/**
|
|
133
|
-
* Run the router for one turn.
|
|
134
|
-
*
|
|
178
|
+
* Run the router for one turn.
|
|
179
|
+
*
|
|
180
|
+
* Top-level orchestration. When `config.memory.v2.router.batch_size` is
|
|
181
|
+
* `null` (default), the entire page index is sent in one call — bit-
|
|
182
|
+
* identical to the pre-batching code path so v3's KV cache is preserved.
|
|
183
|
+
* When set, `partitionPageIndex` splits the index into stable hash-bucketed
|
|
184
|
+
* batches and we fire one provider call per batch in parallel; the selected
|
|
185
|
+
* slugs are unioned across batches.
|
|
135
186
|
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* 3. Build system + user prompts. The system prompt is the rendered
|
|
142
|
-
* router template with the page index inlined and gets one ephemeral
|
|
143
|
-
* breakpoint at the end (the page-index block). The user message is
|
|
144
|
-
* *two* text blocks: the cached `<now>` block and the uncached
|
|
145
|
-
* already-injected/last-turn block.
|
|
146
|
-
* 4. Force `tool_choice` so the model can only emit `select_pages_to_inject`.
|
|
147
|
-
* 5. Parse the tool input via Zod. Anything off-shape collapses to
|
|
148
|
-
* `schema_mismatch`.
|
|
149
|
-
* 6. Map IDs to slugs through the page index, dropping IDs outside
|
|
150
|
-
* `[1, N]` and truncating at `max_page_ids`.
|
|
187
|
+
* Per-batch failure does not abort the turn — as long as at least one batch
|
|
188
|
+
* returns a usable selection, the union is returned with `failureReason:
|
|
189
|
+
* null`. Only when EVERY batch fails do we surface a failure; in that case
|
|
190
|
+
* the first batch's reason is returned for parity with the single-batch
|
|
191
|
+
* v3 behavior.
|
|
151
192
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
193
|
+
* Single batch error semantics, preserved from v3:
|
|
194
|
+
* - `empty_index` — workspace has no concept pages or skill entries.
|
|
195
|
+
* - `no_provider` — `getConfiguredProvider("memoryRouter")` returned null.
|
|
196
|
+
* - `api_error` — any uncaught throw during the provider call (incl. abort).
|
|
197
|
+
* - `tool_use_missing` — the model returned no `select_pages_to_inject` tool_use.
|
|
198
|
+
* - `schema_mismatch` — tool input failed Zod validation.
|
|
157
199
|
*/
|
|
158
200
|
export async function runRouter(
|
|
159
201
|
params: RunRouterParams,
|
|
160
202
|
): Promise<RouterResult> {
|
|
161
|
-
const {
|
|
162
|
-
workspaceDir,
|
|
163
|
-
userMessage,
|
|
164
|
-
assistantMessage,
|
|
165
|
-
nowText,
|
|
166
|
-
priorEverInjected,
|
|
167
|
-
config,
|
|
168
|
-
signal,
|
|
169
|
-
} = params;
|
|
203
|
+
const { workspaceDir, priorEverInjected, config } = params;
|
|
170
204
|
|
|
171
205
|
const pageIndex = await getPageIndex(workspaceDir);
|
|
172
206
|
if (pageIndex.entries.length === 0) {
|
|
@@ -179,31 +213,153 @@ export async function runRouter(
|
|
|
179
213
|
return emptyResult("no_provider");
|
|
180
214
|
}
|
|
181
215
|
|
|
216
|
+
const batchSize = config.memory?.v2?.router?.batch_size ?? null;
|
|
217
|
+
const tier1Size = config.memory?.v2?.router?.tier1_size ?? null;
|
|
218
|
+
const tier2Size = config.memory?.v2?.router?.tier2_size ?? null;
|
|
219
|
+
|
|
220
|
+
// Carve in tier order so each later tier sees only what's left. With
|
|
221
|
+
// every tier disabled (defaults) we hit the bit-identical single-batch
|
|
222
|
+
// path that preserves v3's KV cache.
|
|
223
|
+
const { tier1, rest: afterTier1 } = splitTier1(pageIndex, tier1Size);
|
|
224
|
+
|
|
225
|
+
let tier2: PageIndex | null = null;
|
|
226
|
+
let afterTier2: PageIndex = afterTier1;
|
|
227
|
+
if (tier2Size !== null && params.database && afterTier1.entries.length > 0) {
|
|
228
|
+
const slugs = afterTier1.entries.map((e) => e.slug);
|
|
229
|
+
const scores = computeInjectionScores(params.database, slugs, Date.now());
|
|
230
|
+
const split = splitTier2(afterTier1, tier2Size, scores);
|
|
231
|
+
tier2 = split.tier2;
|
|
232
|
+
afterTier2 = split.rest;
|
|
233
|
+
} else if (tier2Size !== null && !params.database) {
|
|
234
|
+
log.warn(
|
|
235
|
+
"tier2_size set but no database passed to runRouter; skipping tier 2",
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const tier3Batches = partitionPageIndex(afterTier2, batchSize).filter(
|
|
240
|
+
(b) => b.entries.length > 0,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Tag each batch with its provenance string. Tier 3 batches carry their
|
|
244
|
+
// bucket index so the inspector can attribute selections per-bucket.
|
|
245
|
+
const taggedBatches: Array<{ source: RouterSource; index: PageIndex }> = [];
|
|
246
|
+
if (tier1) taggedBatches.push({ source: "tier1", index: tier1 });
|
|
247
|
+
if (tier2) taggedBatches.push({ source: "tier2", index: tier2 });
|
|
248
|
+
tier3Batches.forEach((index, i) => {
|
|
249
|
+
taggedBatches.push({ source: `tier3:${i}` as const, index });
|
|
250
|
+
});
|
|
251
|
+
if (taggedBatches.length === 0) {
|
|
252
|
+
return emptyResult("empty_index");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const batchResults = await Promise.all(
|
|
256
|
+
taggedBatches.map(({ index }) =>
|
|
257
|
+
runRouterBatch({
|
|
258
|
+
...params,
|
|
259
|
+
batchIndex: index,
|
|
260
|
+
priorEverInjected,
|
|
261
|
+
provider,
|
|
262
|
+
}),
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const successes = batchResults.filter((r) => r.failureReason === null);
|
|
267
|
+
if (successes.length === 0) {
|
|
268
|
+
// For the single-batch (K=null) path this preserves v3's behavior:
|
|
269
|
+
// one batch, one failure reason surfaces directly.
|
|
270
|
+
return emptyResult(batchResults[0].failureReason);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Union selected slugs preserving first-seen order across batches; batch
|
|
274
|
+
// ordering is deterministic so the union and provenance map are stable.
|
|
275
|
+
// First-seen wins if a slug somehow appears in multiple batches (shouldn't
|
|
276
|
+
// happen — tier 1/2/3 partition is disjoint — but be defensive).
|
|
277
|
+
const sourceBySlug = new Map<string, RouterSource>();
|
|
278
|
+
const selectedSlugs: string[] = [];
|
|
279
|
+
for (let i = 0; i < batchResults.length; i++) {
|
|
280
|
+
const result = batchResults[i];
|
|
281
|
+
const source = taggedBatches[i].source;
|
|
282
|
+
for (const slug of result.selectedSlugs) {
|
|
283
|
+
if (sourceBySlug.has(slug)) continue;
|
|
284
|
+
sourceBySlug.set(slug, source);
|
|
285
|
+
selectedSlugs.push(slug);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (successes.length < batchResults.length) {
|
|
289
|
+
log.warn(
|
|
290
|
+
{
|
|
291
|
+
totalBatches: batchResults.length,
|
|
292
|
+
failedBatches: batchResults.length - successes.length,
|
|
293
|
+
failureReasons: batchResults
|
|
294
|
+
.filter((r) => r.failureReason !== null)
|
|
295
|
+
.map((r) => r.failureReason),
|
|
296
|
+
},
|
|
297
|
+
"Some router batches failed; returning union of successful batches",
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Each per-batch call caps at max_page_ids, but the union across batches can
|
|
302
|
+
// exceed it (e.g. 10 batches × 10 selections each ≫ 25 cap). Apply a final
|
|
303
|
+
// truncation so RouterResult honors the contract that injection.ts trusts.
|
|
304
|
+
// Iteration order above is tier 1 → tier 2 → tier 3:0 → … so earlier-tier
|
|
305
|
+
// slugs win the truncation.
|
|
306
|
+
const maxPageIds = config.memory?.v2?.router?.max_page_ids ?? 25;
|
|
307
|
+
if (selectedSlugs.length > maxPageIds) {
|
|
308
|
+
log.warn(
|
|
309
|
+
{ unionSize: selectedSlugs.length, max: maxPageIds },
|
|
310
|
+
"Router union across batches exceeded max_page_ids; truncating",
|
|
311
|
+
);
|
|
312
|
+
const dropped = selectedSlugs.splice(maxPageIds);
|
|
313
|
+
for (const slug of dropped) sourceBySlug.delete(slug);
|
|
314
|
+
}
|
|
315
|
+
return { selectedSlugs, sourceBySlug, failureReason: null };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface RunRouterBatchParams extends RunRouterParams {
|
|
319
|
+
batchIndex: PageIndex;
|
|
320
|
+
provider: NonNullable<Awaited<ReturnType<typeof getConfiguredProvider>>>;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Route one batch of the page index. Uses batch-local IDs everywhere
|
|
325
|
+
* (including `<already_injected_ids>`, which is filtered to slugs present
|
|
326
|
+
* in this batch). Provider is passed in by the orchestrator so we don't
|
|
327
|
+
* re-resolve it N times for an N-batch turn.
|
|
328
|
+
*/
|
|
329
|
+
async function runRouterBatch(
|
|
330
|
+
params: RunRouterBatchParams,
|
|
331
|
+
): Promise<RouterBatchResult> {
|
|
332
|
+
const {
|
|
333
|
+
workspaceDir,
|
|
334
|
+
userMessage,
|
|
335
|
+
assistantMessage,
|
|
336
|
+
nowText,
|
|
337
|
+
priorEverInjected,
|
|
338
|
+
config,
|
|
339
|
+
signal,
|
|
340
|
+
batchIndex,
|
|
341
|
+
provider,
|
|
342
|
+
} = params;
|
|
343
|
+
|
|
182
344
|
const systemPrompt = resolveRouterPrompt(
|
|
183
345
|
config.memory?.v2?.router?.router_prompt_path ?? null,
|
|
184
346
|
workspaceDir,
|
|
185
347
|
{
|
|
186
348
|
assistantName: getAssistantName(),
|
|
187
349
|
userName: resolveUserName(workspaceDir),
|
|
188
|
-
pageIndexBlock:
|
|
350
|
+
pageIndexBlock: batchIndex.rendered,
|
|
189
351
|
},
|
|
190
352
|
);
|
|
191
353
|
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
354
|
+
// Filter prior-injected to slugs present in THIS batch and map to
|
|
355
|
+
// batch-local IDs. The model in batch B can't reference global IDs that
|
|
356
|
+
// aren't in its prompt, so listing them would just be noise.
|
|
195
357
|
const priorIds: number[] = [];
|
|
196
358
|
for (const entry of priorEverInjected) {
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
359
|
+
const local = batchIndex.bySlug.get(entry.slug);
|
|
360
|
+
if (local) priorIds.push(local.id);
|
|
199
361
|
}
|
|
200
362
|
|
|
201
|
-
// Cache breakpoint 2 — `<now>` is stable across most turns (NOW.md only
|
|
202
|
-
// changes when the model rewrites it), so the bulk of the user message
|
|
203
|
-
// rides the cache. We use a 1h TTL to match the system-prompt breakpoint
|
|
204
|
-
// and the provider's auto-applied breakpoints. The trailing block has no
|
|
205
|
-
// `cache_control`; the Anthropic provider auto-applies a 1h breakpoint on
|
|
206
|
-
// the last text block of a turn-starting user message, which covers it.
|
|
207
363
|
const userMsg: Message = {
|
|
208
364
|
role: "user",
|
|
209
365
|
content: [
|
|
@@ -236,7 +392,7 @@ export async function runRouter(
|
|
|
236
392
|
);
|
|
237
393
|
} catch (err) {
|
|
238
394
|
log.warn({ err }, "Router provider call threw; treating as api_error");
|
|
239
|
-
return
|
|
395
|
+
return emptyBatchResult("api_error");
|
|
240
396
|
}
|
|
241
397
|
|
|
242
398
|
const toolBlock = extractToolUse(response);
|
|
@@ -245,7 +401,7 @@ export async function runRouter(
|
|
|
245
401
|
{ stopReason: response.stopReason },
|
|
246
402
|
"Router model returned no select_pages_to_inject tool_use block",
|
|
247
403
|
);
|
|
248
|
-
return
|
|
404
|
+
return emptyBatchResult("tool_use_missing");
|
|
249
405
|
}
|
|
250
406
|
|
|
251
407
|
const parsed = RouterResultSchema.safeParse(toolBlock.input);
|
|
@@ -254,11 +410,10 @@ export async function runRouter(
|
|
|
254
410
|
{ error: parsed.error.message },
|
|
255
411
|
"Router tool input did not match schema",
|
|
256
412
|
);
|
|
257
|
-
return
|
|
413
|
+
return emptyBatchResult("schema_mismatch");
|
|
258
414
|
}
|
|
259
415
|
|
|
260
|
-
const N =
|
|
261
|
-
|
|
416
|
+
const N = batchIndex.entries.length;
|
|
262
417
|
const inRangeIds: number[] = [];
|
|
263
418
|
const droppedIds: number[] = [];
|
|
264
419
|
for (const id of parsed.data.page_ids) {
|
|
@@ -275,9 +430,8 @@ export async function runRouter(
|
|
|
275
430
|
);
|
|
276
431
|
}
|
|
277
432
|
|
|
278
|
-
// De-duplicate BEFORE applying the cap —
|
|
279
|
-
//
|
|
280
|
-
// dedupes to `[1]`, under-filling the cap.
|
|
433
|
+
// De-duplicate BEFORE applying the cap — `[1, 1, 2]` with max=2 must
|
|
434
|
+
// yield 2 distinct slugs, not collapse to 1 after slicing duplicates.
|
|
281
435
|
const dedupedIds = Array.from(new Set(inRangeIds));
|
|
282
436
|
|
|
283
437
|
const truncated = dedupedIds.length > maxPageIds;
|
|
@@ -291,7 +445,7 @@ export async function runRouter(
|
|
|
291
445
|
|
|
292
446
|
const selectedSlugs: string[] = [];
|
|
293
447
|
for (const id of finalIds) {
|
|
294
|
-
const entry =
|
|
448
|
+
const entry = batchIndex.byId.get(id);
|
|
295
449
|
if (!entry) continue;
|
|
296
450
|
selectedSlugs.push(entry.slug);
|
|
297
451
|
}
|
|
@@ -174,8 +174,14 @@ async function deliverSlack(
|
|
|
174
174
|
channel,
|
|
175
175
|
threadTs: statusThreadTs,
|
|
176
176
|
status,
|
|
177
|
+
loadingMessages,
|
|
177
178
|
} = payload.assistantThreadStatus;
|
|
178
|
-
await sendSlackAssistantThreadStatus(
|
|
179
|
+
await sendSlackAssistantThreadStatus(
|
|
180
|
+
channel,
|
|
181
|
+
statusThreadTs,
|
|
182
|
+
status,
|
|
183
|
+
loadingMessages,
|
|
184
|
+
);
|
|
179
185
|
return { ok: true };
|
|
180
186
|
}
|
|
181
187
|
|