CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
memoryLifecycle.integration.test.ts233 linesDownload Raw Back to memory
1/**2 * @license3 * Copyright 2026 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6 7import * as fs from 'node:fs/promises';8import * as os from 'node:os';9import * as path from 'node:path';10import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';11import type { Config } from '../config/config.js';12import { runAutoMemoryExtractionByAgent } from './extractionAgentPlanner.js';13import { runManagedAutoMemoryDream } from './dream.js';14import { planManagedAutoMemoryDreamByAgent } from './dreamAgentPlanner.js';15import { MemoryManager } from './manager.js';16import { rebuildManagedAutoMemoryIndex } from './indexer.js';17import { getAutoMemoryFilePath, getAutoMemoryIndexPath } from './paths.js';18import { resolveRelevantAutoMemoryPromptForQuery } from './recall.js';19import { scanAutoMemoryTopicDocuments } from './scan.js';20import { ensureAutoMemoryScaffold } from './store.js';21 22vi.mock('./extractionAgentPlanner.js', () => ({23  runAutoMemoryExtractionByAgent: vi.fn(),24}));25 26vi.mock('./dreamAgentPlanner.js', () => ({27  planManagedAutoMemoryDreamByAgent: vi.fn(),28}));29 30describe('managed auto-memory lifecycle integration', () => {31  let tempDir: string;32  let projectRoot: string;33  let mockConfig: Config;34  let extractionCount: number;35  let mgr: MemoryManager;36 37  beforeEach(async () => {38    mgr = new MemoryManager();39    tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'memory-lifecycle-int-'));40    projectRoot = path.join(tempDir, 'project');41    await fs.mkdir(projectRoot, { recursive: true });42    await ensureAutoMemoryScaffold(43      projectRoot,44      new Date('2026-04-01T00:00:00.000Z'),45    );46    mockConfig = {47      getSessionId: () => 'session-1',48      getModel: () => 'qwen3-coder-plus',49    } as Config;50    vi.clearAllMocks();51    extractionCount = 0;52    vi.mocked(runAutoMemoryExtractionByAgent).mockImplementation(53      async (_config, root: string) => {54        extractionCount += 1;55        const topic = extractionCount > 1 ? 'reference' : 'user';56        const relativePath =57          topic === 'reference'58            ? path.join('reference', 'latency-dashboard.md')59            : path.join('user', 'terse-responses.md');60        const filePath = getAutoMemoryFilePath(root, relativePath);61        await fs.mkdir(path.dirname(filePath), { recursive: true });62        const description =63          topic === 'reference'64            ? 'https://grafana.example/d/api-latency'65            : 'I prefer terse responses.';66        await fs.writeFile(67          filePath,68          [69            '---',70            `type: ${topic}`,71            `name: ${topic === 'reference' ? 'Latency Dashboard' : 'Terse Responses'}`,72            `description: ${description}`,73            '---',74            '',75            description,76            '',77          ].join('\n'),78          'utf-8',79        );80 81        return {82          touchedTopics: [topic],83          touchedProjectScope: true,84          touchedUserScope: false,85          hasToolActivity: true,86          systemMessage: undefined,87        };88      },89    );90    vi.mocked(planManagedAutoMemoryDreamByAgent).mockResolvedValue({91      status: 'completed',92      finalText: 'Consolidated memory files and updated the index.',93      filesTouched: [94        getAutoMemoryFilePath(95          projectRoot,96          path.join('user', 'terse-responses.md'),97        ),98        getAutoMemoryFilePath(99          projectRoot,100          path.join('reference', 'latency-dashboard.md'),101        ),102      ],103    });104  });105 106  afterEach(async () => {107    mgr.resetExtractStateForTests();108    await fs.rm(tempDir, {109      recursive: true,110      force: true,111      maxRetries: 3,112      retryDelay: 10,113    });114  });115 116  it('supports a durable memory lifecycle across extraction, recall, and dream', async () => {117    const firstExtraction = mgr.scheduleExtract({118      projectRoot,119      sessionId: 'session-1',120      config: mockConfig,121      history: [122        { role: 'user', parts: [{ text: 'I prefer terse responses.' }] },123      ],124    });125 126    const queuedExtraction = await mgr.scheduleExtract({127      projectRoot,128      sessionId: 'session-1',129      config: mockConfig,130      history: [131        { role: 'user', parts: [{ text: 'I prefer terse responses.' }] },132        { role: 'model', parts: [{ text: 'Understood.' }] },133        {134          role: 'user',135          parts: [136            {137              text: 'The latency dashboard is https://grafana.example/d/api-latency',138            },139          ],140        },141      ],142    });143 144    expect(queuedExtraction.skippedReason).toBe('queued');145 146    const firstResult = await firstExtraction;147    expect(firstResult.touchedTopics).toEqual(['user']);148 149    const drained = await mgr.drain({150      timeoutMs: 1_000,151    });152    expect(drained).toBe(true);153 154    const projectPath = getAutoMemoryFilePath(155      projectRoot,156      path.join('project', 'latency-dashboard.md'),157    );158    await fs.mkdir(path.dirname(projectPath), { recursive: true });159    await fs.writeFile(160      projectPath,161      [162        '---',163        'type: project',164        'name: Latency Dashboard',165        'description: The latency dashboard is https://grafana.example/d/api-latency',166        '---',167        '',168        'The latency dashboard is https://grafana.example/d/api-latency',169        '',170        'Why: This is temporary for this task.',171      ].join('\n'),172      'utf-8',173    );174    await rebuildManagedAutoMemoryIndex(projectRoot);175 176    const duplicateUserPath = getAutoMemoryFilePath(177      projectRoot,178      path.join('user', 'terse-duplicate.md'),179    );180    await fs.mkdir(path.dirname(duplicateUserPath), { recursive: true });181    await fs.writeFile(182      duplicateUserPath,183      [184        '---',185        'type: user',186        'name: User Memory Duplicate',187        'description: Duplicate terse preference',188        '---',189        '',190        'I prefer terse responses.',191        '',192        'Why: User repeatedly asks for concise replies.',193      ].join('\n'),194      'utf-8',195    );196    await rebuildManagedAutoMemoryIndex(projectRoot);197 198    const dreamResult = await runManagedAutoMemoryDream(199      projectRoot,200      new Date('2026-04-01T03:00:00.000Z'),201      mockConfig,202    );203    expect(dreamResult.touchedTopics).toContain('user');204    expect(dreamResult.dedupedEntries).toBe(0);205 206    const indexContent = await fs.readFile(207      getAutoMemoryIndexPath(projectRoot),208      'utf-8',209    );210    const docs = await scanAutoMemoryTopicDocuments(projectRoot);211    const userDoc = docs.find((doc) => doc.type === 'user');212    const projectDoc = docs.find((doc) => doc.type === 'project');213    const referenceDoc = docs.find((doc) => doc.type === 'reference');214 215    expect(userDoc?.body).toContain('I prefer terse responses.');216    expect(userDoc?.body).toContain(217      'Why: User repeatedly asks for concise replies.',218    );219    expect(referenceDoc?.body).toContain('grafana.example/d/api-latency');220    expect(projectDoc?.body).toContain('This is temporary for this task.');221    expect(indexContent).toContain('user/');222 223    const recall = await resolveRelevantAutoMemoryPromptForQuery(224      projectRoot,225      'Check the latency dashboard and use a terse answer.',226    );227    expect(recall.strategy).toBe('heuristic');228    expect(recall.prompt).toContain('## Relevant memory');229    expect(recall.prompt).toContain('user/');230    expect(recall.prompt).toContain('reference/');231  });232});233 
basant307/AI_Governance_Project · CoolFace