maestro/src/engine/agent-loop.notes-inject.test.ts
2026-06-03 05:08:00 +00:00

134 lines
4.0 KiB
TypeScript

/**
* Smoke test: buildSystemPrompt injects "## Subscribed Notes" when the
* job owner has inject-mode subscriptions, and omits it when they don't.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Database from 'better-sqlite3';
import { mkdtempSync, rmSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { runMigrations } from '../db/migrate.js';
import { NotesRepository } from '../notes/notes-repository.js';
import { NotesService } from '../notes/notes-service.js';
import { buildSystemPrompt, type NotesInjectContext, type Movement } from './agent-loop.js';
import { DEFAULT_NOTES_INJECT } from '../config.js';
function makeMovement(): Movement {
return {
name: 'investigate',
persona: 'investigator',
instruction: 'do the thing',
rules: [{ condition: 'done', next: 'plan' }],
allowedTools: [],
edit: false,
};
}
describe('buildSystemPrompt — notes inject section', () => {
let tmpRoot: string;
let db: Database.Database;
let service: NotesService;
const aliceUser = {
id: 'alice',
role: 'user' as const,
orgIds: [] as string[],
email: 'alice@example.com',
name: 'Alice',
avatarUrl: null,
status: 'active' as const,
defaultVisibility: 'private' as const,
defaultVisibilityOrgId: null,
};
const bobPublisher = { id: 'bob', role: 'user' as const, orgIds: [] as string[] };
beforeEach(() => {
tmpRoot = mkdtempSync(join(tmpdir(), 'al-notes-test-'));
db = new Database(join(tmpRoot, 'test.db'));
runMigrations(db);
db.prepare(
`INSERT INTO users (id, email, name) VALUES ('alice','alice@example.com','Alice'),('bob','bob@example.com','Bob')`
).run();
const repo = new NotesRepository(db);
service = new NotesService({
db,
repo,
userFolderRoot: tmpRoot,
getUserOrgIds: () => [],
});
});
afterEach(() => {
db.close();
rmSync(tmpRoot, { recursive: true, force: true });
});
it('omits ## Subscribed Notes when user has no inject subscriptions', () => {
const prompt = buildSystemPrompt(
makeMovement(),
1, 5, [], undefined, null,
'alice', undefined, undefined, null, undefined,
undefined, // no notesCtx
);
expect(prompt).not.toContain('## Subscribed Notes');
});
it('includes ## Subscribed Notes when inject subscription exists', () => {
// alice publishes a public note
service.writeNote({
ownerId: 'alice',
folder: 'runbooks',
fileName: 'deploy.md',
content: '---\nvisibility: public\n---\nDeploy checklist step 1',
});
// bob subscribes to alice's note in inject mode — alice is the consumer here
// Actually let's have alice subscribe to bob's note:
service.writeNote({
ownerId: 'bob',
folder: 'tips',
fileName: 'shortcuts.md',
content: '---\nvisibility: public\n---\nUseful shortcuts: Ctrl+C',
});
service.upsertSubscription({
consumerUser: aliceUser as Express.User,
publisherUserId: 'bob',
folder: 'tips',
mode: 'inject',
enabled: 1,
});
const notesCtx: NotesInjectContext = {
service,
config: DEFAULT_NOTES_INJECT,
user: aliceUser,
};
const prompt = buildSystemPrompt(
makeMovement(),
1, 5, [], undefined, null,
'alice', undefined, undefined, null, undefined,
notesCtx,
);
expect(prompt).toContain('## Subscribed Notes');
expect(prompt).toContain('shortcuts.md');
expect(prompt).toContain('Useful shortcuts: Ctrl+C');
});
it('does not include section when notesCtx is provided but subscriptions are empty', () => {
const notesCtx: NotesInjectContext = {
service,
config: DEFAULT_NOTES_INJECT,
user: aliceUser,
};
const prompt = buildSystemPrompt(
makeMovement(),
1, 5, [], undefined, null,
'alice', undefined, undefined, null, undefined,
notesCtx,
);
expect(prompt).not.toContain('## Subscribed Notes');
});
});