diff --git a/.github/time/test_time.py b/.github/time/test_time.py index b167ea8..d43d0ac 100644 --- a/.github/time/test_time.py +++ b/.github/time/test_time.py @@ -279,3 +279,8 @@ vt.tm.think = lambda seat, model, effort, system, user: votes[seat] w, meta = vt.board(ps, ["grok", "kimi", "qwen"]) assert w == "other" and meta["score"] == {"star-checker": 5, "other": 6}, meta print("ALL OK 6") +vt.tm.think = lambda *a: 'Sure! Here you go:\n```json\n{"slug": "x", "title": "T", "one_liner": "o", "why_now": "w", "page": "p {with braces}"}\n```' +assert vt.ask_json("q", "s", "u")["page"] == "p {with braces}" +vt.tm.think = lambda *a: "I would rather not." +assert vt.ask_json("q", "s", "u") is None +print("ALL OK 7") diff --git a/.github/time/venture.py b/.github/time/venture.py index 8be4ca9..dd8088c 100644 --- a/.github/time/venture.py +++ b/.github/time/venture.py @@ -69,10 +69,24 @@ hour, is it honest. Reply with ONLY JSON: {{"ranking": ["slug1", "slug2", "slug3 def ask_json(seat: str, system: str, user: str) -> dict | None: text = tm.think(seat, None, None, system, user) - try: - return json.loads(text[text.index("{"): text.rindex("}") + 1]) - except ValueError: - return None + text = re.sub(r"```(?:json)?", "", text) + # the outermost {...} may contain prose braces; try the widest span first, then each balanced candidate + starts = [m.start() for m in re.finditer(r"\{", text)] + for a in starts: + depth = 0 + for b, ch in enumerate(text[a:], a): + depth += ch == "{" + depth -= ch == "}" + if depth == 0: + try: + out = json.loads(text[a:b + 1]) + if isinstance(out, dict): + return out + except ValueError: + pass + break + print(f"{seat}: no JSON in reply: {text[:160]!r}") + return None def pitch(repos: list[dict], seats: list[str]) -> list[dict]: