SkillWiki / skillwiki /tests /test_skill_runtime_phase4.py
Apollo-universe
HF Spaces deploy: initial orphan branch (no binary history)
a9df8b1
Raw
History Blame Contribute Delete
7 kB
from __future__ import annotations
import json
from types import SimpleNamespace
from skillos.layers.skill_runtime.reflection import ReflectionAgent, _REFLECT_PROMPT
from skillos.layers.skill_runtime.verifier import (
VerificationResult,
VerifierAgent,
_VERIFY_PROMPT,
)
from skillos.models.maintenance_model import (
MaintenanceRecommendedAction,
MaintenanceTrigger,
)
def test_runtime_verifier_and_reflection_prompts_are_ascii():
_VERIFY_PROMPT.encode("ascii")
_REFLECT_PROMPT.encode("ascii")
def test_verifier_normalizes_llm_output():
payload = {
"passed": True,
"score": 2.5,
"issues": "bad shape",
"suggestions": ["keep going", None],
"reasoning": "looks okay",
}
verifier = VerifierAgent(FakeLLM(json.dumps(payload)))
result = verifier.verify("finish task", {"ok": True})
assert result.passed is True
assert result.score == 1.0
assert result.issues == []
assert result.suggestions == ["keep going"]
assert result.details["reasoning"] == "looks okay"
def test_verifier_fallback_detects_failure_output():
verifier = VerifierAgent(FakeLLM("not json"))
result = verifier.verify(
"finish task",
{"success": False, "error": "step failed"},
"step failed with timeout",
)
assert result.passed is False
assert result.score == 0.2
assert result.issues
assert result.suggestions
def test_verifier_fallback_passes_non_empty_output_without_failure_evidence():
verifier = VerifierAgent(FakeLLM("not json"))
result = verifier.verify("finish task", {"result": "done"}, "all steps completed")
assert result.passed is True
assert result.score == 0.65
assert result.issues == []
def test_reflection_normalizes_d_compatible_proposals():
payload = {
"root_cause": "timeout",
"failed_skill_ids": ["skill_a", None],
"improvement_suggestions": ["repair prompt", ""],
"skill_update_proposals": [
{
"skill_id": "skill_a",
"issue": "timeout",
"proposed_fix": "add timeout handling",
"recommended_action": "unknown",
"evidence": ["step failed", None],
"targets_to_fix": ["timeout branch"],
"invariants_to_preserve": ["successful retry behavior"],
"validation_plan": ["replay failed task", ""],
},
"bad",
{"skill_id": "", "recommended_action": "repair"},
],
"experience_summary": "timeout during execution",
}
reflector = ReflectionAgent(FakeLLM(json.dumps(payload)))
verification = VerificationResult(
passed=False,
score=0.2,
goal="finish task",
issues=["timeout"],
)
feedback = reflector.reflect("task-1", "finish task", {}, verification)
assert feedback.success is False
assert feedback.failed_skill_ids == ["skill_a"]
assert feedback.improvement_suggestions == ["repair prompt"]
assert feedback.skill_update_proposals == [
{
"skill_id": "skill_a",
"issue": "timeout",
"proposed_fix": "add timeout handling",
"recommended_action": "review",
"evidence": ["step failed"],
"targets_to_fix": ["timeout branch"],
"invariants_to_preserve": ["successful retry behavior"],
"validation_plan": ["replay failed task"],
}
]
def test_reflection_fallback_generates_repair_proposal_for_failed_skill():
reflector = ReflectionAgent(FakeLLM("not json"))
verification = VerificationResult(
passed=False,
score=0.2,
goal="finish task",
issues=["Execution trace contains skipped steps."],
suggestions=["Repair the failed skill."],
)
trace = {
"steps": [
{
"skill_id": "skill_a",
"status": "failed",
"error": "Skill code raised RuntimeError",
}
]
}
feedback = reflector.reflect("task-1", "finish task", trace, verification)
assert feedback.success is False
assert feedback.failed_skill_ids == ["skill_a"]
assert feedback.skill_update_proposals[0]["skill_id"] == "skill_a"
assert feedback.skill_update_proposals[0]["recommended_action"] == "repair"
assert feedback.skill_update_proposals[0]["evidence"]
proposals = feedback.to_maintenance_proposals()
assert len(proposals) == 1
assert proposals[0].skill_id == "skill_a"
assert proposals[0].trigger == MaintenanceTrigger.RUNTIME_FAILURE
assert proposals[0].recommended_action == MaintenanceRecommendedAction.REPAIR
assert proposals[0].root_cause == "Execution trace contains skipped steps."
assert proposals[0].feedback_sources == ["runtime_reflection"]
assert proposals[0].targets_to_fix == ["Execution trace contains skipped steps."]
assert proposals[0].invariants_to_preserve
assert proposals[0].validation_plan
assert proposals[0].requires_human_review is True
def test_reflection_fallback_uses_trace_skill_ids_for_verifier_failure():
reflector = ReflectionAgent(FakeLLM("not json"))
verification = VerificationResult(
passed=False,
score=0.0,
goal="submit form",
issues=["Path not found: output.final_state.submitted"],
suggestions=["Repair the postcondition mapping."],
)
trace = {
"steps": [
{
"skill_id": "skill_submit_form",
"status": "success",
"outputs": {"success": True},
}
]
}
feedback = reflector.reflect("task-verify", "submit form", trace, verification)
assert feedback.success is False
assert feedback.failed_skill_ids == ["skill_submit_form"]
assert feedback.skill_update_proposals == [
{
"skill_id": "skill_submit_form",
"issue": "Path not found: output.final_state.submitted",
"proposed_fix": (
"Review runtime failure and repair the skill implementation or prompt."
),
"recommended_action": "repair",
"evidence": ["Path not found: output.final_state.submitted"],
}
]
def test_reflection_fallback_success_does_not_generate_repair_proposal():
reflector = ReflectionAgent(FakeLLM("not json"))
verification = VerificationResult(
passed=True,
score=0.8,
goal="finish task",
)
feedback = reflector.reflect("task-1", "finish task", {"result": "done"}, verification)
assert feedback.success is True
assert feedback.skill_update_proposals == []
assert feedback.experience_summary == "Task completed successfully."
class FakeLLM:
def __init__(self, content: str) -> None:
self.content = content
def chat(self, messages: object) -> SimpleNamespace:
return SimpleNamespace(content=self.content)