/**
 * ============================================================
 *  plugins/workflow-runner/src/stepExecutors/agent.ts —— agent step 执行
 * ------------------------------------------------------------
 *  「受工作流指导的 TAOR」一等公民。作者在 yaml 里 inline 描述一步开放任务
 *  （agent: "..."），本执行器起一个**有界 TAOR agent**（miniReAct）随机应变完成：
 *  思考 → 用工具 → 观察 → 反思 → 再来，直到把这一步要的结果做出来。
 *
 *  与 skill: 节点的分工：
 *    - skill: 跑一个**外部 SKILL.md 定义的、可复用的**完整 agent（runQuery，maxTurns 50，流式）
 *    - agent: 跑一个**inline 描述的、一次性的**有界 agent（miniReAct，白名单工具 + output_schema
 *             + 验证闸门），轻、收敛快、产出受验证
 *
 *  与 onError:'recover' 共享 agentCommon 的系统提示词纪律与验证闸门——同一个脑子。
 *
 *  失败语义：agent 放弃 / 空产出 → interpretMiniReActResult 判 ok:false → 本执行器 throw，
 *  走 dispatchActionStep 的正常失败路径，由 step.onError 接管（halt/continue/recover）。
 *  —— 与其它动作 step 完全一致：agent 节点自己也能声明 onError:'recover' 被再救一次。
 *
 *  流式：execAgentStep 是 AsyncGenerator，`yield* runMiniReAct(...)` 把子 agent 的
 *  text / reasoning / tool_start / tool_end 事件透传到 runWorkflow → UI，内层思考实时可见。
 * ============================================================
 */
import { ALL_TOOLS } from '../../../../src/plugin-sdk.js';
import { buildWorkflowAgentSystem, describeCaptureContract, interpretMiniReActResult, } from '../agentCommon.js';
import { interpolate } from '../expressions.js';
import { runMiniReAct } from '../miniReAct.js';
const AGENT_OPENING = `你是一名资深工程师。一个工作流把其中**一步开放任务**交给你自主完成。
你受工作流的总目标与已知上下文指导，但具体怎么做由你用工具随机应变决定——把这一步要的结果真正做出来。`;
const AGENT_NODE_SYSTEM = buildWorkflowAgentSystem(AGENT_OPENING);
export async function* execAgentStep(step, vars, ctx) {
    if (typeof step.agent !== 'string') {
        throw new Error(`step ${step.id}: 缺少 agent 字段`);
    }
    const task = interpolate(step.agent, vars);
    const goalLine = ctx.goal ? `工作流总目标：${ctx.goal}\n\n` : '';
    const captureLine = describeCaptureContract(step);
    // 可选 context_files：列出 path + hint，让 agent 用 Read 按需取（不 inline 内容）。
    let filesLine = '';
    if (step.context_files && step.context_files.length > 0) {
        const list = step.context_files
            .map((f) => `- ${interpolate(f.path, vars)}${f.hint ? ` — ${f.hint}` : ''}`)
            .join('\n');
        filesLine = `\n\n以下文件可用，按需用 Read 读取：\n${list}`;
    }
    const userMsg = `${goalLine}` +
        `你这一步要完成的任务：\n${task}` +
        `${filesLine}${captureLine}\n\n` +
        `请用工具把它做出来；确实做不成就按约定输出放弃标记。`;
    // 工具集：默认全量 ALL_TOOLS（真 agency）；step.allowed_tools 收窄。
    const allowed = step.allowed_tools;
    const tools = allowed && allowed.length > 0
        ? ALL_TOOLS.filter((t) => allowed.includes(t.name))
        : ALL_TOOLS;
    const result = yield* runMiniReAct({
        messages: [
            { role: 'system', content: AGENT_NODE_SYSTEM },
            { role: 'user', content: userMsg },
        ],
        tools,
        output_schema: step.output_schema,
        provider: ctx.provider,
        signal: ctx.signal,
        maxTurns: step.maxTurns ?? 12,
    });
    const outcome = interpretMiniReActResult(result, step.output_schema !== undefined);
    if (!outcome.ok) {
        // 放弃 / 空产出 → 抛错，交给 dispatchActionStep 的失败路径 + step.onError 处置。
        throw new Error(`agent 未完成任务：${outcome.reason}`);
    }
    return outcome.value;
}
