会話内容からタスク要件をまとめる必要がなくなったので削除
This commit is contained in:
parent
fabf4bcd27
commit
184a1d756a
@ -69,45 +69,33 @@ vi.mock('../infra/github/issue.js', () => ({
|
||||
}));
|
||||
|
||||
import { interactiveMode } from '../features/interactive/index.js';
|
||||
import { getProvider } from '../infra/providers/index.js';
|
||||
import { promptInput, confirm } from '../shared/prompt/index.js';
|
||||
import { summarizeTaskName } from '../infra/task/summarize.js';
|
||||
import { determineWorkflow } from '../features/tasks/execute/selectAndExecute.js';
|
||||
import { getWorkflowDescription } from '../infra/config/loaders/workflowResolver.js';
|
||||
import { resolveIssueTask } from '../infra/github/issue.js';
|
||||
import { addTask, summarizeConversation } from '../features/tasks/index.js';
|
||||
import { addTask } from '../features/tasks/index.js';
|
||||
|
||||
const mockResolveIssueTask = vi.mocked(resolveIssueTask);
|
||||
|
||||
const mockInteractiveMode = vi.mocked(interactiveMode);
|
||||
const mockGetProvider = vi.mocked(getProvider);
|
||||
const mockPromptInput = vi.mocked(promptInput);
|
||||
const mockConfirm = vi.mocked(confirm);
|
||||
const mockSummarizeTaskName = vi.mocked(summarizeTaskName);
|
||||
const mockDetermineWorkflow = vi.mocked(determineWorkflow);
|
||||
const mockGetWorkflowDescription = vi.mocked(getWorkflowDescription);
|
||||
|
||||
/** Helper: set up mocks for the full happy path */
|
||||
function setupFullFlowMocks(overrides?: {
|
||||
conversationTask?: string;
|
||||
summaryContent?: string;
|
||||
task?: string;
|
||||
slug?: string;
|
||||
}) {
|
||||
const task = overrides?.conversationTask ?? 'User: 認証機能を追加したい\n\nAssistant: 了解です。';
|
||||
const summary = overrides?.summaryContent ?? '# 認証機能追加\nJWT認証を実装する';
|
||||
const task = overrides?.task ?? '# 認証機能追加\nJWT認証を実装する';
|
||||
const slug = overrides?.slug ?? 'add-auth';
|
||||
|
||||
mockDetermineWorkflow.mockResolvedValue('default');
|
||||
mockGetWorkflowDescription.mockReturnValue({ name: 'default', description: '' });
|
||||
mockInteractiveMode.mockResolvedValue({ confirmed: true, task });
|
||||
|
||||
const mockProviderCall = vi.fn().mockResolvedValue({ content: summary });
|
||||
mockGetProvider.mockReturnValue({ call: mockProviderCall } as any);
|
||||
|
||||
mockSummarizeTaskName.mockResolvedValue(slug);
|
||||
mockConfirm.mockResolvedValue(false);
|
||||
|
||||
return { mockProviderCall };
|
||||
}
|
||||
|
||||
let testDir: string;
|
||||
@ -135,11 +123,9 @@ describe('addTask', () => {
|
||||
// When
|
||||
await addTask(testDir);
|
||||
|
||||
// Then: no task file created
|
||||
const tasksDir = path.join(testDir, '.takt', 'tasks');
|
||||
const files = fs.existsSync(tasksDir) ? fs.readdirSync(tasksDir) : [];
|
||||
expect(files.length).toBe(0);
|
||||
expect(mockGetProvider).not.toHaveBeenCalled();
|
||||
expect(mockSummarizeTaskName).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -160,38 +146,14 @@ describe('addTask', () => {
|
||||
expect(content).toContain('JWT認証を実装する');
|
||||
});
|
||||
|
||||
it('should summarize conversation via provider.call', async () => {
|
||||
// Given
|
||||
const { mockProviderCall } = setupFullFlowMocks({
|
||||
conversationTask: 'User: バグ修正して\n\nAssistant: どのバグですか?',
|
||||
});
|
||||
|
||||
// When
|
||||
await addTask(testDir);
|
||||
|
||||
// Then: provider.call was called with conversation text
|
||||
expect(mockProviderCall).toHaveBeenCalledWith(
|
||||
'task-summarizer',
|
||||
'User: バグ修正して\n\nAssistant: どのバグですか?',
|
||||
expect.objectContaining({
|
||||
cwd: testDir,
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should use first line of summary for filename generation', async () => {
|
||||
// Given: summary with multiple lines
|
||||
it('should use first line of task for filename generation', async () => {
|
||||
setupFullFlowMocks({
|
||||
summaryContent: 'First line summary\nSecond line details',
|
||||
task: 'First line summary\nSecond line details',
|
||||
slug: 'first-line',
|
||||
});
|
||||
|
||||
// When
|
||||
await addTask(testDir);
|
||||
|
||||
// Then: summarizeTaskName receives only the first line
|
||||
expect(mockSummarizeTaskName).toHaveBeenCalledWith('First line summary', { cwd: testDir });
|
||||
});
|
||||
|
||||
@ -354,11 +316,9 @@ describe('addTask', () => {
|
||||
// When
|
||||
await addTask(testDir, '#99');
|
||||
|
||||
// Then: no task file created, no crash
|
||||
const tasksDir = path.join(testDir, '.takt', 'tasks');
|
||||
const files = fs.readdirSync(tasksDir);
|
||||
expect(files.length).toBe(0);
|
||||
expect(mockGetProvider).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should include issue number in task file when issue reference is used', async () => {
|
||||
@ -378,27 +338,3 @@ describe('addTask', () => {
|
||||
expect(content).toContain('issue: 99');
|
||||
});
|
||||
});
|
||||
|
||||
describe('summarizeConversation', () => {
|
||||
it('should call provider with summarize system prompt', async () => {
|
||||
// Given
|
||||
const mockCall = vi.fn().mockResolvedValue({ content: 'Summary text' });
|
||||
mockGetProvider.mockReturnValue({ call: mockCall } as any);
|
||||
|
||||
// When
|
||||
const result = await summarizeConversation('/project', 'conversation text');
|
||||
|
||||
// Then
|
||||
expect(result).toBe('Summary text');
|
||||
expect(mockCall).toHaveBeenCalledWith(
|
||||
'task-summarizer',
|
||||
'conversation text',
|
||||
expect.objectContaining({
|
||||
cwd: '/project',
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
systemPrompt: expect.stringContaining('会話履歴からタスクの要件をまとめてください'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -105,7 +105,6 @@ describe('YAML content integrity', () => {
|
||||
expect(() => getPrompt('interactive.noTranscript', 'en')).not.toThrow();
|
||||
expect(() => getPromptObject('interactive.ui', 'en')).not.toThrow();
|
||||
expect(() => getPrompt('summarize.slugGenerator')).not.toThrow();
|
||||
expect(() => getPrompt('summarize.conversationSummarizer')).not.toThrow();
|
||||
expect(() => getPrompt('claude.agentDefault')).not.toThrow();
|
||||
expect(() => getPrompt('claude.judgePrompt')).not.toThrow();
|
||||
expect(() => getPromptObject('instruction.metadata', 'en')).not.toThrow();
|
||||
@ -126,7 +125,6 @@ describe('YAML content integrity', () => {
|
||||
expect(() => getPrompt('interactive.noTranscript', 'ja')).not.toThrow();
|
||||
expect(() => getPromptObject('interactive.ui', 'ja')).not.toThrow();
|
||||
expect(() => getPrompt('summarize.slugGenerator', 'ja')).not.toThrow();
|
||||
expect(() => getPrompt('summarize.conversationSummarizer', 'ja')).not.toThrow();
|
||||
expect(() => getPrompt('claude.agentDefault', 'ja')).not.toThrow();
|
||||
expect(() => getPrompt('claude.judgePrompt', 'ja')).not.toThrow();
|
||||
expect(() => getPromptObject('instruction.metadata', 'ja')).not.toThrow();
|
||||
|
||||
@ -13,37 +13,12 @@ import { success, info } from '../../../shared/ui/index.js';
|
||||
import { summarizeTaskName, type TaskFileData } from '../../../infra/task/index.js';
|
||||
import { loadGlobalConfig, getWorkflowDescription } from '../../../infra/config/index.js';
|
||||
import { determineWorkflow } from '../execute/selectAndExecute.js';
|
||||
import { getProvider, type ProviderType } from '../../../infra/providers/index.js';
|
||||
import { createLogger, getErrorMessage } from '../../../shared/utils/index.js';
|
||||
import { getPrompt } from '../../../shared/prompts/index.js';
|
||||
import { isIssueReference, resolveIssueTask, parseIssueNumbers } from '../../../infra/github/index.js';
|
||||
import { interactiveMode } from '../../interactive/index.js';
|
||||
|
||||
const log = createLogger('add-task');
|
||||
|
||||
/**
|
||||
* Summarize conversation history into a task description using AI.
|
||||
*/
|
||||
export async function summarizeConversation(cwd: string, conversationText: string): Promise<string> {
|
||||
const globalConfig = loadGlobalConfig();
|
||||
const providerType = (globalConfig.provider as ProviderType) ?? 'claude';
|
||||
const provider = getProvider(providerType);
|
||||
|
||||
info('Summarizing task from conversation...');
|
||||
|
||||
const response = await provider.call('task-summarizer', conversationText, {
|
||||
cwd,
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
systemPrompt: getPrompt('summarize.conversationSummarizer'),
|
||||
});
|
||||
|
||||
return response.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique task filename with AI-summarized slug
|
||||
*/
|
||||
async function generateFilename(tasksDir: string, taskContent: string, cwd: string): Promise<string> {
|
||||
info('Generating task filename...');
|
||||
const slug = await summarizeTaskName(taskContent, { cwd });
|
||||
@ -112,8 +87,8 @@ export async function addTask(cwd: string, task?: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 会話履歴からタスク要約を生成
|
||||
taskContent = await summarizeConversation(cwd, result.task);
|
||||
// interactiveMode already returns a summarized task from conversation
|
||||
taskContent = result.task;
|
||||
}
|
||||
|
||||
// 3. 要約からファイル名生成
|
||||
|
||||
@ -14,7 +14,7 @@ export {
|
||||
type SelectAndExecuteOptions,
|
||||
type WorktreeConfirmationResult,
|
||||
} from './execute/selectAndExecute.js';
|
||||
export { addTask, summarizeConversation } from './add/index.js';
|
||||
export { addTask } from './add/index.js';
|
||||
export { watchTasks } from './watch/index.js';
|
||||
export {
|
||||
listTasks,
|
||||
|
||||
@ -96,12 +96,6 @@ summarize:
|
||||
worktreeを作るときブランチ名をAIで生成 → ai-branch-naming
|
||||
レビュー画面に元の指示を表示する → show-original-instruction
|
||||
|
||||
conversationSummarizer: |
|
||||
会話履歴からタスクの要件をまとめてください。
|
||||
タスク実行エージェントへの指示として使われます。
|
||||
具体的・簡潔に、必要な情報をすべて含めてください。
|
||||
マークダウン形式で出力してください。
|
||||
|
||||
# ===== Claude Client =====
|
||||
claude:
|
||||
agentDefault: "You are the {agentName} agent. Follow the standard {agentName} workflow."
|
||||
|
||||
@ -109,12 +109,6 @@ summarize:
|
||||
worktreeを作るときブランチ名をAIで生成 → ai-branch-naming
|
||||
レビュー画面に元の指示を表示する → show-original-instruction
|
||||
|
||||
conversationSummarizer: |
|
||||
会話履歴からタスクの要件をまとめてください。
|
||||
タスク実行エージェントへの指示として使われます。
|
||||
具体的・簡潔に、必要な情報をすべて含めてください。
|
||||
マークダウン形式で出力してください。
|
||||
|
||||
# ===== Claude Client =====
|
||||
claude:
|
||||
agentDefault: "You are the {agentName} agent. Follow the standard {agentName} workflow."
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user