feat: add trigger generation
ref: N25B-376
This commit is contained in:
@@ -23,6 +23,7 @@ from control_backend.schemas.program import (
|
|||||||
ProgramElement,
|
ProgramElement,
|
||||||
SemanticBelief,
|
SemanticBelief,
|
||||||
SpeechAction,
|
SpeechAction,
|
||||||
|
Trigger,
|
||||||
)
|
)
|
||||||
|
|
||||||
test_program = Program(
|
test_program = Program(
|
||||||
@@ -47,22 +48,30 @@ test_program = Program(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
triggers=[
|
triggers=[
|
||||||
# Trigger(
|
Trigger(
|
||||||
# condition=InferredBelief(
|
condition=InferredBelief(
|
||||||
# left=KeywordBelief(keyword="key"),
|
left=KeywordBelief(keyword="key"),
|
||||||
# right=InferredBelief(
|
right=InferredBelief(
|
||||||
# left=KeywordBelief(keyword="key2"),
|
left=KeywordBelief(keyword="key2"),
|
||||||
# right=SemanticBelief(
|
right=SemanticBelief(
|
||||||
# description="Decode this", name="semantic belief 2"
|
description="Decode this", name="semantic belief 2"
|
||||||
# ),
|
),
|
||||||
# operator=LogicalOperator.OR,
|
operator=LogicalOperator.OR,
|
||||||
# name="test trigger inferred inner",
|
name="test trigger inferred inner",
|
||||||
# ),
|
),
|
||||||
# operator=LogicalOperator.OR,
|
operator=LogicalOperator.OR,
|
||||||
# name="test trigger inferred outer",
|
name="test trigger inferred outer",
|
||||||
# ),
|
),
|
||||||
# plan=Plan(steps=[]),
|
plan=Plan(
|
||||||
# )
|
steps=[
|
||||||
|
SpeechAction(text="Testing trigger"),
|
||||||
|
Goal(
|
||||||
|
name="Testing trigger",
|
||||||
|
plan=Plan(steps=[LLMAction(goal="Do something")]),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
goals=[
|
goals=[
|
||||||
Goal(
|
Goal(
|
||||||
@@ -93,6 +102,10 @@ test_program = Program(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def do_things():
|
||||||
|
print(AgentSpeakGenerator().generate(test_program))
|
||||||
|
|
||||||
|
|
||||||
class AgentSpeakGenerator:
|
class AgentSpeakGenerator:
|
||||||
"""
|
"""
|
||||||
Converts Pydantic representation of behavior programs into AgentSpeak(L) code string.
|
Converts Pydantic representation of behavior programs into AgentSpeak(L) code string.
|
||||||
@@ -186,13 +199,13 @@ class AgentSpeakGenerator:
|
|||||||
for phase in program.phases:
|
for phase in program.phases:
|
||||||
previous_goal: Goal | None = None
|
previous_goal: Goal | None = None
|
||||||
for goal in phase.goals:
|
for goal in phase.goals:
|
||||||
lines += self._generate_plan_recursive(goal, phase, previous_goal)
|
lines += self._generate_goal_plan_recursive(goal, phase, previous_goal)
|
||||||
previous_goal = goal
|
previous_goal = goal
|
||||||
|
|
||||||
lines += ["", ""]
|
lines += ["", ""]
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def _generate_plan_recursive(
|
def _generate_goal_plan_recursive(
|
||||||
self, goal: Goal, phase: Phase, previous_goal: Goal | None = None
|
self, goal: Goal, phase: Phase, previous_goal: Goal | None = None
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
lines = []
|
lines = []
|
||||||
@@ -210,6 +223,11 @@ class AgentSpeakGenerator:
|
|||||||
extra_goals_to_generate = []
|
extra_goals_to_generate = []
|
||||||
|
|
||||||
steps = goal.plan.steps
|
steps = goal.plan.steps
|
||||||
|
|
||||||
|
if len(steps) == 0:
|
||||||
|
lines.append(f"{' ' * 2}<-{' ' * 2}true.")
|
||||||
|
return lines
|
||||||
|
|
||||||
first_step = steps[0]
|
first_step = steps[0]
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}"
|
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}"
|
||||||
@@ -239,7 +257,7 @@ class AgentSpeakGenerator:
|
|||||||
|
|
||||||
extra_previous_goal: Goal | None = None
|
extra_previous_goal: Goal | None = None
|
||||||
for extra_goal in extra_goals_to_generate:
|
for extra_goal in extra_goals_to_generate:
|
||||||
lines += self._generate_plan_recursive(extra_goal, phase, extra_previous_goal)
|
lines += self._generate_goal_plan_recursive(extra_goal, phase, extra_previous_goal)
|
||||||
extra_previous_goal = extra_goal
|
extra_previous_goal = extra_goal
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
@@ -248,9 +266,57 @@ class AgentSpeakGenerator:
|
|||||||
lines = []
|
lines = []
|
||||||
lines.append("// --- Triggers ---")
|
lines.append("// --- Triggers ---")
|
||||||
|
|
||||||
|
for phase in program.phases:
|
||||||
|
for trigger in phase.triggers:
|
||||||
|
lines += self._generate_trigger_plan(trigger, phase)
|
||||||
|
|
||||||
lines += ["", ""]
|
lines += ["", ""]
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
def _generate_trigger_plan(self, trigger: Trigger, phase: Phase) -> list[str]:
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
belief_name = self._slugify(trigger.condition)
|
||||||
|
|
||||||
|
lines.append(f"+{belief_name}")
|
||||||
|
lines.append(f"{' ' * 2}:{' ' * 3}phase({phase.id})")
|
||||||
|
|
||||||
|
extra_goals_to_generate = []
|
||||||
|
|
||||||
|
steps = trigger.plan.steps
|
||||||
|
|
||||||
|
if len(steps) == 0:
|
||||||
|
lines.append(f"{' ' * 2}<-{' ' * 2}true.")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
first_step = steps[0]
|
||||||
|
lines.append(
|
||||||
|
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}"
|
||||||
|
f"{'.' if len(steps) == 1 else ';'}"
|
||||||
|
)
|
||||||
|
if isinstance(first_step, Goal):
|
||||||
|
extra_goals_to_generate.append(first_step)
|
||||||
|
|
||||||
|
for step in steps[1:-1]:
|
||||||
|
lines.append(f"{' ' * 6}{self._slugify(step, include_prefix=True)};")
|
||||||
|
if isinstance(step, Goal):
|
||||||
|
extra_goals_to_generate.append(step)
|
||||||
|
|
||||||
|
if len(steps) > 1:
|
||||||
|
last_step = steps[-1]
|
||||||
|
lines.append(f"{' ' * 6}{self._slugify(last_step, include_prefix=True)}.")
|
||||||
|
if isinstance(last_step, Goal):
|
||||||
|
extra_goals_to_generate.append(last_step)
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
extra_previous_goal: Goal | None = None
|
||||||
|
for extra_goal in extra_goals_to_generate:
|
||||||
|
lines += self._generate_goal_plan_recursive(extra_goal, phase, extra_previous_goal)
|
||||||
|
extra_previous_goal = extra_goal
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
def _slugify(self, element: ProgramElement, include_prefix: bool = False) -> str:
|
def _slugify(self, element: ProgramElement, include_prefix: bool = False) -> str:
|
||||||
def base_slugify_call(text: str):
|
def base_slugify_call(text: str):
|
||||||
return slugify(text, separator="_", stopwords=["a", "the"])
|
return slugify(text, separator="_", stopwords=["a", "the"])
|
||||||
|
|||||||
Reference in New Issue
Block a user