// Vendored from packages/runtime/src/plan.ts. // Sole change: import Skill/Action from local ./skill.ts instead of @meeseeks/schema. import type { Action, Skill } from "./skill.ts"; import { findPlaceholders, substitute, substituteWithReport } from "./substitute.ts"; export interface StepPlan { id: string; action: Action; instruction: string; target: { description: string; bbox?: [number, number, number, number]; ax_role?: string; ax_name?: string; }; successCheck: string; fallback?: string; } export interface ExecutionPlan { skill_name: string; intent: string; domain: string; inputs: Record; steps: StepPlan[]; unbound_placeholders: string[]; } export function planSkill( skill: Skill, inputs: Record = {}, ): ExecutionPlan { const unbound = new Set(); const collect = (s: string) => { for (const ph of findPlaceholders(s)) { const key = ph.slice(2, -2); if (inputs[key] === undefined && inputs[key.toLowerCase()] === undefined) { unbound.add(ph); } } }; for (const ph of skill.meta.placeholders) { const key = ph.slice(2, -2); if (inputs[key] === undefined && inputs[key.toLowerCase()] === undefined) { unbound.add(ph); } } const steps: StepPlan[] = skill.steps.map((s) => { collect(s.instruction); collect(s.target.description); collect(s.successCheck); if (s.fallback) collect(s.fallback); const target: StepPlan["target"] = { description: substitute(s.target.description, inputs), }; if (s.target.bbox) target.bbox = s.target.bbox; if (s.target.ax_role) target.ax_role = s.target.ax_role; if (s.target.ax_name) target.ax_name = s.target.ax_name; const step: StepPlan = { id: s.id, action: s.action, instruction: substitute(s.instruction, inputs), target, successCheck: substitute(s.successCheck, inputs), }; if (s.fallback) step.fallback = substitute(s.fallback, inputs); return step; }); return { skill_name: skill.name, intent: substitute(skill.intent, inputs), domain: skill.meta.domain, inputs, steps, unbound_placeholders: [...unbound].sort(), }; } export { substitute, substituteWithReport, findPlaceholders };