Merge branch 'fix/trigger-subgoal-error' into 'main'
Allow subgoals in triggers and empty plan See merge request ics/sp/2025/n25b/pepperplus-cb!50
This commit was merged in pull request #50.
This commit is contained in:
@@ -4,6 +4,7 @@ University within the Software Project course.
|
|||||||
© Copyright Utrecht University (Department of Information and Computing Sciences)
|
© Copyright Utrecht University (Department of Information and Computing Sciences)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
from functools import singledispatchmethod
|
from functools import singledispatchmethod
|
||||||
|
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
@@ -66,6 +67,7 @@ class AgentSpeakGenerator:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
_asp: AstProgram
|
_asp: AstProgram
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def generate(self, program: Program) -> str:
|
def generate(self, program: Program) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -479,7 +481,8 @@ class AgentSpeakGenerator:
|
|||||||
:param main_goal: Whether this is a main goal (for UI notification purposes).
|
:param main_goal: Whether this is a main goal (for UI notification purposes).
|
||||||
"""
|
"""
|
||||||
context: list[AstExpression] = [self._astify(phase)]
|
context: list[AstExpression] = [self._astify(phase)]
|
||||||
context.append(~self._astify(goal, achieved=True))
|
if goal.can_fail:
|
||||||
|
context.append(~self._astify(goal, achieved=True))
|
||||||
if previous_goal and previous_goal.can_fail:
|
if previous_goal and previous_goal.can_fail:
|
||||||
context.append(self._astify(previous_goal, achieved=True))
|
context.append(self._astify(previous_goal, achieved=True))
|
||||||
if not continues_response:
|
if not continues_response:
|
||||||
@@ -503,6 +506,10 @@ class AgentSpeakGenerator:
|
|||||||
if not goal.can_fail and not continues_response:
|
if not goal.can_fail and not continues_response:
|
||||||
body.append(AstStatement(StatementType.ADD_BELIEF, self._astify(goal, achieved=True)))
|
body.append(AstStatement(StatementType.ADD_BELIEF, self._astify(goal, achieved=True)))
|
||||||
|
|
||||||
|
if len(body) == 0:
|
||||||
|
self.logger.warning("Goal with no plan detected: %s", goal.name)
|
||||||
|
body.append(AstStatement(StatementType.EMPTY, AstLiteral("true")))
|
||||||
|
|
||||||
self._asp.plans.append(AstPlan(TriggerType.ADDED_GOAL, self._astify(goal), context, body))
|
self._asp.plans.append(AstPlan(TriggerType.ADDED_GOAL, self._astify(goal), context, body))
|
||||||
|
|
||||||
self._asp.plans.append(
|
self._asp.plans.append(
|
||||||
@@ -563,10 +570,10 @@ class AgentSpeakGenerator:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
for step in trigger.plan.steps:
|
for step in trigger.plan.steps:
|
||||||
body.append(self._step_to_statement(step))
|
|
||||||
if isinstance(step, Goal):
|
if isinstance(step, Goal):
|
||||||
step.can_fail = False # triggers are continuous sequence
|
new_step = step.model_copy(update={"can_fail": False}) # triggers are sequence
|
||||||
subgoals.append(step)
|
subgoals.append(new_step)
|
||||||
|
body.append(self._step_to_statement(step))
|
||||||
|
|
||||||
# Arbitrary wait for UI to display nicely
|
# Arbitrary wait for UI to display nicely
|
||||||
body.append(
|
body.append(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ University within the Software Project course.
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from pydantic import UUID4, BaseModel
|
from pydantic import UUID4, BaseModel, field_validator
|
||||||
|
|
||||||
|
|
||||||
class ProgramElement(BaseModel):
|
class ProgramElement(BaseModel):
|
||||||
@@ -24,6 +24,13 @@ class ProgramElement(BaseModel):
|
|||||||
# To make program elements hashable
|
# To make program elements hashable
|
||||||
model_config = {"frozen": True}
|
model_config = {"frozen": True}
|
||||||
|
|
||||||
|
@field_validator("name")
|
||||||
|
@classmethod
|
||||||
|
def name_must_not_start_with_number(cls, v: str) -> str:
|
||||||
|
if v and v[0].isdigit():
|
||||||
|
raise ValueError('Field "name" must not start with a number.')
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class LogicalOperator(Enum):
|
class LogicalOperator(Enum):
|
||||||
"""
|
"""
|
||||||
@@ -105,6 +112,7 @@ class InferredBelief(ProgramElement):
|
|||||||
left: Belief
|
left: Belief
|
||||||
right: Belief
|
right: Belief
|
||||||
|
|
||||||
|
|
||||||
class EmotionBelief(ProgramElement):
|
class EmotionBelief(ProgramElement):
|
||||||
"""
|
"""
|
||||||
Represents a belief that is set when a certain emotion is detected.
|
Represents a belief that is set when a certain emotion is detected.
|
||||||
@@ -115,6 +123,7 @@ class EmotionBelief(ProgramElement):
|
|||||||
name: str = ""
|
name: str = ""
|
||||||
emotion: str
|
emotion: str
|
||||||
|
|
||||||
|
|
||||||
class Norm(ProgramElement):
|
class Norm(ProgramElement):
|
||||||
"""
|
"""
|
||||||
Base class for behavioral norms that guide the robot's interactions.
|
Base class for behavioral norms that guide the robot's interactions.
|
||||||
|
|||||||
Reference in New Issue
Block a user