(↑↓ to move, Enter to select, b to bookmark, r to remove) [?7l ❯ 🎼 default (current) 🎼 minimal [*] 📁 その他/ 📂 Builtin/ (8) Cancel [?7h が でハングする
90 lines
3.4 KiB
TypeScript
90 lines
3.4 KiB
TypeScript
/**
|
|
* Builds RunAgentOptions for different execution phases.
|
|
*
|
|
* Centralizes the option construction logic that was previously
|
|
* scattered across WorkflowEngine methods.
|
|
*/
|
|
|
|
import { join } from 'node:path';
|
|
import type { WorkflowStep, WorkflowState, Language } from '../../models/types.js';
|
|
import type { RunAgentOptions } from '../../../agents/runner.js';
|
|
import type { PhaseRunnerContext } from '../phase-runner.js';
|
|
import type { WorkflowEngineOptions } from '../types.js';
|
|
|
|
export class OptionsBuilder {
|
|
constructor(
|
|
private readonly engineOptions: WorkflowEngineOptions,
|
|
private readonly getCwd: () => string,
|
|
private readonly getProjectCwd: () => string,
|
|
private readonly getSessionId: (agent: string) => string | undefined,
|
|
private readonly getReportDir: () => string,
|
|
private readonly getLanguage: () => Language | undefined,
|
|
) {}
|
|
|
|
/** Build common RunAgentOptions shared by all phases */
|
|
buildBaseOptions(step: WorkflowStep): RunAgentOptions {
|
|
return {
|
|
cwd: this.getCwd(),
|
|
agentPath: step.agentPath,
|
|
provider: step.provider ?? this.engineOptions.provider,
|
|
model: step.model ?? this.engineOptions.model,
|
|
permissionMode: step.permissionMode,
|
|
onStream: this.engineOptions.onStream,
|
|
onPermissionRequest: this.engineOptions.onPermissionRequest,
|
|
onAskUserQuestion: this.engineOptions.onAskUserQuestion,
|
|
bypassPermissions: this.engineOptions.bypassPermissions,
|
|
};
|
|
}
|
|
|
|
/** Build RunAgentOptions for Phase 1 (main execution) */
|
|
buildAgentOptions(step: WorkflowStep): RunAgentOptions {
|
|
// Phase 1: exclude Write from allowedTools when step has report config AND edit is NOT enabled
|
|
// (If edit is enabled, Write is needed for code implementation even if report exists)
|
|
// Note: edit defaults to undefined, so check !== true to catch both false and undefined
|
|
const allowedTools = step.report && step.edit !== true
|
|
? step.allowedTools?.filter((t) => t !== 'Write')
|
|
: step.allowedTools;
|
|
|
|
// Skip session resume when cwd !== projectCwd (worktree execution) to avoid cross-directory contamination
|
|
const shouldResumeSession = step.session !== 'refresh' && this.getCwd() === this.getProjectCwd();
|
|
|
|
return {
|
|
...this.buildBaseOptions(step),
|
|
sessionId: shouldResumeSession ? this.getSessionId(step.agent ?? step.name) : undefined,
|
|
allowedTools,
|
|
};
|
|
}
|
|
|
|
/** Build RunAgentOptions for session-resume phases (Phase 2, Phase 3) */
|
|
buildResumeOptions(
|
|
step: WorkflowStep,
|
|
sessionId: string,
|
|
overrides: Pick<RunAgentOptions, 'allowedTools' | 'maxTurns'>,
|
|
): RunAgentOptions {
|
|
return {
|
|
...this.buildBaseOptions(step),
|
|
// Do not pass permission mode in report/status phases.
|
|
permissionMode: undefined,
|
|
sessionId,
|
|
allowedTools: overrides.allowedTools,
|
|
maxTurns: overrides.maxTurns,
|
|
};
|
|
}
|
|
|
|
/** Build PhaseRunnerContext for Phase 2/3 execution */
|
|
buildPhaseRunnerContext(
|
|
state: WorkflowState,
|
|
updateAgentSession: (agent: string, sessionId: string | undefined) => void,
|
|
): PhaseRunnerContext {
|
|
return {
|
|
cwd: this.getCwd(),
|
|
reportDir: join(this.getProjectCwd(), this.getReportDir()),
|
|
language: this.getLanguage(),
|
|
interactive: this.engineOptions.interactive,
|
|
getSessionId: (agent: string) => state.agentSessions.get(agent),
|
|
buildResumeOptions: this.buildResumeOptions.bind(this),
|
|
updateAgentSession,
|
|
};
|
|
}
|
|
}
|