Spaces:
Running on Zero
Running on Zero
| from pathlib import Path | |
| from tests.helpers import load_test_index | |
| from hackathon_advisor.agent import AdvisorEngine | |
| from hackathon_advisor.data import ProjectIndex | |
| from hackathon_advisor.tool_contracts import ToolCall, ToolResolution | |
| class StaticPlanner: | |
| backend = "test" | |
| model_id = "static" | |
| def __init__(self, call: ToolCall) -> None: | |
| self.call = call | |
| def plan(self, message: str, state: dict) -> ToolResolution: | |
| return ToolResolution(status="valid", call=self.call, errors=()) | |
| def test_agent_scores_and_persists_idea() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| result = engine.turn("A local-first archive cartographer for family photos", {}) | |
| assert result.score is not None | |
| assert result.state["ideas"] | |
| assert result.state["ideas"][0]["score"] is not None | |
| assert "goal_fit" in result.state["ideas"][0]["score"] | |
| assert "prize_fit" not in result.state["ideas"][0]["score"] | |
| assert "goal_fit" in result.artifact["seal"] | |
| assert "prize_fit" not in result.artifact["seal"] | |
| assert result.state["trace"] | |
| assert result.state["last_tool_resolution"]["call"]["name"] == "save_idea" | |
| assert result.state["trace"][0]["tool_resolution"]["call"]["name"] == "save_idea" | |
| assert result.state["last_artifact"]["title"] == result.artifact["title"] | |
| assert result.state["ideas"][0]["artifact"]["title"] == result.artifact["title"] | |
| assert result.artifact["wood_map"]["caption"] | |
| assert {dot["kind"] for dot in result.artifact["wood_map"]["dots"]} >= {"idea", "echo", "inked"} | |
| assert result.score.to_dict()["echoes"][0]["page_number"] >= 1 | |
| assert "page " in result.response | |
| assert result.response | |
| def test_agent_finds_whitespace() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| result = engine.turn("write bolder and find whitespace", {}) | |
| assert result.whitespace | |
| assert result.score is not None | |
| assert result.artifact["verdict"] == "UNWRITTEN" | |
| assert result.state["ideas"][0]["title"] == result.whitespace[0].label | |
| def test_gap_command_explores_unused_whitespace() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("write bolder and find whitespace", {}) | |
| second = engine.turn("write bolder and find whitespace", first.state) | |
| assert len(second.state["ideas"]) == 2 | |
| assert first.whitespace[0].label != second.whitespace[0].label | |
| assert second.state["ideas"][-1]["title"] == second.whitespace[0].label | |
| assert second.state["current_whitespace"]["label"] == second.whitespace[0].label | |
| def test_agent_preserves_canonical_jargon_case() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| result = engine.turn("use neutron and mini cpm on zero gpu", {}) | |
| assert "MiniCPM5" in result.artifact["title"] | |
| assert "ZeroGPU" in result.artifact["title"] | |
| def test_plan_command_uses_current_idea() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("A local-first archive cartographer for family photos", {}) | |
| planned = engine.turn("make a build plan", first.state) | |
| assert planned.plan | |
| assert planned.artifact["title"] == first.artifact["title"] | |
| assert planned.state["ideas"][0]["title"] == first.artifact["title"] | |
| assert all("Record the trace" not in step for step in planned.plan) | |
| assert all("session trace" not in step for step in planned.plan) | |
| def test_non_plan_turns_clear_stale_build_plan() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("A local-first archive cartographer for family photos", {}) | |
| planned = engine.turn("make a build plan", first.state) | |
| project = engine.turn("read project lolaby", planned.state) | |
| second = engine.turn("A hands-on science coach for kitchen experiments", planned.state) | |
| assert planned.state["last_plan"] | |
| assert "last_plan" not in project.state | |
| assert "last_plan" not in second.state | |
| def test_plan_and_rank_do_not_create_placeholder_ideas() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| planned = engine.turn("make a build plan", {}) | |
| ranked = engine.turn("compare ideas", planned.state) | |
| assert planned.state["ideas"] == [] | |
| assert ranked.state["ideas"] == [] | |
| assert "Write one project instinct first" in planned.response | |
| assert "No idea pages" in ranked.response | |
| assert planned.tool_events[0].name == "make_plan" | |
| assert ranked.tool_events[0].name == "compare_ideas" | |
| def test_plan_uses_profile_context() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| state = { | |
| "profile": { | |
| "skills": "frontend prototyping", | |
| "time": "one evening", | |
| "preferences": "quiet dashboards", | |
| "constraints": "CPU-only Space", | |
| } | |
| } | |
| first = engine.turn("A local-first archive cartographer for family photos", state) | |
| planned = engine.turn("make a build plan", first.state) | |
| assert any("one evening" in step for step in planned.plan) | |
| assert any("frontend prototyping" in step for step in planned.plan) | |
| assert any("CPU-only Space" in step for step in planned.plan) | |
| assert any("quiet dashboards" in step for step in planned.plan) | |
| def test_distinct_idea_turns_append_to_board() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("A local-first archive cartographer for family photos", {}) | |
| second = engine.turn("write bolder and find whitespace", first.state) | |
| assert len(second.state["ideas"]) == 2 | |
| assert second.state["ideas"][0]["title"] == first.artifact["title"] | |
| assert second.state["ideas"][1]["title"] == second.artifact["title"] | |
| assert second.state["ideas"][0]["artifact"]["title"] == first.artifact["title"] | |
| assert second.state["ideas"][1]["artifact"]["title"] == second.artifact["title"] | |
| def test_compare_ideas_reranks_board_and_selects_winner() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("A local-first archive cartographer for family photos", {}) | |
| second = engine.turn("write bolder and find whitespace", first.state) | |
| ranked = engine.turn("compare ideas", second.state) | |
| assert ranked.score is not None | |
| assert ranked.artifact["title"] == ranked.state["ideas"][0]["title"] | |
| assert ranked.state["current_idea_id"] == ranked.state["ideas"][0]["id"] | |
| assert ranked.state["ideas"][0]["score"]["overall"] >= ranked.state["ideas"][1]["score"]["overall"] | |
| assert all(idea["artifact"]["title"] == idea["title"] for idea in ranked.state["ideas"]) | |
| assert ranked.plan | |
| assert "Ranked pages:" in ranked.response | |
| assert ranked.tool_events[0].name == "compare_ideas" | |
| def test_plan_preserves_unwritten_whitespace_verdict() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| whitespace = engine.turn("write bolder and find whitespace", {}) | |
| planned = engine.turn("make a build plan", whitespace.state) | |
| assert whitespace.artifact["verdict"] == "UNWRITTEN" | |
| assert planned.artifact["title"] == whitespace.artifact["title"] | |
| assert planned.artifact["verdict"] == "UNWRITTEN" | |
| def test_planner_get_project_drives_project_response() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index, planner=StaticPlanner(ToolCall("get_project", {"id": "lolaby"}))) | |
| result = engine.turn("read lolaby", {}) | |
| assert result.projects | |
| assert result.projects[0].slug == "lolaby" | |
| assert result.tool_events[0].name == "get_project" | |
| def test_rule_project_reference_does_not_create_or_score_idea() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| first = engine.turn("A local-first archive cartographer for family photos", {}) | |
| result = engine.turn("read project lolaby", first.state) | |
| assert result.projects | |
| assert result.projects[0].slug == "lolaby" | |
| assert result.score is None | |
| assert result.artifact == {} | |
| assert len(result.state["ideas"]) == 1 | |
| assert result.state["ideas"][0]["title"] == first.artifact["title"] | |
| assert result.state["last_artifact"]["title"] == first.artifact["title"] | |
| assert result.state["last_tool_resolution"]["call"]["name"] == "get_project" | |
| def test_planner_profile_and_goals_update_state() -> None: | |
| index = load_test_index() | |
| planned = AdvisorEngine(index).turn("A local-first archive cartographer for family photos", {}) | |
| planned = AdvisorEngine(index).turn("make a build plan", planned.state) | |
| assert planned.state["last_plan"] | |
| profile_engine = AdvisorEngine( | |
| index, | |
| planner=StaticPlanner(ToolCall("update_profile", {"field": "skills", "value": "frontend"})), | |
| ) | |
| profile = profile_engine.turn("remember this", planned.state) | |
| target_engine = AdvisorEngine( | |
| index, | |
| planner=StaticPlanner(ToolCall("set_goals", {"goals": ["Off the Grid", "Field Notes"]})), | |
| ) | |
| targeted = target_engine.turn("set goals", profile.state) | |
| assert targeted.state["profile"]["skills"] == "frontend" | |
| assert targeted.state["goals"] == ["Off the Grid", "Field Notes"] | |
| assert "last_plan" not in profile.state | |
| assert "last_plan" not in targeted.state | |
| assert "Local-first, Build notes" in targeted.response | |
| def test_goal_update_invalidates_current_idea_artifact() -> None: | |
| index = load_test_index() | |
| first = AdvisorEngine(index).turn("A local-first archive cartographer for family photos", {}) | |
| first = AdvisorEngine(index).turn("make a build plan", first.state) | |
| assert first.state["last_plan"] | |
| target_engine = AdvisorEngine( | |
| index, | |
| planner=StaticPlanner(ToolCall("set_goals", {"goals": ["Field Notes"]})), | |
| ) | |
| targeted = target_engine.turn("set goals", first.state) | |
| idea = targeted.state["ideas"][0] | |
| assert idea["score"] is None | |
| assert idea["artifact"] is None | |
| assert "last_artifact" not in targeted.state | |
| assert "last_plan" not in targeted.state | |
| def test_session_goals_apply_to_new_and_current_ideas() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| state = {"goals": ["Field Notes"]} | |
| first = engine.turn("A local-first archive cartographer for family photos", state) | |
| first_idea = first.state["ideas"][0] | |
| planned = engine.turn("make a build plan", first.state) | |
| assert first_idea["goals"] == ["Field Notes"] | |
| assert all("LoRA" not in step for step in planned.plan) | |
| def test_well_tuned_goal_adds_training_step_to_plan() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| state = {"goals": ["Well-Tuned"]} | |
| first = engine.turn("A local-first archive cartographer for family photos", state) | |
| planned = engine.turn("make a build plan", first.state) | |
| assert first.state["ideas"][0]["goals"] == ["Well-Tuned"] | |
| assert any("LoRA" in step for step in planned.plan) | |
| assert all("advisor turns" not in step for step in planned.plan) | |
| def test_planner_score_idea_scores_current_idea() -> None: | |
| index = load_test_index() | |
| first = AdvisorEngine(index).turn("A local-first archive cartographer for family photos", {}) | |
| engine = AdvisorEngine(index, planner=StaticPlanner(ToolCall("score_idea", {}))) | |
| scored = engine.turn("score it", first.state) | |
| assert scored.score is not None | |
| assert scored.artifact["title"] == first.artifact["title"] | |
| def test_turn_stream_emits_ordered_progress_events() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index) | |
| events = list(engine.turn_stream("A local-first archive cartographer for family photos", {})) | |
| types = [event["type"] for event in events] | |
| assert types[0] == "start" | |
| assert types[-1] == "done" | |
| assert "token" in types | |
| # the planning stage is announced before any tool runs, and tools stream as they execute | |
| assert types.index("stage") < types.index("tool_event") | |
| tool_events = [event for event in events if event["type"] == "tool_event"] | |
| assert [event["name"] for event in tool_events] == ["save_idea", "search_projects", "score_idea"] | |
| assert events[-1]["state"]["ideas"] | |
| def test_turn_stream_done_matches_blocking_turn() -> None: | |
| # idea ids are randomly generated, so compare the deterministic surface of the turn. | |
| index = load_test_index() | |
| streamed = list(AdvisorEngine(index).turn_stream("write bolder and find whitespace", {})) | |
| done = next(event for event in streamed if event["type"] == "done") | |
| blocking = AdvisorEngine(index).turn("write bolder and find whitespace", {}) | |
| assert done["response"] == blocking.response | |
| assert done["score"] == (blocking.score.to_dict() if blocking.score else None) | |
| assert done["plan"] == blocking.plan | |
| assert [item["label"] for item in done["whitespace"]] == [ | |
| item.label for item in blocking.whitespace | |
| ] | |
| assert [idea["title"] for idea in done["state"]["ideas"]] == [ | |
| idea["title"] for idea in blocking.state["ideas"] | |
| ] | |
| def test_turn_accepts_injected_resolution() -> None: | |
| index = load_test_index() | |
| engine = AdvisorEngine(index, planner=StaticPlanner(ToolCall("score_idea", {}))) | |
| injected = ToolResolution(status="valid", call=ToolCall("list_projects", {"sort": "likes"}), errors=()) | |
| result = engine.turn("score it", {}, resolution=injected) | |
| # the injected list_projects call wins over the planner's score_idea call | |
| assert result.state["last_tool_resolution"]["call"]["name"] == "list_projects" | |