muse-agent-example/tests/e2e/test_compounding.py

139 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""P1:lesson 证据强制、升格 merge、回放与生产 flow 同一入口、web 写面闭集。"""
from __future__ import annotations
import inspect
import json
import os
import pathlib
import sqlite3
import sys
import tempfile
import unittest
ROOT = next(
parent
for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents)
if (parent / "AGENTS.md").is_file() and (parent / ".git").exists()
)
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from unittest import mock
from muse import replay as replay_mod # noqa: E402
from muse.flow import dispatch as dispatch_mod # noqa: E402
from muse.flow.adopt import adopt_candidate # noqa: E402
from muse.store import ( # noqa: E402
add_review,
approve_and_merge_lesson,
connect,
register_lesson,
)
from web import app as webapp # noqa: E402
class CompoundingTest(unittest.TestCase):
def setUp(self) -> None:
self.tmp = pathlib.Path(tempfile.mkdtemp())
self.db = self.tmp / "muse.db"
with connect(self.db) as conn:
conn.execute(
"""INSERT INTO runs(id, created_at, kind, input_json, output_text, meta_json, skill_set_hash)
VALUES ('run-p1', datetime('now'), 'agent.writer', '{"k":1}', '旧稿', '{}', 'hash')"""
)
conn.commit()
self.review_id = add_review(
run_id="run-p1",
target="candidate",
action="revise",
reviewer="qingse",
reason="改钩子",
before_text="旧稿",
after_text="新稿",
path=self.db,
)
def test_empty_evidence_ids_are_rejected_by_python_and_db(self) -> None:
with self.assertRaises(ValueError):
register_lesson(
lesson_id="bad",
source_run_ids=[],
source_review_ids=[str(self.review_id)],
kind="craft",
title="空证据",
content="x",
target_ref="打磨小说语言",
lessons_dir=self.tmp / "lessons",
path=self.db,
)
with connect(self.db) as conn:
with self.assertRaises(sqlite3.IntegrityError):
conn.execute(
"""INSERT INTO lessons(id, source_run_ids, source_review_ids, kind, title, content_path, status)
VALUES ('bad2', '[]', '[]', 'craft', 'x', 'p.md', 'proposed')"""
)
def test_lesson_merges_into_skill_references_with_source_ids(self) -> None:
register_lesson(
lesson_id="hook-1",
source_run_ids=["run-p1"],
source_review_ids=[str(self.review_id)],
kind="craft",
title="钩子再紧",
content="章末只留一个未解动作。\n",
target_ref="打磨小说语言",
lessons_dir=self.tmp / "pending",
path=self.db,
)
dest = approve_and_merge_lesson(
"hook-1",
decided_by="qingse",
rationale="人审通过",
references_dir=self.tmp / "打磨小说语言" / "references",
path=self.db,
)
self.assertTrue(dest.is_file())
self.assertIn("未解动作", dest.read_text(encoding="utf-8"))
with connect(self.db) as conn:
row = conn.execute("SELECT * FROM lessons WHERE id='hook-1'").fetchone()
self.assertEqual(row["status"], "promoted")
self.assertEqual(json.loads(row["source_run_ids"]), ["run-p1"])
self.assertEqual(json.loads(row["source_review_ids"]), [str(self.review_id)])
def test_replay_imports_the_same_production_flow(self) -> None:
self.assertIs(replay_mod.production_run_dispatch, dispatch_mod.run_dispatch)
source = inspect.getsource(replay_mod.replay_run)
self.assertIn("production_run_dispatch", source)
def test_web_write_surface_is_reviews_revisions_adopt_only(self) -> None:
self.assertEqual(webapp.WRITE_ACTIONS, frozenset({"reviews", "revisions", "adopt"}))
source = pathlib.Path(webapp.__file__).read_text(encoding="utf-8")
self.assertNotIn("INSERT INTO cards", source)
self.assertNotIn("INSERT INTO runs", source)
os.environ["MUSE_DB"] = str(self.db)
self.addCleanup(os.environ.pop, "MUSE_DB", None)
self.assertIn("adopt_candidate", inspect.getsource(webapp.adopt))
with mock.patch.object(webapp, "adopt_candidate", wraps=adopt_candidate) as spy:
review_id = webapp.adopt("run-p1", "qingse", "收下")
spy.assert_called_once_with("run-p1", "qingse", "收下")
self.assertIsInstance(review_id, int)
revise_id = webapp.revise("run-p1", "qingse", "改", "旧", "新")
with connect(self.db) as conn:
actions = [
row[0]
for row in conn.execute(
"SELECT action FROM reviews WHERE run_id='run-p1' ORDER BY id"
)
]
revision_n = conn.execute("SELECT COUNT(*) FROM revisions").fetchone()[0]
self.assertIn("adopt", actions)
self.assertIn("revise", actions)
self.assertGreaterEqual(revision_n, 2)
self.assertNotEqual(review_id, revise_id)
if __name__ == "__main__":
unittest.main()