export type Plan = { name: string, id: string, steps: PlanElement[], } export type PlanElement = Goal | Action export type PlanElementTypes = ActionTypes | "goal" export type Goal = { id: string, name: string, plan: Plan, can_fail: boolean, type: "goal" } // Actions export type Action = SpeechAction | GestureAction | LLMAction export type SpeechAction = { id: string, text: string, type:"speech" } export type GestureAction = { id: string, gesture: string, isTag: boolean, type:"gesture" } export type LLMAction = { id: string, goal: string, type:"llm" } export type ActionTypes = "speech" | "gesture" | "llm" // Extract the wanted information from a plan within the reducing of nodes export function PlanReduce(plan?: Plan) { if (!plan) return "" return { name: plan.name, id: plan.id, steps: plan.steps.map((x) => StepReduce(x)) } } // Extract the wanted information from a plan element. function StepReduce(planElement: PlanElement) { // We have different types of plan elements, requiring differnt types of output switch (planElement.type) { case ("speech"): return { id: planElement.id, text: planElement.text, } case ("gesture"): return { id: planElement.id, gesture: { type: planElement.isTag ? "tag" : "single", name: planElement.gesture }, } case ("llm"): return { id: planElement.id, goal: planElement.goal, } case ("goal"): return { id: planElement.id, plan: planElement.plan, can_fail: planElement.can_fail, }; default: } } /** * Finds out whether the plan can iterate multiple times, or always stops after one action. * This comes down to checking if the plan only has speech/ gesture actions, or others as well. * @param plan: the plan to check * @returns: a boolean */ export function DoesPlanIterate(plan?: Plan) : boolean { // TODO: should recursively check plans that have goals (and thus more plans) in them. if (!plan) return false return plan.steps.filter((step) => step.type == "llm").length > 0 || (plan.steps.filter((x) => x.type == "goal").map((x) => DoesPlanIterate(x.plan))).includes(true); } /** * Returns the value of the action. * Since typescript can't polymorphicly access the value field, * we need to switch over the types and return the correct field. * @param action: action to retrieve the value from * @returns string | undefined */ export function GetActionValue(action: Action) { let returnAction; switch (action.type) { case "gesture": returnAction = action as GestureAction return returnAction.gesture; case "speech": returnAction = action as SpeechAction return returnAction.text; case "llm": returnAction = action as LLMAction return returnAction.goal; default: } }