import { mergeProviderOptions } from '../../../infra/config/providerOptions.js';
import { trimResumePointStackForWorkflow } from '../run/resume-point.js';
import { buildWorkflowResumePointEntry, workflowEntryMatchesWorkflow } from '../workflow-reference.js';
function encodeWorkflowNamespaceValue(value) {
    return encodeURIComponent(value).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
}
function buildWorkflowCallNamespaceSegment(stepName, workflowName, iteration) {
    return `iteration-${iteration}--step-${encodeWorkflowNamespaceValue(stepName)}--workflow-${encodeWorkflowNamespaceValue(workflowName)}`;
}
export function applyWorkflowCallOverridesToPersonaProviders(personaProviders, overrides) {
    if (!personaProviders) {
        return undefined;
    }
    if (overrides?.provider === undefined && overrides?.model === undefined) {
        return personaProviders;
    }
    return Object.fromEntries(Object.entries(personaProviders).map(([persona, entry]) => {
        const nextEntry = {
            ...(overrides.provider !== undefined
                ? { provider: overrides.provider }
                : entry.provider !== undefined
                    ? { provider: entry.provider }
                    : {}),
        };
        if (overrides.model !== undefined) {
            nextEntry.model = overrides.model;
        }
        else if (overrides.provider === undefined && entry.model !== undefined) {
            nextEntry.model = entry.model;
        }
        if (entry.providerOptions !== undefined) {
            nextEntry.providerOptions = entry.providerOptions;
        }
        return [persona, nextEntry];
    }));
}
export class WorkflowCallExecutor {
    deps;
    constructor(deps) {
        this.deps = deps;
    }
    buildWorkflowCallNamespace(step, childWorkflow) {
        const baseNamespace = this.deps.getOptions().runPathNamespace ?? [];
        const callIteration = this.deps.state.iteration;
        if (!Number.isInteger(callIteration) || callIteration <= 0) {
            throw new Error(`workflow_call step "${step.name}" requires a positive parent iteration before creating child report namespace`);
        }
        return [
            ...baseNamespace,
            'subworkflows',
            buildWorkflowCallNamespaceSegment(step.name, childWorkflow.name, callIteration),
        ];
    }
    resolveChildResumeStartStep(childWorkflow, resumePoint) {
        if (!resumePoint) {
            return undefined;
        }
        const nextEntry = resumePoint.stack[this.deps.resumeStackPrefix.length + 1];
        if (!nextEntry || !workflowEntryMatchesWorkflow(nextEntry, childWorkflow)) {
            return undefined;
        }
        const targetStep = childWorkflow.steps.find((step) => step.name === nextEntry.step);
        return targetStep?.name;
    }
    resolveChildResumePoint(step, childWorkflow) {
        const options = this.deps.getOptions();
        const parentConfig = this.deps.getConfig();
        return trimResumePointStackForWorkflow({
            workflow: childWorkflow,
            resumePoint: options.resumePoint,
            resumeStackPrefix: [
                ...this.deps.resumeStackPrefix,
                buildWorkflowResumePointEntry(parentConfig, step.name, 'workflow_call'),
            ],
            resolveWorkflowCall: (parentWorkflow, nestedStep) => this.deps.resolveWorkflowCall({
                parentWorkflow,
                identifier: nestedStep.call,
                stepName: nestedStep.name,
                projectCwd: this.deps.projectCwd,
                lookupCwd: this.deps.getCwd(),
            }),
        });
    }
    relayChildEvents(childEngine) {
        for (const eventName of [
            'step:start',
            'step:complete',
            'step:report',
            'step:blocked',
            'step:rate_limited',
            'step:user_input',
            'phase:start',
            'phase:complete',
            'phase:judge_stage',
            'step:loop_detected',
            'step:cycle_detected',
            'iteration:limit',
        ]) {
            childEngine.on(eventName, (...args) => this.deps.emit(eventName, ...args));
        }
    }
    syncStateFromChild(step, childState) {
        if (this.deps.sharedRuntime.maxSteps !== undefined) {
            this.deps.updateMaxSteps(this.deps.sharedRuntime.maxSteps);
        }
        this.deps.state.iteration = childState.iteration;
        for (const [sessionKey, sessionId] of childState.personaSessions.entries()) {
            this.deps.state.personaSessions.set(sessionKey, sessionId);
        }
        this.deps.setActiveResumePoint(step, this.deps.state.iteration);
    }
    async execute(request) {
        const options = this.deps.getOptions();
        const parentConfig = this.deps.getConfig();
        const childResumePoint = this.resolveChildResumePoint(request.step, request.childWorkflow);
        const childEngine = this.deps.createEngine(request.childWorkflow, this.deps.getCwd(), this.deps.task, {
            ...options,
            maxStepsOverride: this.deps.sharedRuntime.maxSteps ?? this.deps.getMaxSteps(),
            initialSessions: Object.fromEntries(this.deps.state.personaSessions),
            provider: request.childProviderInfo.provider,
            model: request.childProviderInfo.model,
            providerOptions: mergeProviderOptions(request.parentProviderOptions, request.step.overrides?.providerOptions),
            personaProviders: request.personaProviders,
            startStep: this.resolveChildResumeStartStep(request.childWorkflow, childResumePoint),
            resumePoint: childResumePoint,
            initialIteration: this.deps.state.iteration,
            reportDirName: this.deps.runPaths.slug,
            runPathNamespace: this.buildWorkflowCallNamespace(request.step, request.childWorkflow),
            sharedRuntime: this.deps.sharedRuntime,
            resumeStackPrefix: [
                ...this.deps.resumeStackPrefix,
                buildWorkflowResumePointEntry(parentConfig, request.step.name, 'workflow_call'),
            ],
        });
        this.relayChildEvents(childEngine);
        const childResult = await childEngine.runWithResult();
        const childState = childResult.state;
        this.syncStateFromChild(request.step, childState);
        return {
            ...childState,
            ...(childResult.returnValue !== undefined ? { returnValue: childResult.returnValue } : {}),
            ...(childResult.abort
                ? {
                    abortKind: childResult.abort.kind,
                    abortReason: childResult.abort.reason,
                }
                : {}),
        };
    }
}
//# sourceMappingURL=WorkflowCallExecutor.js.map