feat(planner): persist reusable action semantics
Tests / Test passed: 879

This commit is contained in:
2026-07-15 18:14:28 +08:00
parent 361dada276
commit d69be48f96
41 changed files with 733 additions and 116 deletions
+32 -8
View File
@@ -61,18 +61,36 @@ class SkillMetadata:
class FlowStep:
tool_name: str
args: dict[str, Any] = field(default_factory=dict)
purpose: str | None = None
expected_outcome: str | None = None
def to_dict(self) -> dict[str, Any]:
return {
payload: dict[str, Any] = {
"tool_name": self.tool_name,
"args": dict(self.args),
}
if self.purpose is not None:
payload["purpose"] = self.purpose
if self.expected_outcome is not None:
payload["expected_outcome"] = self.expected_outcome
return payload
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "FlowStep":
return cls(
tool_name=str(data.get("tool_name") or data.get("action") or ""),
args=dict(data.get("args") or {}),
purpose=(
data["purpose"]
if isinstance(data.get("purpose"), str) and data["purpose"].strip()
else None
),
expected_outcome=(
data["expected_outcome"]
if isinstance(data.get("expected_outcome"), str)
and data["expected_outcome"].strip()
else None
),
)
@@ -119,8 +137,7 @@ class FlowTemplateSkill(Skill):
**self.metadata.to_dict(),
"steps": [step.to_dict() for step in self.steps],
"parameters": {
name: dict(schema)
for name, schema in self.parameters.items()
name: dict(schema) for name, schema in self.parameters.items()
},
}
@@ -128,10 +145,7 @@ class FlowTemplateSkill(Skill):
def from_dict(cls, data: dict[str, Any]) -> "FlowTemplateSkill":
return cls(
metadata=SkillMetadata.from_dict(data),
steps=[
FlowStep.from_dict(step)
for step in data.get("steps", [])
],
steps=[FlowStep.from_dict(step) for step in data.get("steps", [])],
parameters={
str(name): dict(schema)
for name, schema in (data.get("parameters") or {}).items()
@@ -189,7 +203,17 @@ class KnowledgeSkill(Skill):
def skill_embedding_text(skill: FlowTemplateSkill) -> str:
goal = skill.originating_goal or ""
return f"{skill.name}: {skill.description}\nOriginal goal: {goal}"
step_context = "\n".join(
(
f"{step.tool_name}: purpose={step.purpose}; "
f"expected_outcome={step.expected_outcome}"
)
for step in skill.steps
if step.purpose is not None or step.expected_outcome is not None
)
return f"{skill.name}: {skill.description}\nOriginal goal: {goal}" + (
f"\nAction semantics:\n{step_context}" if step_context else ""
)
def clone_skill(skill: FlowTemplateSkill) -> FlowTemplateSkill: