@vellumai/assistant 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/ARCHITECTURE.md +68 -15
- package/Dockerfile +2 -2
- package/bun.lock +6 -2
- package/docker-entrypoint.sh +42 -1
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/memory.md +21 -24
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
- package/openapi.yaml +539 -4
- package/package.json +5 -1
- package/src/__tests__/anthropic-provider.test.ts +160 -95
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +47 -1
- package/src/__tests__/app-source-watcher.test.ts +159 -0
- package/src/__tests__/assistant-event-hub.test.ts +30 -0
- package/src/__tests__/checker.test.ts +138 -172
- package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +5 -0
- package/src/__tests__/context-overflow-approval.test.ts +5 -5
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -6
- package/src/__tests__/conversation-agent-loop.test.ts +4 -51
- package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
- package/src/__tests__/conversation-directories-parse.test.ts +105 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
- package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
- package/src/__tests__/conversation-wipe.test.ts +2 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
- package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +0 -2
- package/src/__tests__/date-context.test.ts +76 -210
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
- package/src/__tests__/file-list-tool.test.ts +219 -0
- package/src/__tests__/first-greeting.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +180 -3
- package/src/__tests__/identity-routes.test.ts +328 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
- package/src/__tests__/injection-block.test.ts +24 -0
- package/src/__tests__/inline-command-runner.test.ts +7 -5
- package/src/__tests__/install-skill-routing.test.ts +7 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +15 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
- package/src/__tests__/llm-context-normalization.test.ts +18 -18
- package/src/__tests__/llm-context-route-provider.test.ts +101 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +162 -0
- package/src/__tests__/log-export-workspace.test.ts +257 -100
- package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
- package/src/__tests__/mcp-abort-signal.test.ts +5 -0
- package/src/__tests__/mcp-client-auth.test.ts +5 -0
- package/src/__tests__/memory-recall-log-store.test.ts +132 -0
- package/src/__tests__/migration-export-streaming.test.ts +304 -0
- package/src/__tests__/migration-import-commit-http.test.ts +11 -10
- package/src/__tests__/mock-fetch.ts +87 -0
- package/src/__tests__/navigate-settings-tab.test.ts +14 -1
- package/src/__tests__/notification-broadcaster.test.ts +65 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
- package/src/__tests__/onboarding-template-contract.test.ts +63 -14
- package/src/__tests__/parser.test.ts +32 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
- package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
- package/src/__tests__/permission-mode-sse.test.ts +418 -0
- package/src/__tests__/permission-mode-store.test.ts +277 -0
- package/src/__tests__/permission-mode.test.ts +101 -0
- package/src/__tests__/pkb-autoinject.test.ts +96 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
- package/src/__tests__/profiler-routes.test.ts +502 -0
- package/src/__tests__/profiler-run-store.test.ts +441 -0
- package/src/__tests__/proxy-approval-callback.test.ts +4 -75
- package/src/__tests__/registry.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +0 -2
- package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
- package/src/__tests__/sandbox-host-parity.test.ts +5 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
- package/src/__tests__/search-skills-unified.test.ts +4 -3
- package/src/__tests__/send-endpoint-busy.test.ts +42 -3
- package/src/__tests__/set-permission-mode.test.ts +274 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +12 -0
- package/src/__tests__/skill-memory.test.ts +2 -783
- package/src/__tests__/strip-memory-injections.test.ts +187 -0
- package/src/__tests__/subagent-detail.test.ts +84 -0
- package/src/__tests__/subagent-disposal.test.ts +308 -0
- package/src/__tests__/subagent-manager-notify.test.ts +19 -10
- package/src/__tests__/subagent-notify-parent.test.ts +390 -0
- package/src/__tests__/subagent-role-registry.test.ts +108 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
- package/src/__tests__/subagent-tools.test.ts +464 -4
- package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
- package/src/__tests__/task-memory-cleanup.test.ts +12 -12
- package/src/__tests__/terminal-sandbox.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +16 -29
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
- package/src/__tests__/tool-executor.test.ts +4 -27
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/top-level-renderer.test.ts +10 -13
- package/src/__tests__/transport-hints-queue.test.ts +77 -0
- package/src/__tests__/trust-store.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +116 -2
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
- package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
- package/src/__tests__/workspace-policy.test.ts +2 -7
- package/src/agent/loop.ts +6 -29
- package/src/approvals/guardian-request-resolvers.ts +24 -0
- package/src/avatar/traits-png-sync.ts +3 -3
- package/src/channels/types.ts +5 -0
- package/src/cli/__tests__/run-assistant-command.ts +56 -0
- package/src/cli/__tests__/unknown-command.test.ts +33 -0
- package/src/cli/commands/__tests__/email-download.test.ts +245 -0
- package/src/cli/commands/__tests__/email-list.test.ts +192 -0
- package/src/cli/commands/__tests__/email-register.test.ts +186 -0
- package/src/cli/commands/__tests__/email-send.test.ts +291 -0
- package/src/cli/commands/__tests__/email-status.test.ts +181 -0
- package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
- package/src/cli/commands/__tests__/routes.test.ts +562 -0
- package/src/cli/commands/conversations.ts +1 -8
- package/src/cli/commands/default-action.ts +68 -1
- package/src/cli/commands/email.ts +584 -835
- package/src/cli/commands/memory.ts +1 -34
- package/src/cli/commands/notifications.ts +7 -2
- package/src/cli/commands/oauth/__tests__/connect.test.ts +27 -0
- package/src/cli/commands/oauth/connect.ts +25 -5
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
- package/src/cli/commands/routes.ts +396 -0
- package/src/cli/commands/skills.ts +130 -20
- package/src/cli/program.ts +11 -2
- package/src/cli.ts +1 -120
- package/src/config/assistant-feature-flags.ts +59 -55
- package/src/config/bundled-skills/app-builder/SKILL.md +91 -5
- package/src/config/bundled-skills/gmail/SKILL.md +13 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +7 -0
- package/src/config/bundled-skills/schedule/SKILL.md +22 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/bundled-skills/settings/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
- package/src/config/bundled-skills/slack/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/SKILL.md +43 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
- package/src/config/env-registry.ts +63 -0
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/filing.ts +51 -0
- package/src/config/schemas/heartbeat.ts +15 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/security.ts +14 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/managed-catalog.ts +3 -7
- package/src/daemon/app-source-watcher.ts +93 -0
- package/src/daemon/config-watcher.ts +85 -3
- package/src/daemon/context-overflow-approval.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +20 -0
- package/src/daemon/conversation-agent-loop.ts +179 -65
- package/src/daemon/conversation-attachments.ts +0 -1
- package/src/daemon/conversation-history.ts +4 -19
- package/src/daemon/conversation-lifecycle.ts +8 -14
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +30 -8
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +359 -308
- package/src/daemon/conversation-surfaces.ts +65 -0
- package/src/daemon/conversation-tool-setup.ts +44 -17
- package/src/daemon/conversation-workspace.ts +1 -2
- package/src/daemon/conversation.ts +19 -3
- package/src/daemon/date-context.ts +26 -53
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/conversations.ts +5 -7
- package/src/daemon/handlers/shared.test.ts +143 -0
- package/src/daemon/handlers/shared.ts +70 -5
- package/src/daemon/handlers/skills.ts +11 -18
- package/src/daemon/lifecycle.ts +220 -158
- package/src/daemon/message-types/conversations.ts +29 -6
- package/src/daemon/message-types/messages.ts +9 -2
- package/src/daemon/message-types/notifications.ts +12 -0
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +18 -0
- package/src/daemon/profiler-run-store.ts +557 -0
- package/src/daemon/server.ts +87 -10
- package/src/daemon/shutdown-handlers.ts +5 -0
- package/src/daemon/tool-side-effects.ts +23 -3
- package/src/daemon/transport-hints.ts +33 -0
- package/src/export/transcript-formatter.ts +148 -0
- package/src/filing/filing-service.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +96 -7
- package/src/index.ts +1 -1
- package/src/mcp/client.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +149 -27
- package/src/memory/admin.ts +33 -32
- package/src/memory/app-store.ts +69 -0
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +151 -117
- package/src/memory/conversation-directories.ts +39 -0
- package/src/memory/conversation-group-migration.ts +66 -6
- package/src/memory/conversation-queries.ts +58 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/db-init.ts +182 -376
- package/src/memory/embedding-local.ts +1 -1
- package/src/memory/graph/bootstrap.ts +75 -66
- package/src/memory/graph/capability-seed.ts +167 -17
- package/src/memory/graph/consolidation.ts +38 -4
- package/src/memory/graph/conversation-graph-memory.ts +133 -104
- package/src/memory/graph/extraction-job.ts +9 -4
- package/src/memory/graph/extraction.ts +66 -23
- package/src/memory/graph/graph-memory-state-store.ts +37 -0
- package/src/memory/graph/graph-search.ts +29 -15
- package/src/memory/graph/injection.ts +38 -8
- package/src/memory/graph/inspect.ts +12 -3
- package/src/memory/graph/retriever.ts +365 -262
- package/src/memory/graph/store.test.ts +48 -0
- package/src/memory/graph/store.ts +150 -11
- package/src/memory/graph/tool-handlers.ts +84 -209
- package/src/memory/graph/tools.ts +8 -52
- package/src/memory/graph/types.ts +24 -0
- package/src/memory/group-crud.ts +25 -9
- package/src/memory/job-handlers/cleanup.ts +44 -1
- package/src/memory/jobs-store.ts +70 -60
- package/src/memory/jobs-worker.ts +44 -28
- package/src/memory/llm-request-log-store.ts +96 -12
- package/src/memory/memory-recall-log-store.ts +49 -5
- package/src/memory/migrations/203-drop-memory-items-tables.ts +33 -1
- package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
- package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
- package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
- package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +14 -0
- package/src/memory/schema/infrastructure.ts +8 -1
- package/src/memory/schema/memory-core.ts +0 -51
- package/src/memory/schema/memory-graph.ts +15 -0
- package/src/memory/task-memory-cleanup.ts +30 -11
- package/src/messaging/provider.ts +1 -1
- package/src/notifications/broadcaster.ts +6 -0
- package/src/notifications/conversation-pairing.ts +12 -4
- package/src/notifications/copy-composer.ts +86 -0
- package/src/notifications/decision-engine.ts +35 -0
- package/src/notifications/emit-signal.ts +14 -0
- package/src/notifications/signal.ts +11 -0
- package/src/oauth/platform-connection.test.ts +2 -2
- package/src/oauth/seed-providers.ts +1 -0
- package/src/permissions/checker.ts +15 -4
- package/src/permissions/defaults.ts +7 -8
- package/src/permissions/permission-mode-store.ts +180 -0
- package/src/permissions/permission-mode.ts +31 -0
- package/src/permissions/prompter.ts +0 -2
- package/src/permissions/workspace-policy.ts +9 -0
- package/src/platform/client.ts +1 -1
- package/src/prompts/system-prompt.ts +59 -7
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
- package/src/prompts/templates/BOOTSTRAP.md +76 -162
- package/src/prompts/templates/HEARTBEAT.md +3 -1
- package/src/prompts/templates/SOUL.md +30 -9
- package/src/prompts/templates/UPDATES.md +8 -0
- package/src/providers/anthropic/client.ts +107 -219
- package/src/runtime/assistant-event-hub.ts +22 -0
- package/src/runtime/auth/route-policy.ts +23 -0
- package/src/runtime/auth/token-service.ts +8 -0
- package/src/runtime/http-server.ts +32 -2
- package/src/runtime/http-types.ts +12 -1
- package/src/runtime/migrations/vbundle-builder.ts +389 -3
- package/src/runtime/migrations/vbundle-importer.ts +8 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
- package/src/runtime/routes/app-management-routes.ts +1 -11
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
- package/src/runtime/routes/archive-utils.ts +29 -0
- package/src/runtime/routes/avatar-routes.ts +2 -9
- package/src/runtime/routes/btw-routes.ts +14 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +185 -0
- package/src/runtime/routes/conversation-management-routes.ts +1 -14
- package/src/runtime/routes/conversation-query-routes.ts +49 -3
- package/src/runtime/routes/conversation-routes.ts +270 -44
- package/src/runtime/routes/group-routes.ts +22 -8
- package/src/runtime/routes/heartbeat-routes.ts +4 -10
- package/src/runtime/routes/identity-routes.ts +53 -18
- package/src/runtime/routes/llm-context-normalization.ts +14 -10
- package/src/runtime/routes/log-export/AGENTS.md +104 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
- package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
- package/src/runtime/routes/log-export-routes.ts +41 -278
- package/src/runtime/routes/memory-item-routes.test.ts +168 -233
- package/src/runtime/routes/migration-routes.ts +18 -7
- package/src/runtime/routes/profiler-routes.ts +350 -0
- package/src/runtime/routes/schedule-routes.ts +27 -12
- package/src/runtime/routes/settings-routes.ts +95 -8
- package/src/runtime/routes/subagents-routes.ts +28 -7
- package/src/runtime/routes/user-route-dispatcher.ts +223 -0
- package/src/runtime/routes/user-routes.ts +41 -0
- package/src/runtime/routes/workspace-routes.ts +0 -1
- package/src/schedule/schedule-store.ts +30 -0
- package/src/schedule/scheduler.ts +45 -18
- package/src/skills/catalog-install.ts +10 -2
- package/src/skills/inline-command-runner.ts +12 -14
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/skill-memory.ts +1 -293
- package/src/subagent/index.ts +13 -3
- package/src/subagent/manager.ts +308 -29
- package/src/subagent/types.ts +68 -0
- package/src/tasks/task-runner.ts +4 -4
- package/src/tools/apps/executors.ts +29 -4
- package/src/tools/filesystem/list.ts +93 -0
- package/src/tools/permission-checker.ts +78 -18
- package/src/tools/registry.ts +4 -0
- package/src/tools/schedule/create.ts +3 -0
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +6 -0
- package/src/tools/secret-detection-handler.ts +0 -1
- package/src/tools/shared/filesystem/errors.ts +5 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
- package/src/tools/shared/filesystem/types.ts +17 -0
- package/src/tools/shared/shell-output.ts +31 -2
- package/src/tools/skills/sandbox-runner.ts +3 -6
- package/src/tools/subagent/abort.ts +12 -2
- package/src/tools/subagent/message.ts +9 -2
- package/src/tools/subagent/notify-parent.ts +79 -0
- package/src/tools/subagent/read.ts +29 -8
- package/src/tools/subagent/resolve.ts +21 -0
- package/src/tools/subagent/spawn.ts +2 -0
- package/src/tools/subagent/status.ts +11 -1
- package/src/tools/system/avatar-generator.ts +3 -3
- package/src/tools/system/register.ts +23 -0
- package/src/tools/system/set-permission-mode.ts +103 -0
- package/src/tools/terminal/parser.ts +30 -5
- package/src/tools/terminal/safe-env.ts +16 -1
- package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
- package/src/tools/terminal/sandbox.ts +4 -1
- package/src/tools/terminal/shell.ts +3 -5
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +2 -3
- package/src/util/logger.ts +1 -1
- package/src/util/platform.ts +50 -17
- package/src/watcher/provider-types.ts +1 -1
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
- package/src/workspace/migrations/029-seed-pkb.ts +85 -0
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +5 -9
- package/src/__tests__/cli-memory.test.ts +0 -377
- package/src/__tests__/clipboard.test.ts +0 -88
- package/src/cli/cli-memory.ts +0 -179
- package/src/util/clipboard.ts +0 -34
|
@@ -62,14 +62,10 @@ mock.module("../../memory/qdrant-circuit-breaker.js", () => ({
|
|
|
62
62
|
withQdrantBreaker: async (fn: () => Promise<unknown>) => fn(),
|
|
63
63
|
}));
|
|
64
64
|
|
|
65
|
-
import {
|
|
65
|
+
import { eq } from "drizzle-orm";
|
|
66
66
|
|
|
67
67
|
import { getDb, initializeDb } from "../../memory/db.js";
|
|
68
|
-
import {
|
|
69
|
-
memoryEmbeddings,
|
|
70
|
-
memoryItems,
|
|
71
|
-
memoryJobs,
|
|
72
|
-
} from "../../memory/schema.js";
|
|
68
|
+
import { memoryGraphNodes, memoryJobs } from "../../memory/schema.js";
|
|
73
69
|
import type { RouteContext } from "../http-router.js";
|
|
74
70
|
import { memoryItemRouteDefinitions } from "./memory-item-routes.js";
|
|
75
71
|
|
|
@@ -125,42 +121,45 @@ function makeJsonCtx(
|
|
|
125
121
|
|
|
126
122
|
function insertItem(opts: {
|
|
127
123
|
id: string;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
lastSeenAt?: number;
|
|
135
|
-
supersedes?: string;
|
|
136
|
-
supersededBy?: string;
|
|
124
|
+
type: string;
|
|
125
|
+
content: string;
|
|
126
|
+
fidelity?: string;
|
|
127
|
+
significance?: number;
|
|
128
|
+
created?: number;
|
|
129
|
+
lastAccessed?: number;
|
|
137
130
|
}) {
|
|
138
131
|
const db = getDb();
|
|
139
132
|
const now = Date.now();
|
|
140
|
-
db.insert(
|
|
133
|
+
db.insert(memoryGraphNodes)
|
|
141
134
|
.values({
|
|
142
135
|
id: opts.id,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
136
|
+
content: opts.content,
|
|
137
|
+
type: opts.type,
|
|
138
|
+
created: opts.created ?? now,
|
|
139
|
+
lastAccessed: opts.lastAccessed ?? now,
|
|
140
|
+
lastConsolidated: now,
|
|
141
|
+
eventDate: null,
|
|
142
|
+
emotionalCharge: JSON.stringify({
|
|
143
|
+
valence: 0,
|
|
144
|
+
intensity: 0.1,
|
|
145
|
+
decayCurve: "linear",
|
|
146
|
+
decayRate: 0.05,
|
|
147
|
+
originalIntensity: 0.1,
|
|
148
|
+
}),
|
|
149
|
+
fidelity: opts.fidelity ?? "vivid",
|
|
147
150
|
confidence: 0.95,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
significance: opts.significance ?? 0.8,
|
|
152
|
+
stability: 14,
|
|
153
|
+
reinforcementCount: 0,
|
|
154
|
+
lastReinforced: now,
|
|
155
|
+
sourceConversations: JSON.stringify([]),
|
|
156
|
+
sourceType: "direct",
|
|
157
|
+
narrativeRole: null,
|
|
158
|
+
partOfStory: null,
|
|
159
|
+
imageRefs: null,
|
|
151
160
|
scopeId: "default",
|
|
152
|
-
firstSeenAt: opts.firstSeenAt ?? now,
|
|
153
|
-
lastSeenAt: opts.lastSeenAt ?? now,
|
|
154
|
-
lastUsedAt: null,
|
|
155
161
|
})
|
|
156
162
|
.run();
|
|
157
|
-
|
|
158
|
-
if (opts.supersedes || opts.supersededBy) {
|
|
159
|
-
const set: Record<string, unknown> = {};
|
|
160
|
-
if (opts.supersedes) set.supersedes = opts.supersedes;
|
|
161
|
-
if (opts.supersededBy) set.supersededBy = opts.supersededBy;
|
|
162
|
-
db.update(memoryItems).set(set).where(eq(memoryItems.id, opts.id)).run();
|
|
163
|
-
}
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
// ---------------------------------------------------------------------------
|
|
@@ -174,9 +173,10 @@ describe("Memory Item Routes", () => {
|
|
|
174
173
|
|
|
175
174
|
beforeEach(() => {
|
|
176
175
|
const db = getDb();
|
|
177
|
-
db.run("DELETE FROM
|
|
178
|
-
db.run("DELETE FROM
|
|
179
|
-
db.run("DELETE FROM
|
|
176
|
+
db.run("DELETE FROM memory_graph_node_edits");
|
|
177
|
+
db.run("DELETE FROM memory_graph_triggers");
|
|
178
|
+
db.run("DELETE FROM memory_graph_edges");
|
|
179
|
+
db.run("DELETE FROM memory_graph_nodes");
|
|
180
180
|
db.run("DELETE FROM memory_jobs");
|
|
181
181
|
});
|
|
182
182
|
|
|
@@ -199,16 +199,14 @@ describe("Memory Item Routes", () => {
|
|
|
199
199
|
test("returns all active items by default", async () => {
|
|
200
200
|
insertItem({
|
|
201
201
|
id: "i1",
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
statement: "st1",
|
|
202
|
+
type: "semantic",
|
|
203
|
+
content: "s1\nst1",
|
|
205
204
|
});
|
|
206
205
|
insertItem({
|
|
207
206
|
id: "i2",
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
status: "deleted",
|
|
207
|
+
type: "episodic",
|
|
208
|
+
content: "s2\nst2",
|
|
209
|
+
fidelity: "gone",
|
|
212
210
|
});
|
|
213
211
|
|
|
214
212
|
const ctx = makeCtx();
|
|
@@ -226,17 +224,15 @@ describe("Memory Item Routes", () => {
|
|
|
226
224
|
test("returns items of all statuses when status=all", async () => {
|
|
227
225
|
insertItem({
|
|
228
226
|
id: "i1",
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
status: "active",
|
|
227
|
+
type: "semantic",
|
|
228
|
+
content: "s1\nst1",
|
|
229
|
+
fidelity: "vivid",
|
|
233
230
|
});
|
|
234
231
|
insertItem({
|
|
235
232
|
id: "i2",
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
status: "deleted",
|
|
233
|
+
type: "episodic",
|
|
234
|
+
content: "s2\nst2",
|
|
235
|
+
fidelity: "gone",
|
|
240
236
|
});
|
|
241
237
|
|
|
242
238
|
const ctx = makeCtx({ status: "all" });
|
|
@@ -255,18 +251,16 @@ describe("Memory Item Routes", () => {
|
|
|
255
251
|
test("filters by kind", async () => {
|
|
256
252
|
insertItem({
|
|
257
253
|
id: "i1",
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
statement: "st1",
|
|
254
|
+
type: "semantic",
|
|
255
|
+
content: "s1\nst1",
|
|
261
256
|
});
|
|
262
257
|
insertItem({
|
|
263
258
|
id: "i2",
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
statement: "st2",
|
|
259
|
+
type: "episodic",
|
|
260
|
+
content: "s2\nst2",
|
|
267
261
|
});
|
|
268
262
|
|
|
269
|
-
const ctx = makeCtx({ kind: "
|
|
263
|
+
const ctx = makeCtx({ kind: "semantic" });
|
|
270
264
|
const res = await handler(ctx);
|
|
271
265
|
const body = (await res.json()) as {
|
|
272
266
|
items: Array<{ id: string }>;
|
|
@@ -276,18 +270,16 @@ describe("Memory Item Routes", () => {
|
|
|
276
270
|
expect(body.items[0].id).toBe("i1");
|
|
277
271
|
});
|
|
278
272
|
|
|
279
|
-
test("filters by search on
|
|
273
|
+
test("filters by search on content", async () => {
|
|
280
274
|
insertItem({
|
|
281
275
|
id: "i1",
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
statement: "User prefers dark mode",
|
|
276
|
+
type: "semantic",
|
|
277
|
+
content: "dark mode\nUser prefers dark mode",
|
|
285
278
|
});
|
|
286
279
|
insertItem({
|
|
287
280
|
id: "i2",
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
statement: "User name is Alice",
|
|
281
|
+
type: "episodic",
|
|
282
|
+
content: "name\nUser name is Alice",
|
|
291
283
|
});
|
|
292
284
|
|
|
293
285
|
const ctx = makeCtx({ search: "dark" });
|
|
@@ -303,24 +295,21 @@ describe("Memory Item Routes", () => {
|
|
|
303
295
|
test("supports pagination with limit and offset", async () => {
|
|
304
296
|
insertItem({
|
|
305
297
|
id: "i1",
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
lastSeenAt: 1000,
|
|
298
|
+
type: "semantic",
|
|
299
|
+
content: "s1\nst1",
|
|
300
|
+
lastAccessed: 1000,
|
|
310
301
|
});
|
|
311
302
|
insertItem({
|
|
312
303
|
id: "i2",
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
lastSeenAt: 2000,
|
|
304
|
+
type: "semantic",
|
|
305
|
+
content: "s2\nst2",
|
|
306
|
+
lastAccessed: 2000,
|
|
317
307
|
});
|
|
318
308
|
insertItem({
|
|
319
309
|
id: "i3",
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
lastSeenAt: 3000,
|
|
310
|
+
type: "semantic",
|
|
311
|
+
content: "s3\nst3",
|
|
312
|
+
lastAccessed: 3000,
|
|
324
313
|
});
|
|
325
314
|
|
|
326
315
|
const ctx = makeCtx({ limit: "1", offset: "1" });
|
|
@@ -338,17 +327,15 @@ describe("Memory Item Routes", () => {
|
|
|
338
327
|
test("supports sort by firstSeenAt ascending", async () => {
|
|
339
328
|
insertItem({
|
|
340
329
|
id: "i1",
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
firstSeenAt: 3000,
|
|
330
|
+
type: "semantic",
|
|
331
|
+
content: "s1\nst1",
|
|
332
|
+
created: 3000,
|
|
345
333
|
});
|
|
346
334
|
insertItem({
|
|
347
335
|
id: "i2",
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
firstSeenAt: 1000,
|
|
336
|
+
type: "semantic",
|
|
337
|
+
content: "s2\nst2",
|
|
338
|
+
created: 1000,
|
|
352
339
|
});
|
|
353
340
|
|
|
354
341
|
const ctx = makeCtx({ sort: "firstSeenAt", order: "asc" });
|
|
@@ -360,32 +347,21 @@ describe("Memory Item Routes", () => {
|
|
|
360
347
|
expect(body.items[1].id).toBe("i1");
|
|
361
348
|
});
|
|
362
349
|
|
|
363
|
-
test("supports sort by
|
|
350
|
+
test("supports sort by importance descending", async () => {
|
|
364
351
|
insertItem({
|
|
365
352
|
id: "i1",
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
353
|
+
type: "semantic",
|
|
354
|
+
content: "s1\nst1",
|
|
355
|
+
significance: 0.3,
|
|
369
356
|
});
|
|
370
357
|
insertItem({
|
|
371
358
|
id: "i2",
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
.update(memoryItems)
|
|
379
|
-
.set({ accessCount: 2 })
|
|
380
|
-
.where(eq(memoryItems.id, "i1"))
|
|
381
|
-
.run();
|
|
382
|
-
getDb()
|
|
383
|
-
.update(memoryItems)
|
|
384
|
-
.set({ accessCount: 7 })
|
|
385
|
-
.where(eq(memoryItems.id, "i2"))
|
|
386
|
-
.run();
|
|
387
|
-
|
|
388
|
-
const ctx = makeCtx({ sort: "accessCount", order: "desc" });
|
|
359
|
+
type: "semantic",
|
|
360
|
+
content: "s2\nst2",
|
|
361
|
+
significance: 0.9,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const ctx = makeCtx({ sort: "importance", order: "desc" });
|
|
389
365
|
const res = await handler(ctx);
|
|
390
366
|
const body = (await res.json()) as {
|
|
391
367
|
items: Array<{ id: string }>;
|
|
@@ -411,15 +387,13 @@ describe("Memory Item Routes", () => {
|
|
|
411
387
|
test("uses semantic search when embedding backend is available", async () => {
|
|
412
388
|
insertItem({
|
|
413
389
|
id: "i1",
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
statement: "User prefers dark mode",
|
|
390
|
+
type: "semantic",
|
|
391
|
+
content: "dark mode\nUser prefers dark mode",
|
|
417
392
|
});
|
|
418
393
|
insertItem({
|
|
419
394
|
id: "i2",
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
statement: "User name is Alice",
|
|
395
|
+
type: "episodic",
|
|
396
|
+
content: "name\nUser name is Alice",
|
|
423
397
|
});
|
|
424
398
|
|
|
425
399
|
// Enable semantic search
|
|
@@ -433,12 +407,12 @@ describe("Memory Item Routes", () => {
|
|
|
433
407
|
{
|
|
434
408
|
id: "pt-2",
|
|
435
409
|
score: 0.95,
|
|
436
|
-
payload: { target_type: "
|
|
410
|
+
payload: { target_type: "graph_node", target_id: "i2" },
|
|
437
411
|
},
|
|
438
412
|
{
|
|
439
413
|
id: "pt-1",
|
|
440
414
|
score: 0.7,
|
|
441
|
-
payload: { target_type: "
|
|
415
|
+
payload: { target_type: "graph_node", target_id: "i1" },
|
|
442
416
|
},
|
|
443
417
|
];
|
|
444
418
|
|
|
@@ -463,15 +437,13 @@ describe("Memory Item Routes", () => {
|
|
|
463
437
|
test("falls back to SQL LIKE when backend is unavailable", async () => {
|
|
464
438
|
insertItem({
|
|
465
439
|
id: "i1",
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
statement: "User prefers dark mode",
|
|
440
|
+
type: "semantic",
|
|
441
|
+
content: "dark mode\nUser prefers dark mode",
|
|
469
442
|
});
|
|
470
443
|
insertItem({
|
|
471
444
|
id: "i2",
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
statement: "User name is Alice",
|
|
445
|
+
type: "episodic",
|
|
446
|
+
content: "name\nUser name is Alice",
|
|
475
447
|
});
|
|
476
448
|
|
|
477
449
|
// Backend unavailable
|
|
@@ -493,21 +465,18 @@ describe("Memory Item Routes", () => {
|
|
|
493
465
|
test("semantic search respects pagination", async () => {
|
|
494
466
|
insertItem({
|
|
495
467
|
id: "i1",
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
statement: "first item",
|
|
468
|
+
type: "semantic",
|
|
469
|
+
content: "s1\nfirst item",
|
|
499
470
|
});
|
|
500
471
|
insertItem({
|
|
501
472
|
id: "i2",
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
statement: "second item",
|
|
473
|
+
type: "semantic",
|
|
474
|
+
content: "s2\nsecond item",
|
|
505
475
|
});
|
|
506
476
|
insertItem({
|
|
507
477
|
id: "i3",
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
statement: "third item",
|
|
478
|
+
type: "semantic",
|
|
479
|
+
content: "s3\nthird item",
|
|
511
480
|
});
|
|
512
481
|
|
|
513
482
|
mockBackendStatus = {
|
|
@@ -519,17 +488,17 @@ describe("Memory Item Routes", () => {
|
|
|
519
488
|
{
|
|
520
489
|
id: "pt-1",
|
|
521
490
|
score: 0.9,
|
|
522
|
-
payload: { target_type: "
|
|
491
|
+
payload: { target_type: "graph_node", target_id: "i1" },
|
|
523
492
|
},
|
|
524
493
|
{
|
|
525
494
|
id: "pt-2",
|
|
526
495
|
score: 0.8,
|
|
527
|
-
payload: { target_type: "
|
|
496
|
+
payload: { target_type: "graph_node", target_id: "i2" },
|
|
528
497
|
},
|
|
529
498
|
{
|
|
530
499
|
id: "pt-3",
|
|
531
500
|
score: 0.7,
|
|
532
|
-
payload: { target_type: "
|
|
501
|
+
payload: { target_type: "graph_node", target_id: "i3" },
|
|
533
502
|
},
|
|
534
503
|
];
|
|
535
504
|
|
|
@@ -553,9 +522,8 @@ describe("Memory Item Routes", () => {
|
|
|
553
522
|
test("falls back to SQL when semantic returns empty results", async () => {
|
|
554
523
|
insertItem({
|
|
555
524
|
id: "i1",
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
statement: "User prefers dark mode",
|
|
525
|
+
type: "semantic",
|
|
526
|
+
content: "dark mode\nUser prefers dark mode",
|
|
559
527
|
});
|
|
560
528
|
|
|
561
529
|
mockBackendStatus = {
|
|
@@ -593,9 +561,8 @@ describe("Memory Item Routes", () => {
|
|
|
593
561
|
test("returns item by ID", async () => {
|
|
594
562
|
insertItem({
|
|
595
563
|
id: "i1",
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
statement: "Prefers dark mode",
|
|
564
|
+
type: "semantic",
|
|
565
|
+
content: "dark mode\nPrefers dark mode",
|
|
599
566
|
});
|
|
600
567
|
|
|
601
568
|
const ctx = makeCtx({}, { id: "i1" });
|
|
@@ -614,33 +581,20 @@ describe("Memory Item Routes", () => {
|
|
|
614
581
|
expect(res.status).toBe(404);
|
|
615
582
|
});
|
|
616
583
|
|
|
617
|
-
test("
|
|
618
|
-
insertItem({
|
|
619
|
-
id: "old",
|
|
620
|
-
kind: "preference",
|
|
621
|
-
subject: "old pref",
|
|
622
|
-
statement: "old",
|
|
623
|
-
});
|
|
584
|
+
test("returns null for legacy supersedes/supersededBy fields", async () => {
|
|
624
585
|
insertItem({
|
|
625
|
-
id: "
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
statement: "new",
|
|
586
|
+
id: "i1",
|
|
587
|
+
type: "semantic",
|
|
588
|
+
content: "some content\nsome statement",
|
|
629
589
|
});
|
|
630
590
|
|
|
631
|
-
|
|
632
|
-
getDb()
|
|
633
|
-
.update(memoryItems)
|
|
634
|
-
.set({ supersedes: "old" })
|
|
635
|
-
.where(eq(memoryItems.id, "new"))
|
|
636
|
-
.run();
|
|
637
|
-
|
|
638
|
-
const ctx = makeCtx({}, { id: "new" });
|
|
591
|
+
const ctx = makeCtx({}, { id: "i1" });
|
|
639
592
|
const res = await handler(ctx);
|
|
640
593
|
const body = (await res.json()) as {
|
|
641
|
-
item: {
|
|
594
|
+
item: { supersedes: unknown; supersededBy: unknown };
|
|
642
595
|
};
|
|
643
|
-
expect(body.item.
|
|
596
|
+
expect(body.item.supersedes).toBeNull();
|
|
597
|
+
expect(body.item.supersededBy).toBeNull();
|
|
644
598
|
});
|
|
645
599
|
});
|
|
646
600
|
|
|
@@ -653,7 +607,7 @@ describe("Memory Item Routes", () => {
|
|
|
653
607
|
|
|
654
608
|
test("creates a new memory item", async () => {
|
|
655
609
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
656
|
-
kind: "
|
|
610
|
+
kind: "semantic",
|
|
657
611
|
subject: "dark mode",
|
|
658
612
|
statement: "User prefers dark mode",
|
|
659
613
|
});
|
|
@@ -662,14 +616,14 @@ describe("Memory Item Routes", () => {
|
|
|
662
616
|
const body = (await res.json()) as {
|
|
663
617
|
item: { id: string; kind: string; subject: string; statement: string };
|
|
664
618
|
};
|
|
665
|
-
expect(body.item.kind).toBe("
|
|
619
|
+
expect(body.item.kind).toBe("semantic");
|
|
666
620
|
expect(body.item.subject).toBe("dark mode");
|
|
667
621
|
expect(body.item.statement).toBe("User prefers dark mode");
|
|
668
622
|
});
|
|
669
623
|
|
|
670
624
|
test("uses custom importance when provided", async () => {
|
|
671
625
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
672
|
-
kind: "
|
|
626
|
+
kind: "semantic",
|
|
673
627
|
subject: "importance test",
|
|
674
628
|
statement: "Testing custom importance",
|
|
675
629
|
importance: 0.5,
|
|
@@ -682,9 +636,9 @@ describe("Memory Item Routes", () => {
|
|
|
682
636
|
expect(body.item.importance).toBe(0.5);
|
|
683
637
|
});
|
|
684
638
|
|
|
685
|
-
test("rejects duplicate
|
|
639
|
+
test("rejects duplicate content", async () => {
|
|
686
640
|
const payload = {
|
|
687
|
-
kind: "
|
|
641
|
+
kind: "semantic",
|
|
688
642
|
subject: "dark mode",
|
|
689
643
|
statement: "User prefers dark mode",
|
|
690
644
|
};
|
|
@@ -707,18 +661,24 @@ describe("Memory Item Routes", () => {
|
|
|
707
661
|
expect(res.status).toBe(400);
|
|
708
662
|
});
|
|
709
663
|
|
|
710
|
-
test("
|
|
664
|
+
test("accepts missing subject (optional)", async () => {
|
|
711
665
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
712
|
-
kind: "
|
|
713
|
-
statement: "test",
|
|
666
|
+
kind: "semantic",
|
|
667
|
+
statement: "test content without subject",
|
|
714
668
|
});
|
|
715
669
|
const res = await handler(ctx);
|
|
716
|
-
expect(res.status).toBe(
|
|
670
|
+
expect(res.status).toBe(201);
|
|
671
|
+
const body = (await res.json()) as {
|
|
672
|
+
item: { subject: string; statement: string };
|
|
673
|
+
};
|
|
674
|
+
// When no subject, content has no newline, so subject and statement are the same
|
|
675
|
+
expect(body.item.subject).toBe("test content without subject");
|
|
676
|
+
expect(body.item.statement).toBe("test content without subject");
|
|
717
677
|
});
|
|
718
678
|
|
|
719
679
|
test("rejects missing statement", async () => {
|
|
720
680
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
721
|
-
kind: "
|
|
681
|
+
kind: "semantic",
|
|
722
682
|
subject: "test",
|
|
723
683
|
});
|
|
724
684
|
const res = await handler(ctx);
|
|
@@ -729,7 +689,7 @@ describe("Memory Item Routes", () => {
|
|
|
729
689
|
const longSubject = "a".repeat(200);
|
|
730
690
|
const longStatement = "b".repeat(1000);
|
|
731
691
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
732
|
-
kind: "
|
|
692
|
+
kind: "semantic",
|
|
733
693
|
subject: longSubject,
|
|
734
694
|
statement: longStatement,
|
|
735
695
|
});
|
|
@@ -744,7 +704,7 @@ describe("Memory Item Routes", () => {
|
|
|
744
704
|
|
|
745
705
|
test("enqueues embed job on create", async () => {
|
|
746
706
|
const ctx = makeJsonCtx("memory-items", "POST", {
|
|
747
|
-
kind: "
|
|
707
|
+
kind: "semantic",
|
|
748
708
|
subject: "embed test",
|
|
749
709
|
statement: "Should enqueue embed job",
|
|
750
710
|
});
|
|
@@ -754,7 +714,7 @@ describe("Memory Item Routes", () => {
|
|
|
754
714
|
const db = getDb();
|
|
755
715
|
const jobs = db.select().from(memoryJobs).all();
|
|
756
716
|
const embedJobs = jobs.filter(
|
|
757
|
-
(j) => j.type === "
|
|
717
|
+
(j) => j.type === "embed_graph_node" && j.status === "pending",
|
|
758
718
|
);
|
|
759
719
|
expect(embedJobs.length).toBeGreaterThanOrEqual(1);
|
|
760
720
|
});
|
|
@@ -770,9 +730,8 @@ describe("Memory Item Routes", () => {
|
|
|
770
730
|
test("updates subject and statement", async () => {
|
|
771
731
|
insertItem({
|
|
772
732
|
id: "i1",
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
statement: "old statement",
|
|
733
|
+
type: "semantic",
|
|
734
|
+
content: "old subject\nold statement",
|
|
776
735
|
});
|
|
777
736
|
|
|
778
737
|
const ctx = makeJsonCtx(
|
|
@@ -801,17 +760,16 @@ describe("Memory Item Routes", () => {
|
|
|
801
760
|
expect(res.status).toBe(404);
|
|
802
761
|
});
|
|
803
762
|
|
|
804
|
-
test("detects
|
|
763
|
+
test("detects content collision on update", async () => {
|
|
805
764
|
insertItem({
|
|
806
765
|
id: "i1",
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
statement: "first statement",
|
|
766
|
+
type: "semantic",
|
|
767
|
+
content: "first\nfirst statement",
|
|
810
768
|
});
|
|
811
|
-
// Insert a second item using the create handler to get a real
|
|
769
|
+
// Insert a second item using the create handler to get a real node
|
|
812
770
|
const createHandler = getHandler("memory-items", "POST");
|
|
813
771
|
const createCtx = makeJsonCtx("memory-items", "POST", {
|
|
814
|
-
kind: "
|
|
772
|
+
kind: "semantic",
|
|
815
773
|
subject: "second",
|
|
816
774
|
statement: "second statement",
|
|
817
775
|
});
|
|
@@ -832,29 +790,27 @@ describe("Memory Item Routes", () => {
|
|
|
832
790
|
test("allows updating kind", async () => {
|
|
833
791
|
insertItem({
|
|
834
792
|
id: "i1",
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
statement: "test",
|
|
793
|
+
type: "semantic",
|
|
794
|
+
content: "test\ntest",
|
|
838
795
|
});
|
|
839
796
|
|
|
840
797
|
const ctx = makeJsonCtx(
|
|
841
798
|
"memory-items/i1",
|
|
842
799
|
"PATCH",
|
|
843
|
-
{ kind: "
|
|
800
|
+
{ kind: "episodic" },
|
|
844
801
|
{ id: "i1" },
|
|
845
802
|
);
|
|
846
803
|
const res = await handler(ctx);
|
|
847
804
|
expect(res.status).toBe(200);
|
|
848
805
|
const body = (await res.json()) as { item: { kind: string } };
|
|
849
|
-
expect(body.item.kind).toBe("
|
|
806
|
+
expect(body.item.kind).toBe("episodic");
|
|
850
807
|
});
|
|
851
808
|
|
|
852
809
|
test("rejects invalid kind on update", async () => {
|
|
853
810
|
insertItem({
|
|
854
811
|
id: "i1",
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
statement: "test",
|
|
812
|
+
type: "semantic",
|
|
813
|
+
content: "test\ntest",
|
|
858
814
|
});
|
|
859
815
|
|
|
860
816
|
const ctx = makeJsonCtx(
|
|
@@ -870,9 +826,8 @@ describe("Memory Item Routes", () => {
|
|
|
870
826
|
test("enqueues embed job when statement changes", async () => {
|
|
871
827
|
insertItem({
|
|
872
828
|
id: "i1",
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
statement: "old statement",
|
|
829
|
+
type: "semantic",
|
|
830
|
+
content: "test\nold statement",
|
|
876
831
|
});
|
|
877
832
|
|
|
878
833
|
// Clear jobs first
|
|
@@ -889,7 +844,7 @@ describe("Memory Item Routes", () => {
|
|
|
889
844
|
const db = getDb();
|
|
890
845
|
const jobs = db.select().from(memoryJobs).all();
|
|
891
846
|
const embedJobs = jobs.filter(
|
|
892
|
-
(j) => j.type === "
|
|
847
|
+
(j) => j.type === "embed_graph_node" && j.status === "pending",
|
|
893
848
|
);
|
|
894
849
|
expect(embedJobs.length).toBe(1);
|
|
895
850
|
});
|
|
@@ -905,23 +860,22 @@ describe("Memory Item Routes", () => {
|
|
|
905
860
|
test("deletes item and returns 204", async () => {
|
|
906
861
|
insertItem({
|
|
907
862
|
id: "i1",
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
statement: "test",
|
|
863
|
+
type: "semantic",
|
|
864
|
+
content: "test\ntest",
|
|
911
865
|
});
|
|
912
866
|
|
|
913
867
|
const ctx = makeJsonCtx("memory-items/i1", "DELETE", null, { id: "i1" });
|
|
914
868
|
const res = await handler(ctx);
|
|
915
869
|
expect(res.status).toBe(204);
|
|
916
870
|
|
|
917
|
-
// Verify the
|
|
871
|
+
// Verify the node is gone
|
|
918
872
|
const db = getDb();
|
|
919
|
-
const
|
|
873
|
+
const node = db
|
|
920
874
|
.select()
|
|
921
|
-
.from(
|
|
922
|
-
.where(eq(
|
|
875
|
+
.from(memoryGraphNodes)
|
|
876
|
+
.where(eq(memoryGraphNodes.id, "i1"))
|
|
923
877
|
.get();
|
|
924
|
-
expect(
|
|
878
|
+
expect(node).toBeUndefined();
|
|
925
879
|
});
|
|
926
880
|
|
|
927
881
|
test("returns 404 for non-existent item", async () => {
|
|
@@ -932,46 +886,27 @@ describe("Memory Item Routes", () => {
|
|
|
932
886
|
expect(res.status).toBe(404);
|
|
933
887
|
});
|
|
934
888
|
|
|
935
|
-
test("
|
|
889
|
+
test("enqueues delete_qdrant_vectors job on delete", async () => {
|
|
936
890
|
insertItem({
|
|
937
891
|
id: "i1",
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
statement: "test",
|
|
892
|
+
type: "semantic",
|
|
893
|
+
content: "test\ntest",
|
|
941
894
|
});
|
|
942
895
|
|
|
943
|
-
// Insert an embedding for this item
|
|
944
|
-
const db = getDb();
|
|
945
|
-
db.insert(memoryEmbeddings)
|
|
946
|
-
.values({
|
|
947
|
-
id: "emb-1",
|
|
948
|
-
targetType: "item",
|
|
949
|
-
targetId: "i1",
|
|
950
|
-
provider: "test",
|
|
951
|
-
model: "test-model",
|
|
952
|
-
dimensions: 384,
|
|
953
|
-
vectorJson: "[]",
|
|
954
|
-
createdAt: Date.now(),
|
|
955
|
-
updatedAt: Date.now(),
|
|
956
|
-
})
|
|
957
|
-
.run();
|
|
958
|
-
|
|
959
896
|
const ctx = makeJsonCtx("memory-items/i1", "DELETE", null, { id: "i1" });
|
|
960
897
|
const res = await handler(ctx);
|
|
961
898
|
expect(res.status).toBe(204);
|
|
962
899
|
|
|
963
|
-
// Verify
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
.
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
.get();
|
|
974
|
-
expect(emb).toBeUndefined();
|
|
900
|
+
// Verify a delete_qdrant_vectors job was enqueued with graph_node targetType
|
|
901
|
+
const db = getDb();
|
|
902
|
+
const jobs = db.select().from(memoryJobs).all();
|
|
903
|
+
const deleteJobs = jobs.filter(
|
|
904
|
+
(j) => j.type === "delete_qdrant_vectors" && j.status === "pending",
|
|
905
|
+
);
|
|
906
|
+
expect(deleteJobs.length).toBe(1);
|
|
907
|
+
const payload = JSON.parse(deleteJobs[0].payload);
|
|
908
|
+
expect(payload.targetType).toBe("graph_node");
|
|
909
|
+
expect(payload.targetId).toBe("i1");
|
|
975
910
|
});
|
|
976
911
|
});
|
|
977
912
|
});
|