deterministically execute create_skill from create_category, execute skill after creation

This commit is contained in:
Denton Social
2026-09-24 02:31:12 -05:00
parent 5bdfa1d91d
commit 300c20714b
5 changed files with 90 additions and 21 deletions
+29 -1
View File
@@ -206,4 +206,32 @@ def test_create_skill_empty_category_does_not_wedge(tmp_path):
status, detail = scheduler.submit("tell me if my package was delivered")
print(f"[{status}] {detail}")
assert scheduler.current is None
assert scheduler.current is None
def test_create_category_chain_runs_new_skill(tmp_path):
"""A request that needs a brand-new category must end with a skill run.
Deterministic chain: create_category -> create_skill in the new category ->
run that skill (the leaf answers the request, not the category stub). Slow:
uses real codegen (~7 min). Run in the background.
"""
config = load_config()
require_real(config)
config["log"] = str(tmp_path / "decisions.jsonl")
config["trace"] = str(tmp_path / "runs.jsonl")
config["category_registry"] = str(tmp_path / "categories.json")
config["skill_bodies"] = str(tmp_path / "skills")
scheduler, config = build_scheduler(config)
scheduler.tree = {}
status, detail = scheduler.submit("track my drone delivery in real time")
print(f"[{status}] {detail}")
rows = scheduler.trace.read()
kinds = [e["kind"] for e in rows]
assert "category_created" in kinds, "category stub must be authored first"
created = next(e for e in rows if e["kind"] == "skill_created")
assert created["written"] is True, "codegen must produce a runnable body"
assessed = next(e for e in rows if e["kind"] == "assessed")
assert assessed["skill"] == created["skill"], "the created skill must run"
+25 -1
View File
@@ -9,7 +9,9 @@ import pytest
from semif_agent.decisions import Request
from semif_agent.engine import EngineConfig, EngineUnavailable, SemIfEngine
from semif_agent.llm import LLMClient
from semif_agent.log import DecisionLog
from semif_agent.scheduler import Scheduler
from semif_agent.skills import (
CategoryDraft,
CategoryRegistry,
@@ -198,4 +200,26 @@ def test_navigate_empty_tree_short_circuits(tmp_path):
result = navigate(None, log, trace, Request("anything"), {})
assert isinstance(result, CreateCategory)
assert log.read() == []
assert any(e["kind"] == "create_category" for e in trace.read())
assert any(e["kind"] == "create_category" for e in trace.read())
def test_dispatch_create_category_without_engine_returns_error(tmp_path):
"""An empty tree short-circuits to CreateCategory; without an engine the
category authoring fails gracefully instead of leaving the scheduler wedged."""
log = DecisionLog(str(tmp_path / "decisions.jsonl"))
trace = TraceLog(str(tmp_path / "runs.jsonl"))
scheduler = Scheduler(
engine=SemIfEngine(EngineConfig()),
llm=LLMClient(base_url="http://localhost:1/v1", model="test"),
log=log,
config={
"skills": {},
"category_registry": str(tmp_path / "categories.json"),
"skill_bodies": str(tmp_path / "skills"),
},
trace=trace,
)
scheduler.tree = {}
result = scheduler._dispatch(Request("anything"))
assert result.kind == "error"
assert "create_category failed" in result.summary