maestro/src/engine/local-context.test.ts
2026-06-03 05:08:00 +00:00

81 lines
3.4 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { buildLocalConversationContext } from './local-context.js';
import type { LocalTaskComment } from '../db/repository.js';
function comment(id: number, author: string, kind: string, body: string): LocalTaskComment {
return { id, taskId: 1, author, kind, body, createdAt: `2026-05-29T00:00:${String(id).padStart(2, '0')}Z`, injectedAt: null };
}
describe('buildLocalConversationContext', () => {
it('shows the original task with no follow-up when only the initial request exists', () => {
const out = buildLocalConversationContext({
comments: [comment(1, 'user', 'request', 'A を調べて')],
jobInstruction: 'A を調べて',
inputFiles: [],
outputFiles: [],
});
expect(out).toContain('## タスク');
expect(out).toContain('A を調べて');
expect(out).not.toContain('## 現在のユーザー指示');
});
it('treats the latest interjection as the current instruction', () => {
const comments = [
comment(1, 'user', 'request', 'A を調べて'),
comment(2, 'agent', 'progress', '調査中...'),
comment(3, 'user', 'interjection', 'やっぱり B を優先して'),
];
const out = buildLocalConversationContext({
comments,
jobInstruction: 'A を調べて',
inputFiles: [],
outputFiles: [],
});
expect(out).toContain('## 現在のユーザー指示 (これに対応する)');
expect(out).toContain('やっぱり B を優先して');
expect(out).toContain('## オリジナルタスク (参考、対応済みの可能性あり)');
// interjection body also appears in the recent-conversation block
expect(out).toContain('[user/interjection] やっぱり B を優先して');
});
it('keeps a user interjection visible even when many agent progress rows would crowd it out', () => {
const comments: LocalTaskComment[] = [comment(1, 'user', 'interjection', 'C をやって')];
for (let i = 2; i <= 14; i++) comments.push(comment(i, 'agent', 'progress', `step ${i}`));
const out = buildLocalConversationContext({
comments,
jobInstruction: '元のタスク',
inputFiles: [],
outputFiles: [],
});
// last-10 window is all agent rows; the fix must still surface the user message
expect(out).toContain('[user/interjection] C をやって');
expect(out).toContain('## 現在のユーザー指示 (これに対応する)');
expect(out).toContain('C をやって');
});
it('truncates long comment bodies in the recent-conversation block', () => {
const long = 'x'.repeat(600);
// `long` is an OLDER comment so it only appears in the recent block (truncated),
// not as the current instruction (which would render the full body by design).
const out = buildLocalConversationContext({
comments: [comment(1, 'user', 'request', long), comment(2, 'user', 'request', 'newer')],
jobInstruction: 'newer',
inputFiles: [],
outputFiles: [],
});
expect(out).toContain('x'.repeat(500) + '...');
expect(out).not.toContain('x'.repeat(600));
});
it('lists workspace files', () => {
const out = buildLocalConversationContext({
comments: [],
jobInstruction: 'task',
inputFiles: ['a.csv'],
outputFiles: ['report.md'],
});
expect(out).toContain('input/: a.csv');
expect(out).toContain('output/: report.md');
});
});