@vellumai/assistant 0.12.2 → 0.12.3-staging.1
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/.env.example +2 -0
- package/AGENTS.md +1 -1
- package/docs/architecture/integrations.md +7 -0
- package/docs/architecture/memory.md +17 -2
- package/docs/credential-execution-service.md +1 -1
- package/docs/desktop-browser-cli.md +7 -3
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
- package/node_modules/@vellumai/environments/src/shell.ts +24 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/openapi.yaml +54 -5
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +1 -0
- package/scripts/sync-llm-catalog.ts +3 -0
- package/scripts/voice-ttft-spike.ts +2 -2
- package/src/__tests__/agent-loop.test.ts +259 -0
- package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
- package/src/__tests__/anthropic-provider.test.ts +55 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/attachments-store.test.ts +22 -3
- package/src/__tests__/channel-approval.test.ts +9 -14
- package/src/__tests__/channel-reply-delivery.test.ts +56 -0
- package/src/__tests__/chat-credential-redaction.test.ts +23 -0
- package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
- package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +257 -6
- package/src/__tests__/conversation-attachments.test.ts +106 -0
- package/src/__tests__/conversation-fork-crud.test.ts +191 -0
- package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
- package/src/__tests__/credential-execution-client.test.ts +70 -53
- package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
- package/src/__tests__/events-tail-route.test.ts +33 -0
- package/src/__tests__/history-repair.test.ts +53 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
- package/src/__tests__/llm-catalog-parity.test.ts +27 -4
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-commands-routes.test.ts +114 -101
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/persist-media-references.test.ts +50 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
- package/src/__tests__/schedule-routes.test.ts +20 -0
- package/src/__tests__/scheduler-result-notification.test.ts +23 -4
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
- package/src/__tests__/secret-routes-scrub.test.ts +22 -27
- package/src/__tests__/secret-scanner.test.ts +20 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
- package/src/__tests__/secure-keys.test.ts +7 -3
- package/src/__tests__/server-tool-pairing.test.ts +107 -0
- package/src/__tests__/skills.test.ts +5 -4
- package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/tool-result-follow-up.test.ts +99 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +63 -0
- package/src/__tests__/unicode.test.ts +36 -0
- package/src/agent/loop.ts +37 -12
- package/src/agent/tool-result-follow-up.ts +70 -0
- package/src/api/attachment-provenance.test.ts +68 -0
- package/src/api/computer-use-tool.test.ts +55 -0
- package/src/api/computer-use-tool.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +3 -0
- package/src/api/events/desktop-activity-changed.ts +10 -0
- package/src/api/events/question-request.ts +1 -0
- package/src/api/index.ts +11 -0
- package/src/api/responses/conversation-message.ts +3 -0
- package/src/approvals/approval-primitive.ts +5 -2
- package/src/approvals/scoped-approval-grants.ts +6 -2
- package/src/browser/virtual-desktop-target.ts +1 -2
- package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
- package/src/cli/commands/__tests__/plugins.test.ts +20 -1
- package/src/cli/commands/__tests__/schedules.test.ts +14 -0
- package/src/cli/commands/bash.help.ts +4 -3
- package/src/cli/commands/browser.help.ts +5 -1
- package/src/cli/commands/credentials.help.ts +3 -3
- package/src/cli/commands/oauth/index.help.ts +10 -0
- package/src/cli/commands/oauth/providers.ts +12 -0
- package/src/cli/commands/oauth/request.test.ts +179 -2
- package/src/cli/commands/oauth/request.ts +41 -10
- package/src/cli/commands/plugins.ts +12 -5
- package/src/cli/commands/schedules.ts +2 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
- package/src/cli/lib/bundled-marketplace.json +855 -0
- package/src/cli/lib/bundled-plugin-packages.json +783 -1
- package/src/cli/lib/inspect-plugin.ts +11 -4
- package/src/cli/lib/upgrade-plugin.ts +19 -11
- package/src/cli/output.ts +18 -4
- package/src/config/__tests__/default-provider.test.ts +4 -0
- package/src/config/bundled-skills/schedule/SKILL.md +6 -6
- package/src/config/loader.ts +9 -17
- package/src/config/platform-identity.ts +8 -8
- package/src/config/profile-text-generation.test.ts +51 -0
- package/src/config/profile-text-generation.ts +51 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
- package/src/config/schemas/llm.ts +7 -2
- package/src/config/schemas/mcp.ts +5 -1
- package/src/config/schemas/memory-v3.ts +12 -0
- package/src/credential-execution/ces-runtime.ts +2 -2
- package/src/credential-execution/executable-discovery.ts +36 -134
- package/src/credential-execution/process-manager.test.ts +20 -24
- package/src/credential-execution/process-manager.ts +24 -19
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
- package/src/daemon/assistant-attachments.ts +20 -12
- package/src/daemon/chat-credential-redaction.ts +16 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +74 -3
- package/src/daemon/conversation-agent-loop.ts +12 -0
- package/src/daemon/conversation-attachments.ts +93 -12
- package/src/daemon/conversation-tool-setup.ts +71 -3
- package/src/daemon/conversation-turn-finalize.ts +26 -13
- package/src/daemon/conversation.ts +72 -17
- package/src/daemon/daemon-control.ts +3 -7
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/message-types/shared.ts +1 -0
- package/src/daemon/orphan-reaper.ts +4 -3
- package/src/daemon/persist-media-references.ts +20 -3
- package/src/daemon/tool-setup-types.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +50 -15
- package/src/desktop/desktop-automation-lease.test.ts +230 -0
- package/src/desktop/desktop-automation-lease.ts +90 -6
- package/src/desktop/desktop-help.ts +15 -0
- package/src/desktop/desktop-stream-bridge.test.ts +65 -10
- package/src/desktop/desktop-stream-bridge.ts +3 -3
- package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
- package/src/desktop/desktop-wallpaper-worker.ts +17 -0
- package/src/desktop/desktop-wallpaper.test.ts +48 -7
- package/src/desktop/desktop-wallpaper.ts +34 -102
- package/src/desktop/virtual-desktop-feature.ts +1 -1
- package/src/mcp/__tests__/manager-tool-caps.test.ts +111 -0
- package/src/mcp/__tests__/startup.test.ts +30 -7
- package/src/mcp/__tests__/tool-caps.test.ts +107 -0
- package/src/mcp/manager.ts +168 -101
- package/src/mcp/startup.ts +33 -13
- package/src/mcp/tool-caps.ts +176 -0
- package/src/messaging/provider-message-metadata.ts +3 -3
- package/src/notifications/__tests__/copy-composer.test.ts +70 -0
- package/src/notifications/copy-composer.ts +11 -3
- package/src/notifications/schedule-result-producer.ts +4 -6
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
- package/src/oauth/identity-verifier.ts +24 -0
- package/src/oauth/oauth-store.ts +11 -1
- package/src/oauth/provider-serializer.ts +1 -0
- package/src/oauth/seed-providers.ts +12 -0
- package/src/permissions/confirmation-guardian-request.test.ts +16 -0
- package/src/permissions/confirmation-guardian-request.ts +2 -3
- package/src/permissions/question-prompter.test.ts +31 -0
- package/src/permissions/question-prompter.ts +2 -0
- package/src/persistence/attachments-store.ts +84 -44
- package/src/persistence/conversation-crud.ts +111 -20
- package/src/persistence/conversation-plugin-facade.ts +30 -0
- package/src/persistence/conversation-tool-surface.ts +135 -0
- package/src/persistence/conversation-types.test.ts +32 -0
- package/src/persistence/conversation-types.ts +26 -4
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
- package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
- package/src/persistence/schema/index.ts +1 -0
- package/src/persistence/schema/oauth.ts +1 -0
- package/src/persistence/steps.ts +24 -3
- package/src/plugin-api/conversation-turn.ts +31 -7
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
- package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
- package/src/plugins/defaults/memory/AGENTS.md +39 -5
- package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
- package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
- package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
- package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
- package/src/plugins/defaults/memory/buffer-file.ts +354 -0
- package/src/plugins/defaults/memory/buffer-format.ts +40 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -2
- package/src/plugins/defaults/memory/context-search/format.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
- package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
- package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -42
- package/src/plugins/defaults/memory/host-utils.ts +0 -10
- package/src/plugins/defaults/memory/injectors.ts +4 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
- package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
- package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +89 -49
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
- package/src/plugins/defaults/memory/tools.ts +1 -1
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
- package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
- package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +183 -4
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +103 -2
- package/src/plugins/defaults/memory/v3/card.ts +2 -1
- package/src/plugins/defaults/memory/v3/injector.ts +212 -178
- package/src/plugins/defaults/memory/v3/orchestrate.ts +112 -25
- package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +253 -1
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +35 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +31 -19
- package/src/plugins/defaults/memory/v3/sections.ts +2 -1
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
- package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
- package/src/prompts/delegation-gate.ts +57 -0
- package/src/prompts/system-prompt.ts +14 -32
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/jev/client.test.ts +260 -0
- package/src/providers/jev/client.ts +518 -0
- package/src/providers/model-catalog.ts +58 -3
- package/src/providers/server-tool-pairing.ts +16 -7
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +94 -1
- package/src/runtime/agent-wake.ts +31 -4
- package/src/runtime/guardian-action-service.ts +2 -17
- package/src/runtime/guardian-reply-router.ts +1 -8
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
- package/src/runtime/migrations/vbundle-import-policy.ts +33 -11
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
- package/src/runtime/routes/channel-route-shared.ts +1 -9
- package/src/runtime/routes/conversation-routes.ts +29 -4
- package/src/runtime/routes/desktop-setup-routes.test.ts +2 -2
- package/src/runtime/routes/desktop-setup-routes.ts +8 -5
- package/src/runtime/routes/guardian-approval-interception.ts +24 -0
- package/src/runtime/routes/inbound-message-handler.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +1 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
- package/src/runtime/routes/inference-profiles-routes.ts +9 -0
- package/src/runtime/routes/oauth-commands-routes.ts +57 -54
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
- package/src/runtime/routes/oauth-request-hints.ts +149 -0
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/secret-routes.ts +99 -119
- package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
- package/src/schedule/run-script.ts +2 -2
- package/src/schedule/scheduler.ts +47 -11
- package/src/schedule/tool-surface-readiness.ts +65 -0
- package/src/schedule/worker-mcp.ts +85 -0
- package/src/schedule/worker.ts +9 -31
- package/src/security/secure-keys.ts +60 -48
- package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
- package/src/tools/ask-question/ask-question-tool.ts +119 -23
- package/src/tools/browser/browser-execution.ts +7 -1
- package/src/tools/host-terminal/host-shell.ts +12 -6
- package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
- package/src/tools/shared/shell-output.test.ts +10 -0
- package/src/tools/shared/shell-output.ts +14 -2
- package/src/tools/skills/sandbox-runner.ts +13 -2
- package/src/tools/skills/scaffold-managed.ts +2 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +33 -4
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
- package/src/tools/terminal/safe-env.ts +35 -24
- package/src/tools/terminal/sanitized-bash.ts +15 -2
- package/src/tools/terminal/shell-launch.test.ts +162 -0
- package/src/tools/terminal/shell.test.ts +29 -0
- package/src/tools/terminal/shell.ts +13 -7
- package/src/util/browser-human-verification.ts +14 -0
- package/src/util/host-process.test.ts +17 -1
- package/src/util/host-process.ts +24 -0
- package/src/util/unicode.ts +29 -0
|
@@ -28,13 +28,17 @@ import { Database } from "bun:sqlite";
|
|
|
28
28
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
29
29
|
|
|
30
30
|
import type { OrchestrateResult } from "../orchestrate.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
ensureMemoryV3PoolInputsSchema,
|
|
33
|
+
ensureMemoryV3PoolsSchema,
|
|
34
|
+
} from "../plugin-schema.js";
|
|
32
35
|
import type {
|
|
33
36
|
PoolCandidateRecord,
|
|
34
37
|
PoolLane,
|
|
35
38
|
PoolRecord,
|
|
36
39
|
} from "../pool-log-store.js";
|
|
37
|
-
import
|
|
40
|
+
import { renderFinderLine } from "../pool-select.js";
|
|
41
|
+
import type { MemoryRoutingTurn, Section, Slug } from "../types.js";
|
|
38
42
|
|
|
39
43
|
const realDb = {
|
|
40
44
|
...(await import("../../../../../persistence/db-connection.js")),
|
|
@@ -50,6 +54,7 @@ makeDb();
|
|
|
50
54
|
function makeDb() {
|
|
51
55
|
memorySqlite = new Database(":memory:");
|
|
52
56
|
ensureMemoryV3PoolsSchema(memorySqlite);
|
|
57
|
+
ensureMemoryV3PoolInputsSchema(memorySqlite);
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
mock.module("../../../../../persistence/db-connection.js", () => ({
|
|
@@ -62,8 +67,17 @@ mock.module("../../../../../persistence/db-connection.js", () => ({
|
|
|
62
67
|
: realDb.getMemorySqlite(),
|
|
63
68
|
}));
|
|
64
69
|
|
|
65
|
-
const {
|
|
66
|
-
|
|
70
|
+
const {
|
|
71
|
+
buildPoolInput,
|
|
72
|
+
buildPoolRecord,
|
|
73
|
+
hashPoolText,
|
|
74
|
+
readPoolForMessageIds,
|
|
75
|
+
readPoolForTurn,
|
|
76
|
+
readPoolInputForTurn,
|
|
77
|
+
readPoolText,
|
|
78
|
+
writePool,
|
|
79
|
+
writePoolInput,
|
|
80
|
+
} = await import("../pool-log-store.js");
|
|
67
81
|
|
|
68
82
|
beforeEach(() => {
|
|
69
83
|
storeMockActive = true;
|
|
@@ -115,6 +129,32 @@ function orchestrated(): OrchestrateResult {
|
|
|
115
129
|
};
|
|
116
130
|
}
|
|
117
131
|
|
|
132
|
+
/** {@link orchestrated} with the pool the selector was given: a card per
|
|
133
|
+
* stable-prefix slug and one finder candidate per finder line, in the
|
|
134
|
+
* record's order, plus the gate and keep-all facts. */
|
|
135
|
+
function orchestratedWithPool(): OrchestrateResult {
|
|
136
|
+
const result = orchestrated();
|
|
137
|
+
return {
|
|
138
|
+
...result,
|
|
139
|
+
pool: {
|
|
140
|
+
stable: [
|
|
141
|
+
{ slug: "core/page", card: "core card" },
|
|
142
|
+
{ slug: "hot/page", card: "hot card" },
|
|
143
|
+
{ slug: "fresh/page", card: "fresh card" },
|
|
144
|
+
{ slug: "skills/example", card: "skill card" },
|
|
145
|
+
],
|
|
146
|
+
finder: result.lanes.finder.map((line) => ({
|
|
147
|
+
slug: line.slug,
|
|
148
|
+
lane: line.lane,
|
|
149
|
+
section: line.section,
|
|
150
|
+
descriptor: line.descriptor || `${line.slug} lead`,
|
|
151
|
+
})),
|
|
152
|
+
},
|
|
153
|
+
keptAll: false,
|
|
154
|
+
gateReason: "dense_pass",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
118
158
|
/**
|
|
119
159
|
* A turn the injection gate hard-skipped: the selector was never consulted,
|
|
120
160
|
* so there are no selections, but the result's lanes still carry the stable
|
|
@@ -447,3 +487,142 @@ describe("ensureMemoryV3PoolsSchema", () => {
|
|
|
447
487
|
expect(column?.dflt_value).toBe("1");
|
|
448
488
|
});
|
|
449
489
|
});
|
|
490
|
+
|
|
491
|
+
describe("pool input capture", () => {
|
|
492
|
+
const turn: MemoryRoutingTurn = {
|
|
493
|
+
conversationId: "conv-1",
|
|
494
|
+
turnNumber: 4,
|
|
495
|
+
currentMessage: "what did we decide about the garden?",
|
|
496
|
+
recentContext: "user: hi\nassistant: hello",
|
|
497
|
+
situationalContext: "Today is 2026-01-01.",
|
|
498
|
+
previousAssistantMessage: "hello",
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
test("buildPoolInput captures each candidate's rendered text in pool order, aligned with the pool record", () => {
|
|
502
|
+
const result = orchestratedWithPool();
|
|
503
|
+
const { input, texts } = buildPoolInput(result, turn, "select wisely");
|
|
504
|
+
const record = buildPoolRecord(result);
|
|
505
|
+
|
|
506
|
+
expect(input.candidate_text_hashes).toHaveLength(record.candidates.length);
|
|
507
|
+
const rendered = [
|
|
508
|
+
...result.pool!.stable.map((candidate) => candidate.card),
|
|
509
|
+
...result.pool!.finder.map((candidate) => renderFinderLine(candidate)),
|
|
510
|
+
];
|
|
511
|
+
expect(input.candidate_text_hashes.map((hash) => texts.get(hash))).toEqual(
|
|
512
|
+
rendered,
|
|
513
|
+
);
|
|
514
|
+
expect(input.candidate_text_hashes[0]).toBe(hashPoolText("core card"));
|
|
515
|
+
expect(input).toMatchObject({
|
|
516
|
+
situational_context: "Today is 2026-01-01.",
|
|
517
|
+
recent_context: "user: hi\nassistant: hello",
|
|
518
|
+
current_message: "what did we decide about the garden?",
|
|
519
|
+
previous_assistant_message: "hello",
|
|
520
|
+
selector_prompt_hash: hashPoolText("select wisely"),
|
|
521
|
+
kept_all: false,
|
|
522
|
+
gate_reason: "dense_pass",
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test("a turn whose selector never judged a pool captures the context and no candidate texts", () => {
|
|
527
|
+
const { input, texts } = buildPoolInput(
|
|
528
|
+
hardSkipped(),
|
|
529
|
+
{
|
|
530
|
+
...turn,
|
|
531
|
+
situationalContext: undefined,
|
|
532
|
+
previousAssistantMessage: undefined,
|
|
533
|
+
},
|
|
534
|
+
"select wisely",
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
expect(input.candidate_text_hashes).toEqual([]);
|
|
538
|
+
expect(texts.size).toBe(0);
|
|
539
|
+
expect(input).toMatchObject({
|
|
540
|
+
situational_context: null,
|
|
541
|
+
previous_assistant_message: null,
|
|
542
|
+
selector_prompt_hash: null,
|
|
543
|
+
gate_reason: null,
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test("a result without the selector's pool captures no candidate texts rather than misaligned ones", () => {
|
|
548
|
+
const { input, texts } = buildPoolInput(
|
|
549
|
+
orchestrated(),
|
|
550
|
+
turn,
|
|
551
|
+
"select wisely",
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
expect(input.candidate_text_hashes).toEqual([]);
|
|
555
|
+
expect(texts.size).toBe(0);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
test("writePoolInput and readPoolInputForTurn round-trip; a re-observed turn replaces its row; texts are stored once", () => {
|
|
559
|
+
const capture = buildPoolInput(
|
|
560
|
+
orchestratedWithPool(),
|
|
561
|
+
turn,
|
|
562
|
+
"select wisely",
|
|
563
|
+
);
|
|
564
|
+
writePoolInput(memorySqlite, "conv-1", 4, capture);
|
|
565
|
+
|
|
566
|
+
expect(readPoolInputForTurn("conv-1", 4)).toEqual(capture.input);
|
|
567
|
+
expect(readPoolText(capture.input.candidate_text_hashes[0]!)).toBe(
|
|
568
|
+
"core card",
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
// The next turn pools the same candidates: its input row is its own, the
|
|
572
|
+
// texts are shared by hash.
|
|
573
|
+
writePoolInput(
|
|
574
|
+
memorySqlite,
|
|
575
|
+
"conv-1",
|
|
576
|
+
5,
|
|
577
|
+
buildPoolInput(
|
|
578
|
+
orchestratedWithPool(),
|
|
579
|
+
{ ...turn, turnNumber: 5, currentMessage: "and the fence?" },
|
|
580
|
+
"select wisely",
|
|
581
|
+
),
|
|
582
|
+
);
|
|
583
|
+
const textCount = () =>
|
|
584
|
+
(
|
|
585
|
+
memorySqlite
|
|
586
|
+
.query(`SELECT COUNT(*) AS n FROM memory_v3_pool_texts`)
|
|
587
|
+
.get() as { n: number }
|
|
588
|
+
).n;
|
|
589
|
+
expect(textCount()).toBe(new Set(capture.input.candidate_text_hashes).size);
|
|
590
|
+
expect(readPoolInputForTurn("conv-1", 5)?.current_message).toBe(
|
|
591
|
+
"and the fence?",
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
writePoolInput(
|
|
595
|
+
memorySqlite,
|
|
596
|
+
"conv-1",
|
|
597
|
+
4,
|
|
598
|
+
buildPoolInput(
|
|
599
|
+
orchestratedWithPool(),
|
|
600
|
+
{ ...turn, currentMessage: "again" },
|
|
601
|
+
"select wisely",
|
|
602
|
+
),
|
|
603
|
+
);
|
|
604
|
+
expect(readPoolInputForTurn("conv-1", 4)?.current_message).toBe("again");
|
|
605
|
+
expect(
|
|
606
|
+
(
|
|
607
|
+
memorySqlite
|
|
608
|
+
.query(`SELECT COUNT(*) AS n FROM memory_v3_pool_inputs`)
|
|
609
|
+
.get() as { n: number }
|
|
610
|
+
).n,
|
|
611
|
+
).toBe(2);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
test("an absent turn or text reads null, and reads degrade to null when the memory connection is unavailable", () => {
|
|
615
|
+
expect(readPoolInputForTurn("conv-1", 9)).toBeNull();
|
|
616
|
+
expect(readPoolText("missing")).toBeNull();
|
|
617
|
+
|
|
618
|
+
writePoolInput(
|
|
619
|
+
memorySqlite,
|
|
620
|
+
"conv-1",
|
|
621
|
+
4,
|
|
622
|
+
buildPoolInput(orchestratedWithPool(), turn, "select wisely"),
|
|
623
|
+
);
|
|
624
|
+
memoryDbAvailable = false;
|
|
625
|
+
expect(readPoolInputForTurn("conv-1", 4)).toBeNull();
|
|
626
|
+
expect(readPoolText(hashPoolText("core card"))).toBeNull();
|
|
627
|
+
});
|
|
628
|
+
});
|
|
@@ -43,6 +43,7 @@ import type { HotSetEntry, HotSetOptions } from "../hot-set.js";
|
|
|
43
43
|
import type { OrchestrateResult } from "../orchestrate.js";
|
|
44
44
|
import {
|
|
45
45
|
ensureMemoryV3InjectedSectionsSchema,
|
|
46
|
+
ensureMemoryV3PoolInputsSchema,
|
|
46
47
|
ensureMemoryV3PoolsSchema,
|
|
47
48
|
} from "../plugin-schema.js";
|
|
48
49
|
import { MEMORY_V3_FULL_PROFILE_MIN_PAGES } from "../tuning-profile.js";
|
|
@@ -123,6 +124,9 @@ let gateEnabledCfg = true;
|
|
|
123
124
|
// Mutable `memory.v3.rareTerm.enabled` switch carried by the mocked config
|
|
124
125
|
// (default on, mirroring the schema default).
|
|
125
126
|
let rareTermEnabledCfg = true;
|
|
127
|
+
// Mutable `memory.v3.poolLog.captureInput` opt-in carried by the mocked
|
|
128
|
+
// config (default off, mirroring the schema default).
|
|
129
|
+
let captureInputCfg = false;
|
|
126
130
|
let messages: Array<{
|
|
127
131
|
role: string;
|
|
128
132
|
content: string;
|
|
@@ -240,6 +244,7 @@ function makeDb() {
|
|
|
240
244
|
ensureMemoryV3InjectedSectionsSchema(memorySqlite);
|
|
241
245
|
// `observeTurn` records each turn's candidate pool next to its selections.
|
|
242
246
|
ensureMemoryV3PoolsSchema(memorySqlite);
|
|
247
|
+
ensureMemoryV3PoolInputsSchema(memorySqlite);
|
|
243
248
|
return db;
|
|
244
249
|
}
|
|
245
250
|
|
|
@@ -298,6 +303,7 @@ function seedMemoryConfig(): void {
|
|
|
298
303
|
// Gate tuning (schema defaults) with the mutable `enabled` kill-switch,
|
|
299
304
|
// threaded through to orchestrate as-is.
|
|
300
305
|
gate: { ...GATE_DEFAULTS, enabled: gateEnabledCfg },
|
|
306
|
+
poolLog: { captureInput: captureInputCfg },
|
|
301
307
|
},
|
|
302
308
|
qdrant: { vectorSize: 8, onDisk: false },
|
|
303
309
|
});
|
|
@@ -586,8 +592,9 @@ const {
|
|
|
586
592
|
} = await import("../shadow-plugin.js");
|
|
587
593
|
const { memoryV3Injector, resetMemoryV3InjectorStateForTests } =
|
|
588
594
|
await import("../injector.js");
|
|
589
|
-
const { MemoryV3RetrievalUnavailableError } =
|
|
590
|
-
|
|
595
|
+
const { MemoryV3RetrievalUnavailableError, renderFinderLine } =
|
|
596
|
+
await import("../pool-select.js");
|
|
597
|
+
const { buildPoolRecord, readPoolForMessageIds, readPoolText } =
|
|
591
598
|
await import("../pool-log-store.js");
|
|
592
599
|
|
|
593
600
|
/** Seed the real config from the current mutable knobs, then run the real
|
|
@@ -626,6 +633,23 @@ function readPools() {
|
|
|
626
633
|
}>;
|
|
627
634
|
}
|
|
628
635
|
|
|
636
|
+
function readPoolInputs() {
|
|
637
|
+
return memorySqlite
|
|
638
|
+
.query(
|
|
639
|
+
`SELECT conversation_id, turn, current_message, kept_all, gate_reason,
|
|
640
|
+
candidate_text_hashes_json
|
|
641
|
+
FROM memory_v3_pool_inputs ORDER BY turn`,
|
|
642
|
+
)
|
|
643
|
+
.all() as Array<{
|
|
644
|
+
conversation_id: string;
|
|
645
|
+
turn: number;
|
|
646
|
+
current_message: string;
|
|
647
|
+
kept_all: number;
|
|
648
|
+
gate_reason: string | null;
|
|
649
|
+
candidate_text_hashes_json: string;
|
|
650
|
+
}>;
|
|
651
|
+
}
|
|
652
|
+
|
|
629
653
|
/** The `chosen` verdict per pooled slug, read from the single pool row. */
|
|
630
654
|
function chosenBySlug(): Record<string, boolean> {
|
|
631
655
|
const pools = readPools();
|
|
@@ -668,6 +692,7 @@ beforeEach(() => {
|
|
|
668
692
|
selectorEnabledCfg = false;
|
|
669
693
|
gateEnabledCfg = true;
|
|
670
694
|
rareTermEnabledCfg = true;
|
|
695
|
+
captureInputCfg = false;
|
|
671
696
|
messages = [
|
|
672
697
|
{
|
|
673
698
|
role: "user",
|
|
@@ -975,6 +1000,61 @@ describe("memory-v3 engine", () => {
|
|
|
975
1000
|
expect(readPools().map((pool) => pool.message_id)).toEqual(["m-skipped"]);
|
|
976
1001
|
});
|
|
977
1002
|
|
|
1003
|
+
test("the selector's input is not captured unless memory.v3.poolLog.captureInput is on", async () => {
|
|
1004
|
+
await observeTurn("conv-1", 2);
|
|
1005
|
+
|
|
1006
|
+
expect(readPools()).toHaveLength(1);
|
|
1007
|
+
expect(readPoolInputs()).toHaveLength(0);
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
test("with memory.v3.poolLog.captureInput on, the turn log writes the selector's input and every pooled candidate's text", async () => {
|
|
1011
|
+
captureInputCfg = true;
|
|
1012
|
+
const finder = [
|
|
1013
|
+
{ slug: "page-1", descriptor: "the first page", lane: "needle" as const },
|
|
1014
|
+
{ slug: "page-2", descriptor: "", lane: "edge" as const },
|
|
1015
|
+
];
|
|
1016
|
+
orchestrateSpy.mockImplementationOnce(async () => ({
|
|
1017
|
+
selections: [
|
|
1018
|
+
{ slug: "page-core", sections: [] },
|
|
1019
|
+
{ slug: "page-1", sections: [] },
|
|
1020
|
+
],
|
|
1021
|
+
lanes: { core: ["page-core"], hot: [], fresh: [], always: [], finder },
|
|
1022
|
+
selectorRan: true,
|
|
1023
|
+
keptAll: false,
|
|
1024
|
+
gateReason: "dense_pass",
|
|
1025
|
+
pool: {
|
|
1026
|
+
stable: [{ slug: "page-core", card: "core card" }],
|
|
1027
|
+
finder,
|
|
1028
|
+
},
|
|
1029
|
+
}));
|
|
1030
|
+
|
|
1031
|
+
await observeTurn("conv-1", 2);
|
|
1032
|
+
|
|
1033
|
+
const pools = readPools();
|
|
1034
|
+
expect(pools).toHaveLength(1);
|
|
1035
|
+
expect(pools[0]!.pool_size).toBe(3);
|
|
1036
|
+
const inputs = readPoolInputs();
|
|
1037
|
+
expect(inputs).toHaveLength(1);
|
|
1038
|
+
expect(inputs[0]).toMatchObject({
|
|
1039
|
+
conversation_id: "conv-1",
|
|
1040
|
+
turn: 2,
|
|
1041
|
+
current_message: "hello world",
|
|
1042
|
+
kept_all: 0,
|
|
1043
|
+
gate_reason: "dense_pass",
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
// One hash per pooled candidate in pool order: the card as pre-rendered,
|
|
1047
|
+
// then each finder line exactly as the selector renders it.
|
|
1048
|
+
const hashes = JSON.parse(
|
|
1049
|
+
inputs[0]!.candidate_text_hashes_json,
|
|
1050
|
+
) as string[];
|
|
1051
|
+
expect(hashes.map((hash) => readPoolText(hash))).toEqual([
|
|
1052
|
+
"core card",
|
|
1053
|
+
renderFinderLine(finder[0]!),
|
|
1054
|
+
renderFinderLine(finder[1]!),
|
|
1055
|
+
]);
|
|
1056
|
+
});
|
|
1057
|
+
|
|
978
1058
|
test("a turn observed again replaces its selection rows in step with its pool", async () => {
|
|
979
1059
|
orchestrateSpy.mockImplementationOnce(async () =>
|
|
980
1060
|
poolOf(["page-1", "page-2"]),
|
|
@@ -1163,6 +1243,27 @@ describe("memory-v3 engine", () => {
|
|
|
1163
1243
|
expect(sourceOf([])).toBe("needle");
|
|
1164
1244
|
});
|
|
1165
1245
|
|
|
1246
|
+
test("a turn whose selector could not run attributes no rows, so unjudged pages never feed frecency or learned edges", () => {
|
|
1247
|
+
const rows = attributeSelections({
|
|
1248
|
+
selections: [
|
|
1249
|
+
{ slug: "page-core", sections: [] },
|
|
1250
|
+
{ slug: "page-hot", sections: [] },
|
|
1251
|
+
],
|
|
1252
|
+
lanes: {
|
|
1253
|
+
core: ["page-core"],
|
|
1254
|
+
hot: ["page-hot"],
|
|
1255
|
+
fresh: [],
|
|
1256
|
+
always: [],
|
|
1257
|
+
finder: [{ slug: "page-two", descriptor: "", lane: "needle" }],
|
|
1258
|
+
},
|
|
1259
|
+
selectorRan: false,
|
|
1260
|
+
selectorFailure: new MemoryV3RetrievalUnavailableError(
|
|
1261
|
+
"selector unavailable",
|
|
1262
|
+
),
|
|
1263
|
+
});
|
|
1264
|
+
expect(rows).toEqual([]);
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1166
1267
|
test("a selection of a core page a finder also hit attributes to core (pool position wins)", () => {
|
|
1167
1268
|
const rows = attributeSelections({
|
|
1168
1269
|
selections: [{ slug: "page-core", sections: [] }],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { safeStringSlice } from "@vellumai/plugin-api";
|
|
2
|
+
|
|
1
3
|
import { FRONTMATTER_REGEX, parseFrontmatterFields } from "../frontmatter.js";
|
|
2
|
-
import { safeStringSlice } from "../host-utils.js";
|
|
3
4
|
import { injectedConceptHeader } from "../substrate/injected-block-slugs.js";
|
|
4
5
|
import { LINK_SEPARATOR, parseLinkEntry } from "../substrate/page-links.js";
|
|
5
6
|
import type { Slug } from "./types.js";
|