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
+44 -5
View File
@@ -1,6 +1,11 @@
from __future__ import annotations
from skills_learning.models import FlowStep, FlowTemplateSkill, SkillMetadata
from skills_learning.models import (
FlowStep,
FlowTemplateSkill,
SkillMetadata,
skill_embedding_text,
)
from skills_learning.store import SkillStore
from skills_learning.synthesis import extract_tool_calls, synthesize_flow_skill
@@ -10,12 +15,19 @@ def _record(
args: dict[str, object] | None = None,
*,
result: dict[str, object] | None = None,
purpose: str | None = None,
expected_outcome: str | None = None,
) -> dict[str, object]:
tool_call: dict[str, object] = {
"action": action,
"args": args or {},
}
if purpose is not None:
tool_call["purpose"] = purpose
if expected_outcome is not None:
tool_call["expected_outcome"] = expected_outcome
return {
"tool_call": {
"action": action,
"args": args or {},
},
"tool_call": tool_call,
"result": result or {},
}
@@ -50,6 +62,33 @@ def test_first_time_synthesis_has_literal_steps_and_no_parameters() -> None:
assert skill.parameters == {}
def test_synthesis_preserves_action_metadata_for_reuse_and_embedding() -> None:
skill = synthesize_flow_skill(
"open settings",
[
_record(
"tap",
{"x": 12, "y": 34},
purpose="Open the settings tab.",
expected_outcome="The settings page is visible.",
)
],
)
assert skill.steps == [
FlowStep(
"tap",
{"x": 12, "y": 34},
purpose="Open the settings tab.",
expected_outcome="The settings page is visible.",
)
]
assert FlowStep.from_dict(skill.steps[0].to_dict()) == skill.steps[0]
embedding_text = skill_embedding_text(skill)
assert "Open the settings tab." in embedding_text
assert "The settings page is visible." in embedding_text
def test_second_execution_promotes_differing_argument_to_parameter() -> None:
store = SkillStore()
store.create_version(