feat: decomposeTask / requestMoreParts / judgeStatus にプロバイダーイベントロギングを追加

onStream を各オプション型に追加し、runAgent 呼び出しに伝播させる。
これにより team_leader の分解フェーズや Phase 3 判定のイベントが
provider-events.jsonl に記録されるようになる。

変更ファイル:
- agent-usecases.ts: JudgeStatusOptions / DecomposeTaskOptions に onStream 追加
- phase-runner.ts: PhaseRunnerContext に onStream 追加
- status-judgment-phase.ts: judgeStatus に ctx.onStream を渡す
- OptionsBuilder.ts: buildPhaseRunnerContext の戻り値に onStream を含める
- TeamLeaderRunner.ts: decomposeTask / requestMoreParts に engineOptions.onStream を渡す
This commit is contained in:
nrslib 2026-03-02 14:24:57 +09:00
parent b999ae4a4b
commit 872ff5fa36
5 changed files with 12 additions and 1 deletions

View File

@ -1,5 +1,5 @@
import type { AgentResponse, PartDefinition, PieceRule, RuleMatchMethod, Language } from '../models/types.js'; import type { AgentResponse, PartDefinition, PieceRule, RuleMatchMethod, Language } from '../models/types.js';
import { runAgent, type RunAgentOptions } from '../../agents/runner.js'; import { runAgent, type RunAgentOptions, type StreamCallback } from '../../agents/runner.js';
import { detectJudgeIndex, buildJudgePrompt } from '../../agents/judge-utils.js'; import { detectJudgeIndex, buildJudgePrompt } from '../../agents/judge-utils.js';
import { parseParts } from './engine/task-decomposer.js'; import { parseParts } from './engine/task-decomposer.js';
import { loadJudgmentSchema, loadEvaluationSchema, loadDecompositionSchema, loadMorePartsSchema } from './schema-loader.js'; import { loadJudgmentSchema, loadEvaluationSchema, loadDecompositionSchema, loadMorePartsSchema } from './schema-loader.js';
@ -11,6 +11,7 @@ export interface JudgeStatusOptions {
movementName: string; movementName: string;
language?: Language; language?: Language;
interactive?: boolean; interactive?: boolean;
onStream?: StreamCallback;
} }
export interface JudgeStatusResult { export interface JudgeStatusResult {
@ -29,6 +30,7 @@ export interface DecomposeTaskOptions {
language?: Language; language?: Language;
model?: string; model?: string;
provider?: 'claude' | 'codex' | 'opencode' | 'cursor' | 'copilot' | 'mock'; provider?: 'claude' | 'codex' | 'opencode' | 'cursor' | 'copilot' | 'mock';
onStream?: StreamCallback;
} }
export interface MorePartsResponse { export interface MorePartsResponse {
@ -231,6 +233,7 @@ export async function judgeStatus(
maxTurns: 3, maxTurns: 3,
permissionMode: 'readonly' as const, permissionMode: 'readonly' as const,
language: options.language, language: options.language,
onStream: options.onStream,
}; };
// Stage 1: Structured output // Stage 1: Structured output
@ -293,6 +296,7 @@ export async function decomposeTask(
permissionMode: 'readonly', permissionMode: 'readonly',
maxTurns: 4, maxTurns: 4,
outputSchema: loadDecompositionSchema(maxParts), outputSchema: loadDecompositionSchema(maxParts),
onStream: options.onStream,
}); });
if (response.status !== 'done') { if (response.status !== 'done') {
@ -333,6 +337,7 @@ export async function requestMoreParts(
permissionMode: 'readonly', permissionMode: 'readonly',
maxTurns: 4, maxTurns: 4,
outputSchema: loadMorePartsSchema(maxAdditionalParts), outputSchema: loadMorePartsSchema(maxAdditionalParts),
onStream: options.onStream,
}); });
if (response.status !== 'done') { if (response.status !== 'done') {

View File

@ -173,6 +173,7 @@ export class OptionsBuilder {
language: this.getLanguage(), language: this.getLanguage(),
interactive: this.engineOptions.interactive, interactive: this.engineOptions.interactive,
lastResponse, lastResponse,
onStream: this.engineOptions.onStream,
getSessionId: (persona: string) => state.personaSessions.get(persona), getSessionId: (persona: string) => state.personaSessions.get(persona),
buildResumeOptions: this.buildResumeOptions.bind(this), buildResumeOptions: this.buildResumeOptions.bind(this),
buildNewSessionReportOptions: this.buildNewSessionReportOptions.bind(this), buildNewSessionReportOptions: this.buildNewSessionReportOptions.bind(this),

View File

@ -79,6 +79,7 @@ export class TeamLeaderRunner {
personaPath: leaderStep.personaPath, personaPath: leaderStep.personaPath,
model: leaderModel, model: leaderModel,
provider: leaderProvider, provider: leaderProvider,
onStream: this.deps.engineOptions.onStream,
}); });
const leaderResponse: AgentResponse = { const leaderResponse: AgentResponse = {
persona: leaderStep.persona ?? leaderStep.name, persona: leaderStep.persona ?? leaderStep.name,
@ -172,6 +173,7 @@ export class TeamLeaderRunner {
language: this.deps.engineOptions.language, language: this.deps.engineOptions.language,
model: leaderModel, model: leaderModel,
provider: leaderProvider, provider: leaderProvider,
onStream: this.deps.engineOptions.onStream,
}, },
); );
}, },

View File

@ -41,6 +41,8 @@ export interface PhaseRunnerContext {
buildNewSessionReportOptions: (step: PieceMovement, overrides: Pick<RunAgentOptions, 'allowedTools' | 'maxTurns'>) => RunAgentOptions; buildNewSessionReportOptions: (step: PieceMovement, overrides: Pick<RunAgentOptions, 'allowedTools' | 'maxTurns'>) => RunAgentOptions;
/** Update persona session after a phase run */ /** Update persona session after a phase run */
updatePersonaSession: (persona: string, sessionId: string | undefined) => void; updatePersonaSession: (persona: string, sessionId: string | undefined) => void;
/** Stream callback for provider event logging (passed to judgeStatus) */
onStream?: import('../../agents/types.js').StreamCallback;
/** Callback for phase lifecycle logging */ /** Callback for phase lifecycle logging */
onPhaseStart?: (step: PieceMovement, phase: 1 | 2 | 3, phaseName: PhaseName, instruction: string) => void; onPhaseStart?: (step: PieceMovement, phase: 1 | 2 | 3, phaseName: PhaseName, instruction: string) => void;
/** Callback for phase completion logging */ /** Callback for phase completion logging */

View File

@ -93,6 +93,7 @@ export async function runStatusJudgmentPhase(
movementName: step.name, movementName: step.name,
language: ctx.language, language: ctx.language,
interactive: ctx.interactive, interactive: ctx.interactive,
onStream: ctx.onStream,
}); });
const tag = `[${step.name.toUpperCase()}:${result.ruleIndex + 1}]`; const tag = `[${step.name.toUpperCase()}:${result.ruleIndex + 1}]`;
ctx.onPhaseComplete?.(step, 3, 'judge', tag, 'done'); ctx.onPhaseComplete?.(step, 3, 'judge', tag, 'done');