The Big One #43

Merged
k.marinus merged 93 commits from feat/reset-experiment-and-phase into dev 2026-01-26 19:20:45 +00:00
2 changed files with 85 additions and 23 deletions
Showing only changes of commit e704ec5ed4 - Show all commits

View File

@@ -173,12 +173,20 @@ class AgentSpeakGenerator:
Converts Pydantic representation of behavior programs into AgentSpeak(L) code string. Converts Pydantic representation of behavior programs into AgentSpeak(L) code string.
""" """
arrow_prefix = f"{' ' * 2}<-{' ' * 2}"
colon_prefix = f"{' ' * 2}:{' ' * 3}"
indent_prefix = " " * 6
def generate(self, program: Program) -> str: def generate(self, program: Program) -> str:
lines = [] lines = []
lines.append("") lines.append("")
lines += self._generate_initial_beliefs(program) lines += self._generate_initial_beliefs(program)
lines += self._generate_basic_flow(program)
lines += self._generate_phase_transitions(program)
lines += self._generate_norms(program) lines += self._generate_norms(program)
lines += self._generate_belief_inference(program) lines += self._generate_belief_inference(program)
@@ -192,10 +200,60 @@ class AgentSpeakGenerator:
def _generate_initial_beliefs(self, program: Program) -> Iterable[str]: def _generate_initial_beliefs(self, program: Program) -> Iterable[str]:
yield "// --- Initial beliefs ---" yield "// --- Initial beliefs ---"
yield f"phase({program.phases[0].id})." yield "phase(start)."
yield from ["", ""] yield from ["", ""]
def _generate_basic_flow(self, program: Program) -> Iterable[str]:
yield "// --- Basic flow ---"
for phase in program.phases:
yield from self._generate_basic_flow_per_phase(phase)
yield from ["", ""]
def _generate_basic_flow_per_phase(self, phase: Phase) -> Iterable[str]:
yield "+user_said(Message)"
yield f"{self.colon_prefix}phase({phase.id})"
goals = phase.goals
if goals:
yield f"{self.arrow_prefix}{self._slugify(goals[0], include_prefix=True)}"
for goal in goals[1:]:
yield f"{self.indent_prefix}{self._slugify(goal, include_prefix=True)}"
yield f"{self.indent_prefix if goals else self.arrow_prefix}!transition_phase."
def _generate_phase_transitions(self, program: Program) -> Iterable[str]:
yield "// --- Phase transitions ---"
if len(program.phases) == 0:
yield from ["", ""]
return
# TODO: remove outdated things
for i in range(-1, len(program.phases)):
predecessor = program.phases[i] if i >= 0 else None
successor = program.phases[i + 1] if i < len(program.phases) - 1 else None
yield from self._generate_phase_transition(predecessor, successor)
yield from self._generate_phase_transition(None, None) # to avoid failing plan
yield from ["", ""]
def _generate_phase_transition(
self, phase: Phase | None = None, next_phase: Phase | None = None
) -> Iterable[str]:
yield "+!transition_phase"
if phase is None and next_phase is None: # base case true to avoid failing plan
yield f"{self.arrow_prefix}true."
return
yield f"{self.colon_prefix}phase({phase.id if phase else 'start'})"
yield f"{self.arrow_prefix}-+phase({next_phase.id if next_phase else 'end'})."
def _generate_norms(self, program: Program) -> Iterable[str]: def _generate_norms(self, program: Program) -> Iterable[str]:
yield "// --- Norms ---" yield "// --- Norms ---"
@@ -259,46 +317,49 @@ class AgentSpeakGenerator:
yield f"+{self._slugify(goal, include_prefix=True)}" yield f"+{self._slugify(goal, include_prefix=True)}"
# Context # Context
yield f"{' ' * 2}:{' ' * 3}phase({phase.id}) &" yield f"{self.colon_prefix}phase({phase.id}) &"
yield f"{' ' * 6}not responded_this_turn &" yield f"{self.indent_prefix}not responded_this_turn &"
yield f"{' ' * 6}not achieved_{self._slugify(goal)} &" yield f"{self.indent_prefix}not achieved_{self._slugify(goal)} &"
if previous_goal: if previous_goal:
yield f"{' ' * 6}achieved_{self._slugify(previous_goal)}" yield f"{self.indent_prefix}achieved_{self._slugify(previous_goal)}"
else: else:
yield f"{' ' * 6}true" yield f"{self.indent_prefix}true"
extra_goals_to_generate = [] extra_goals_to_generate = []
steps = goal.plan.steps steps = goal.plan.steps
if len(steps) == 0: if len(steps) == 0:
yield f"{' ' * 2}<-{' ' * 2}true." yield f"{self.arrow_prefix}true."
return return
first_step = steps[0] first_step = steps[0]
yield ( yield (
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}" f"{self.arrow_prefix}{self._slugify(first_step, include_prefix=True)}"
f"{'.' if len(steps) == 1 and goal.can_fail else ';'}" f"{'.' if len(steps) == 1 and goal.can_fail else ';'}"
) )
if isinstance(first_step, Goal): if isinstance(first_step, Goal):
extra_goals_to_generate.append(first_step) extra_goals_to_generate.append(first_step)
for step in steps[1:-1]: for step in steps[1:-1]:
yield f"{' ' * 6}{self._slugify(step, include_prefix=True)};" yield f"{self.indent_prefix}{self._slugify(step, include_prefix=True)};"
if isinstance(step, Goal): if isinstance(step, Goal):
extra_goals_to_generate.append(step) extra_goals_to_generate.append(step)
if len(steps) > 1: if len(steps) > 1:
last_step = steps[-1] last_step = steps[-1]
yield ( yield (
f"{' ' * 6}{self._slugify(last_step, include_prefix=True)}" f"{self.indent_prefix}{self._slugify(last_step, include_prefix=True)}"
f"{'.' if goal.can_fail else ';'}" f"{'.' if goal.can_fail else ';'}"
) )
if isinstance(last_step, Goal): if isinstance(last_step, Goal):
extra_goals_to_generate.append(last_step) extra_goals_to_generate.append(last_step)
if not goal.can_fail: if not goal.can_fail:
yield f"{' ' * 6}+achieved_{self._slugify(goal)}." yield f"{self.indent_prefix}+achieved_{self._slugify(goal)}."
yield f"+{self._slugify(goal, include_prefix=True)}"
yield f"{self.arrow_prefix}true."
yield "" yield ""
@@ -320,32 +381,32 @@ class AgentSpeakGenerator:
belief_name = self._slugify(trigger.condition) belief_name = self._slugify(trigger.condition)
yield f"+{belief_name}" yield f"+{belief_name}"
yield f"{' ' * 2}:{' ' * 3}phase({phase.id})" yield f"{self.colon_prefix}phase({phase.id})"
extra_goals_to_generate = [] extra_goals_to_generate = []
steps = trigger.plan.steps steps = trigger.plan.steps
if len(steps) == 0: if len(steps) == 0:
yield f"{' ' * 2}<-{' ' * 2}true." yield f"{self.arrow_prefix}true."
return return
first_step = steps[0] first_step = steps[0]
yield ( yield (
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}" f"{self.arrow_prefix}{self._slugify(first_step, include_prefix=True)}"
f"{'.' if len(steps) == 1 else ';'}" f"{'.' if len(steps) == 1 else ';'}"
) )
if isinstance(first_step, Goal): if isinstance(first_step, Goal):
extra_goals_to_generate.append(first_step) extra_goals_to_generate.append(first_step)
for step in steps[1:-1]: for step in steps[1:-1]:
yield f"{' ' * 6}{self._slugify(step, include_prefix=True)};" yield f"{self.indent_prefix}{self._slugify(step, include_prefix=True)};"
if isinstance(step, Goal): if isinstance(step, Goal):
extra_goals_to_generate.append(step) extra_goals_to_generate.append(step)
if len(steps) > 1: if len(steps) > 1:
last_step = steps[-1] last_step = steps[-1]
yield f"{' ' * 6}{self._slugify(last_step, include_prefix=True)}." yield f"{self.indent_prefix}{self._slugify(last_step, include_prefix=True)}."
if isinstance(last_step, Goal): if isinstance(last_step, Goal):
extra_goals_to_generate.append(last_step) extra_goals_to_generate.append(last_step)
@@ -366,33 +427,36 @@ class AgentSpeakGenerator:
steps = goal.plan.steps steps = goal.plan.steps
if len(steps) == 0: if len(steps) == 0:
yield f"{' ' * 2}<-{' ' * 2}true." yield f"{self.arrow_prefix}true."
return return
first_step = steps[0] first_step = steps[0]
yield ( yield (
f"{' ' * 2}<-{' ' * 2}{self._slugify(first_step, include_prefix=True)}" f"{self.arrow_prefix}{self._slugify(first_step, include_prefix=True)}"
f"{'.' if len(steps) == 1 and goal.can_fail else ';'}" f"{'.' if len(steps) == 1 and goal.can_fail else ';'}"
) )
if isinstance(first_step, Goal): if isinstance(first_step, Goal):
extra_goals_to_generate.append(first_step) extra_goals_to_generate.append(first_step)
for step in steps[1:-1]: for step in steps[1:-1]:
yield f"{' ' * 6}{self._slugify(step, include_prefix=True)};" yield f"{self.indent_prefix}{self._slugify(step, include_prefix=True)};"
if isinstance(step, Goal): if isinstance(step, Goal):
extra_goals_to_generate.append(step) extra_goals_to_generate.append(step)
if len(steps) > 1: if len(steps) > 1:
last_step = steps[-1] last_step = steps[-1]
yield ( yield (
f"{' ' * 6}{self._slugify(last_step, include_prefix=True)}" f"{self.indent_prefix}{self._slugify(last_step, include_prefix=True)}"
f"{'.' if goal.can_fail else ';'}" f"{'.' if goal.can_fail else ';'}"
) )
if isinstance(last_step, Goal): if isinstance(last_step, Goal):
extra_goals_to_generate.append(last_step) extra_goals_to_generate.append(last_step)
if not goal.can_fail: if not goal.can_fail:
yield f"{' ' * 6}+achieved_{self._slugify(goal)}." yield f"{self.indent_prefix}+achieved_{self._slugify(goal)}."
yield f"+{self._slugify(goal, include_prefix=True)}"
yield f"{self.arrow_prefix}true."
yield "" yield ""

View File

@@ -90,8 +90,6 @@ class ConditionalNorm(BasicNorm):
:ivar condition: When to activate this norm. :ivar condition: When to activate this norm.
""" """
name: str = ""
id: int = -1
condition: Belief condition: Belief