81 lines
3.4 KiB
TypeScript
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');
|
|
});
|
|
});
|