diff --git a/packages/context/src/memory/index.ts b/packages/context/src/memory/index.ts index a23c4ed5..28efcd2e 100644 --- a/packages/context/src/memory/index.ts +++ b/packages/context/src/memory/index.ts @@ -8,13 +8,13 @@ export { stepBudgetFor, } from './capture-signals.js'; export { MemoryAgentService } from './memory-agent.service.js'; -export { createLocalProjectMemoryCapture, type CreateLocalProjectMemoryCaptureOptions } from './local-memory.js'; +export { createLocalProjectMemoryIngest, type CreateLocalProjectMemoryIngestOptions } from './local-memory.js'; export { LocalMemoryRunStore, type LocalMemoryRunStoreOptions } from './local-memory-runs.js'; export { - MemoryCaptureService, - type MemoryCaptureServiceDeps, - type MemoryCaptureStartResult, - type MemoryCaptureStatus, + MemoryIngestService, + type MemoryIngestServiceDeps, + type MemoryIngestStartResult, + type MemoryIngestStatus, type MemoryRunRecord, type MemoryRunStatus, type MemoryRunStorePort, diff --git a/packages/context/src/memory/local-memory.test.ts b/packages/context/src/memory/local-memory.test.ts index f0b870eb..24e0df14 100644 --- a/packages/context/src/memory/local-memory.test.ts +++ b/packages/context/src/memory/local-memory.test.ts @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { initKtxProject } from '../project/index.js'; -import { createLocalProjectMemoryCapture } from './local-memory.js'; +import { createLocalProjectMemoryIngest } from './local-memory.js'; import { LocalMemoryRunStore } from './local-memory-runs.js'; vi.mock('ai', () => ({ @@ -77,7 +77,7 @@ describe('LocalMemoryRunStore', () => { }); }); -describe('createLocalProjectMemoryCapture', () => { +describe('createLocalProjectMemoryIngest', () => { let tempDir: string; beforeEach(async () => { @@ -110,13 +110,13 @@ describe('createLocalProjectMemoryCapture', () => { }, }; - const capture = createLocalProjectMemoryCapture(project, { + const ingest = createLocalProjectMemoryIngest(project, { agentRunner: agentRunner as never, runIdFactory: () => 'memory-run-1', }); await expect( - capture.capture({ + ingest.ingest({ userId: 'local-user', chatId: 'chat-1', userMessage: 'define revenue as paid order value net of refunds', @@ -124,12 +124,12 @@ describe('createLocalProjectMemoryCapture', () => { sourceType: 'external_ingest', }), ).resolves.toEqual({ runId: 'memory-run-1' }); - await capture.waitForRun('memory-run-1'); + await ingest.waitForRun('memory-run-1'); await expect(access(join(project.projectDir, '.ktx/db.sqlite'))).resolves.toBeUndefined(); await expectPathMissing(join(project.projectDir, '.ktx/memory-runs/memory-run-1.json')); - await expect(capture.status('memory-run-1')).resolves.toMatchObject({ + await expect(ingest.status('memory-run-1')).resolves.toMatchObject({ runId: 'memory-run-1', status: 'done', done: true, @@ -172,12 +172,12 @@ describe('createLocalProjectMemoryCapture', () => { }, }; - const capture = createLocalProjectMemoryCapture(project, { + const ingest = createLocalProjectMemoryIngest(project, { agentRunner: agentRunner as never, runIdFactory: () => 'memory-run-2', }); - await capture.capture({ + await ingest.ingest({ userId: 'local-user', chatId: 'chat-2', userMessage: 'going forward define orders count as count of public orders', @@ -185,12 +185,12 @@ describe('createLocalProjectMemoryCapture', () => { connectionId: 'warehouse', sourceType: 'external_ingest', }); - await capture.waitForRun('memory-run-2'); + await ingest.waitForRun('memory-run-2'); await expect(access(join(project.projectDir, '.ktx/db.sqlite'))).resolves.toBeUndefined(); await expectPathMissing(join(project.projectDir, '.ktx/memory-runs/memory-run-2.json')); - await expect(capture.status('memory-run-2')).resolves.toMatchObject({ + await expect(ingest.status('memory-run-2')).resolves.toMatchObject({ runId: 'memory-run-2', status: 'done', captured: { wiki: [], sl: ['orders'], xrefs: [] }, diff --git a/packages/context/src/memory/local-memory.ts b/packages/context/src/memory/local-memory.ts index 3cc9d324..c1b1e4bd 100644 --- a/packages/context/src/memory/local-memory.ts +++ b/packages/context/src/memory/local-memory.ts @@ -47,7 +47,7 @@ import { } from '../wiki/index.js'; import { LocalMemoryRunStore } from './local-memory-runs.js'; import { MemoryAgentService } from './memory-agent.service.js'; -import { MemoryCaptureService } from './memory-runs.js'; +import { MemoryIngestService } from './memory-runs.js'; import type { MemoryConnectionPort, MemoryFileStorePort, @@ -60,9 +60,9 @@ import type { const promptsDir = fileURLToPath(new URL('../../prompts', import.meta.url)); const skillsDir = fileURLToPath(new URL('../../skills', import.meta.url)); const LOCAL_AUTHOR = { name: 'KTX Local', email: 'local@ktx.local' }; -const LOCAL_SHAPE_WARNING = 'Local memory capture validates semantic-layer YAML shape only.'; +const LOCAL_SHAPE_WARNING = 'Local memory ingest validates semantic-layer YAML shape only.'; -export interface CreateLocalProjectMemoryCaptureOptions { +export interface CreateLocalProjectMemoryIngestOptions { llmProvider?: KtxLlmProvider; agentRunner?: AgentRunnerService; memoryModel?: string; @@ -72,10 +72,10 @@ export interface CreateLocalProjectMemoryCaptureOptions { logger?: KtxLogger; } -export function createLocalProjectMemoryCapture( +export function createLocalProjectMemoryIngest( project: KtxLocalProject, - options: CreateLocalProjectMemoryCaptureOptions = {}, -): MemoryCaptureService { + options: CreateLocalProjectMemoryIngestOptions = {}, +): MemoryIngestService { const logger = options.logger ?? noopLogger; const rootFileStore = new LocalMemoryFileStore(project.fileStore); const embedding = new NoopEmbeddingPort(); @@ -137,7 +137,7 @@ export function createLocalProjectMemoryCapture( toolsetFactory, logger, }); - return new MemoryCaptureService({ + return new MemoryIngestService({ memoryAgent, runs: new LocalMemoryRunStore({ projectDir: project.projectDir, idFactory: options.runIdFactory }), }); @@ -145,7 +145,7 @@ export function createLocalProjectMemoryCapture( function requireLlmProvider(provider: KtxLlmProvider | null | undefined): KtxLlmProvider { if (!provider) { - throw new Error('createLocalProjectMemoryCapture requires llm.provider.backend or an injected agentRunner'); + throw new Error('createLocalProjectMemoryIngest requires llm.provider.backend or an injected agentRunner'); } return provider; } diff --git a/packages/context/src/memory/memory-runs.test.ts b/packages/context/src/memory/memory-runs.test.ts index 049936ad..9fd9c36d 100644 --- a/packages/context/src/memory/memory-runs.test.ts +++ b/packages/context/src/memory/memory-runs.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest'; import type { MemoryAgentInput, MemoryAgentResult, MemoryAgentService } from './index.js'; -import { MemoryCaptureService, type MemoryRunStorePort } from './memory-runs.js'; +import { MemoryIngestService, type MemoryRunStorePort } from './memory-runs.js'; class InMemoryRunStore implements MemoryRunStorePort { readonly rows = new Map< @@ -74,32 +74,32 @@ function deferred() { } function buildService(): { - capture: MemoryCaptureService; + ingest: MemoryIngestService; store: InMemoryRunStore; - ingest: ReturnType; + memoryAgentIngest: ReturnType; run: ReturnType>; } { const store = new InMemoryRunStore(); const run = deferred(); - const ingest = vi.fn().mockReturnValue(run.promise); - const memoryAgent = { ingest }; + const memoryAgentIngest = vi.fn().mockReturnValue(run.promise); + const memoryAgent = { ingest: memoryAgentIngest }; return { - capture: new MemoryCaptureService({ memoryAgent, runs: store }), + ingest: new MemoryIngestService({ memoryAgent, runs: store }), store, - ingest, + memoryAgentIngest, run, }; } -describe('MemoryCaptureService', () => { - it('creates a run, executes memory capture, and stores a done summary', async () => { +describe('MemoryIngestService', () => { + it('creates a run, executes memory ingest, and stores a done summary', async () => { const result: MemoryAgentResult = { signalDetected: true, actions: [{ target: 'wiki', type: 'created', key: 'revenue', detail: 'captured revenue definition' }], skillsLoaded: ['wiki_capture'], commitHash: 'abc123', }; - const { capture, store, ingest, run } = buildService(); + const { ingest, store, memoryAgentIngest, run } = buildService(); const input: MemoryAgentInput = { userId: 'user-1', @@ -109,21 +109,21 @@ describe('MemoryCaptureService', () => { connectionId: '00000000-0000-0000-0000-000000000001', }; - const started = await capture.capture(input); + const started = await ingest.ingest(input); expect(started.runId).toBe('run-1'); - expect(ingest).toHaveBeenCalledWith(input); - await expect(capture.status(started.runId)).resolves.toMatchObject({ + expect(memoryAgentIngest).toHaveBeenCalledWith(input); + await expect(ingest.status(started.runId)).resolves.toMatchObject({ runId: 'run-1', status: 'running', - stage: 'capturing', + stage: 'ingesting', done: false, }); run.resolve(result); - await capture.waitForRun(started.runId); + await ingest.waitForRun(started.runId); - const status = await capture.status(started.runId); + const status = await ingest.status(started.runId); expect(status).toEqual({ runId: 'run-1', stage: 'done', @@ -142,10 +142,10 @@ describe('MemoryCaptureService', () => { expect(store.rows.get('run-1')?.inputHash).toHaveLength(64); }); - it('stores no-signal captures as done with empty captured arrays', async () => { - const { capture, run } = buildService(); + it('stores no-signal ingests as done with empty captured arrays', async () => { + const { ingest, run } = buildService(); - const started = await capture.capture({ + const started = await ingest.ingest({ userId: 'user-1', chatId: 'chat-2', userMessage: 'Thanks.', @@ -157,9 +157,9 @@ describe('MemoryCaptureService', () => { skillsLoaded: [], commitHash: null, }); - await capture.waitForRun(started.runId); + await ingest.waitForRun(started.runId); - await expect(capture.status(started.runId)).resolves.toMatchObject({ + await expect(ingest.status(started.runId)).resolves.toMatchObject({ done: true, status: 'done', captured: { wiki: [], sl: [], xrefs: [] }, @@ -172,16 +172,16 @@ describe('MemoryCaptureService', () => { const memoryAgent = { ingest: vi.fn().mockRejectedValue(new Error('LLM provider missing')), }; - const capture = new MemoryCaptureService({ memoryAgent, runs: store }); + const ingest = new MemoryIngestService({ memoryAgent, runs: store }); - const started = await capture.capture({ + const started = await ingest.ingest({ userId: 'user-1', chatId: 'chat-3', userMessage: 'Remember this.', }); - await capture.waitForRun(started.runId); + await ingest.waitForRun(started.runId); - await expect(capture.status(started.runId)).resolves.toMatchObject({ + await expect(ingest.status(started.runId)).resolves.toMatchObject({ done: true, status: 'error', stage: 'error', @@ -191,8 +191,8 @@ describe('MemoryCaptureService', () => { }); it('returns null for an unknown run id', async () => { - const { capture } = buildService(); + const { ingest } = buildService(); - await expect(capture.status('missing')).resolves.toBeNull(); + await expect(ingest.status('missing')).resolves.toBeNull(); }); }); diff --git a/packages/context/src/memory/memory-runs.ts b/packages/context/src/memory/memory-runs.ts index 5550d5d0..2b34657e 100644 --- a/packages/context/src/memory/memory-runs.ts +++ b/packages/context/src/memory/memory-runs.ts @@ -21,16 +21,16 @@ export interface MemoryRunStorePort { findById(id: string): Promise; } -export interface MemoryCaptureServiceDeps { +export interface MemoryIngestServiceDeps { memoryAgent: Pick; runs: MemoryRunStorePort; } -export interface MemoryCaptureStartResult { +export interface MemoryIngestStartResult { runId: string; } -export interface MemoryCaptureStatus { +export interface MemoryIngestStatus { runId: string; status: MemoryRunStatus; stage: string; @@ -55,7 +55,7 @@ function inputHash(input: MemoryAgentInput): string { return createHash('sha256').update(stableInput).digest('hex'); } -function capturedKeys(actions: MemoryAction[]): MemoryCaptureStatus['captured'] { +function capturedKeys(actions: MemoryAction[]): MemoryIngestStatus['captured'] { const wiki = new Set(); const sl = new Set(); const xrefs = new Set(); @@ -78,20 +78,20 @@ function capturedKeys(actions: MemoryAction[]): MemoryCaptureStatus['captured'] }; } -export class MemoryCaptureService { +export class MemoryIngestService { private readonly inFlight = new Map>(); - constructor(private readonly deps: MemoryCaptureServiceDeps) {} + constructor(private readonly deps: MemoryIngestServiceDeps) {} - async capture(input: MemoryAgentInput): Promise { + async ingest(input: MemoryAgentInput): Promise { const row = await this.deps.runs.createRunning({ inputHash: inputHash(input), chatId: input.chatId, }); - await this.deps.runs.markRunning(row.id, 'capturing'); + await this.deps.runs.markRunning(row.id, 'ingesting'); - const run = this.runCapture(row.id, input); + const run = this.runIngest(row.id, input); this.inFlight.set(row.id, run); run.finally(() => this.inFlight.delete(row.id)).catch(() => undefined); @@ -102,7 +102,7 @@ export class MemoryCaptureService { await this.inFlight.get(runId); } - private async runCapture(runId: string, input: MemoryAgentInput): Promise { + private async runIngest(runId: string, input: MemoryAgentInput): Promise { try { const outputSummary = await this.deps.memoryAgent.ingest(input); await this.deps.runs.markDone(runId, outputSummary); @@ -111,7 +111,7 @@ export class MemoryCaptureService { } } - async status(runId: string): Promise { + async status(runId: string): Promise { const row = await this.deps.runs.findById(runId); if (!row) { return null;