73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from skills_learning.models import FlowStep, FlowTemplateSkill
|
|
from skills_learning.store import SkillStore
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class VersionDiff:
|
|
structural_divergence: bool
|
|
stored_sequence: list[str]
|
|
executed_sequence: list[str]
|
|
argument_differences: list[tuple[int, str, Any, Any]]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class VersioningResult:
|
|
skill: FlowTemplateSkill
|
|
created_new_version: bool
|
|
|
|
|
|
def diff_flow_versions(
|
|
stored_steps: list[FlowStep],
|
|
executed_steps: list[FlowStep],
|
|
) -> VersionDiff:
|
|
stored_sequence = [step.tool_name for step in stored_steps]
|
|
executed_sequence = [step.tool_name for step in executed_steps]
|
|
structural = stored_sequence != executed_sequence
|
|
differences: list[tuple[int, str, Any, Any]] = []
|
|
if not structural:
|
|
for index, (stored_step, executed_step) in enumerate(
|
|
zip(stored_steps, executed_steps, strict=True)
|
|
):
|
|
keys = set(stored_step.args) | set(executed_step.args)
|
|
for key in sorted(keys):
|
|
stored_value = stored_step.args.get(key)
|
|
executed_value = executed_step.args.get(key)
|
|
if stored_value != executed_value:
|
|
differences.append((index, key, stored_value, executed_value))
|
|
return VersionDiff(
|
|
structural_divergence=structural,
|
|
stored_sequence=stored_sequence,
|
|
executed_sequence=executed_sequence,
|
|
argument_differences=differences,
|
|
)
|
|
|
|
|
|
def store_synthesized_skill(
|
|
store: SkillStore,
|
|
candidate: FlowTemplateSkill,
|
|
) -> VersioningResult:
|
|
latest = store.get_latest_by_name(candidate.name)
|
|
if latest is None:
|
|
return VersioningResult(store.create_version(candidate), True)
|
|
|
|
diff = diff_flow_versions(latest.steps, candidate.steps)
|
|
if diff.structural_divergence:
|
|
return VersioningResult(store.create_version(candidate, parent=latest), True)
|
|
|
|
merged_parameters = {
|
|
**latest.parameters,
|
|
**candidate.parameters,
|
|
}
|
|
updated = latest.with_updates(
|
|
steps=candidate.steps,
|
|
parameters=merged_parameters,
|
|
description=candidate.description,
|
|
originating_goal=candidate.originating_goal,
|
|
)
|
|
return VersioningResult(store.update_skill(updated), False)
|