Re-run on 2026-10-16 with OpenCode (DeepSeek V4 Pro via OpenRouter) against the updated starter (scoped picture bundle, answer scrub, moveButton, key_input clocks, check_env.py). No hardcoded demo code. After the re-run, one line in view.js was changed so the witness name is text inside the heading instead of a DOM node concatenated with a string.
2026-10-16 · task Lp8mRZx1D2vl · opencode · openrouter/deepseek/deepseek-v4-pro-0813
Build a short criminal trial I can prosecute. The case is a theft. I call witnesses, ask them questions, and offer documents or objects as exhibits. A judge decides what the jury is allowed to hear. If I never get the evidence admitted, the jury should not act as if they heard it. When I rest and give a closing, the jury returns a verdict. The witnesses, the judge, and the jury can be played by language models, but the rule is fixed: the jury packet is only the admitted record. Winning is a conviction that came from that record. Show who is on the stand, the admitted exhibits, the last answer, and the verdict at the end. Clicking through the steps is how I play. Restarting should begin the trial over, with nothing admitted yet.
Running the prompt-created workspace on this machine — not a mock. Save an episode, then open Replay below to scrub the timeline.
opening · 0 ms
Exact files the agent wrote — not rewritten by hand.
# AI : a short criminal theft trial the person prosecutes. Click witnesses,
# ask questions, offer exhibits. A judge admits or excludes. The jury packet is
# ONLY the admitted record, and winning is a conviction built from that record.
from __future__ import annotations
from typing import Any, Dict, List, Optional
from helpers import base_observation, pick_task, rng_for, task_ids
GAME_CLASS = "Trial"
# ---------------------------------------------------------------------------
# The fixed scenarios. Each is a theft; witnesses carry questions, each
# question is either admissible or not (the judge rules). Exhibits may require
# a witness to have testified first (foundation). "probative" is the weight the
# jury puts on the item IF it is admitted; excluded items never reach the jury.
# ---------------------------------------------------------------------------
CASES: Dict[str, Dict[str, Any]] = {
"case1": {
"id": "case1",
"name": "The People v. Dana Cole",
"charge": "Grand theft of a gold wristwatch",
"defendant": "Dana Cole",
"victim": "Marcus Hale",
"goal": "Win a conviction with only the evidence the judge admits. The jury hears nothing else.",
"opening": (
"During the lunch hour, Marcus Hale's gold wristwatch vanished from "
"his desk at Meridian Partners. The prosecution says the new intern, "
"Dana Cole, took it. The defense says the State cannot prove it."
),
"threshold": 12,
"witnesses": [
{
"id": "marcus",
"name": "Marcus Hale",
"role": "Owner of the stolen watch",
"questions": [
{
"id": "wm1",
"text": "What did you do with the watch just before it disappeared?",
"answer": "I took it off at lunchtime and left it on my desk while I went to the cafeteria.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. First-hand account, relevant.",
"out_reason": "",
},
{
"id": "wm2",
"text": "Did you ever give anyone permission to take the watch?",
"answer": "No. I never gave Dana or anyone else permission to take it.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. Relevant to whether the taking was unauthorized.",
"out_reason": "",
},
{
"id": "wm3",
"text": "You suspected Dana from the very beginning, didn't you?",
"answer": "Honestly, I did suspect them right away.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Leading. On direct examination you may not suggest the answer.",
},
],
},
{
"id": "priya",
"name": "Priya Shah",
"role": "Coworker who sat across the hall",
"questions": [
{
"id": "wp1",
"text": "What did you see around 12:30 that afternoon?",
"answer": "I saw Dana walk out of Marcus's office alone, holding something small and gold.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Personal observation of a material fact.",
"out_reason": "",
},
{
"id": "wp2",
"text": "Did Dana say anything about it afterwards?",
"answer": "Yes. I heard Dana say, \"I hope nobody notices it's gone.\"",
"probative": 2,
"admit": True,
"in_reason": "Admitted. A statement by a party is not hearsay.",
"out_reason": "",
},
{
"id": "wp3",
"text": "Dana always seemed like the type to do this, didn't they?",
"answer": "I guess Dana did always seem a little sneaky.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Improper character evidence used to show guilt by disposition.",
},
],
},
{
"id": "ortiz",
"name": "Detective Ortiz",
"role": "Investigating officer",
"questions": [
{
"id": "wo1",
"text": "What did you observe about the office door?",
"answer": "No forced entry. The lock was intact, so whoever took it entered while the office was open.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. Relevant context.",
"out_reason": "",
},
{
"id": "wo2",
"text": "What did forensics find on the desk drawer?",
"answer": "A latent print lifted from the drawer matched Dana Cole's right index finger.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Foundation laid for the identification.",
"out_reason": "",
},
{
"id": "wo3",
"text": "Who do you believe stole the watch?",
"answer": "I'm convinced Dana took it.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Opinion on the ultimate issue. That is the jury's call, not a witness's.",
},
],
},
{
"id": "sam",
"name": "Sam Whitfield",
"role": "Building security guard",
"questions": [
{
"id": "ws1",
"text": "Can you authenticate the lobby camera feed from the 14th?",
"answer": "Yes, this is the lobby camera, date-stamped the 14th, noon to 1 pm. I have reviewed it.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. The witness authenticates the recording.",
"out_reason": "",
},
{
"id": "ws2",
"text": "What did the door badge log show around lunch?",
"answer": "Dana's badge was the only one swiped at that office door between 12:20 and 12:45.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Business record, relevant.",
"out_reason": "",
},
{
"id": "ws3",
"text": "What do people in the building say about Dana?",
"answer": "People say Dana is always broke and asks to borrow money.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Hearsay and reputation. Not probative of this particular theft.",
},
],
},
],
"exhibits": [
{
"id": "e1",
"name": "Lobby security footage",
"desc": "Shows Dana enter office 4 at 12:31 and leave alone at 12:38.",
"probative": 3,
"admit": True,
"needs": "sam",
"in_reason": "Admitted. Recording authenticated by the guard.",
"out_reason": "No foundation. The footage has not been authenticated by a witness.",
},
{
"id": "e2",
"name": "Fingerprint card",
"desc": "Latent print from the desk drawer, matched to Dana Cole's right index finger.",
"probative": 2,
"admit": True,
"needs": "ortiz",
"in_reason": "Admitted. Chain of custody established by the detective.",
"out_reason": "No foundation. Chain of custody has not been established.",
},
{
"id": "e3",
"name": "Recovered watch",
"desc": "The gold watch recovered from Dana's locker during a consented search. The serial number matches the one Marcus reported stolen.",
"probative": 3,
"admit": True,
"needs": "ortiz",
"in_reason": "Admitted. Recovered and identified through the investigation.",
"out_reason": "No foundation. No witness has tied this watch to the investigation.",
},
{
"id": "e4",
"name": "Anonymous note",
"desc": "An unsigned note found in the break room reading \"Dana is a thief.\"",
"probative": 0,
"admit": False,
"needs": None,
"in_reason": "",
"out_reason": "Anonymous hearsay with no probative value. Excluded.",
},
],
},
"case2": {
"id": "case2",
"name": "The People v. Ray Porter",
"charge": "Theft of a wallet",
"defendant": "Ray Porter",
"victim": "Elena Vasquez",
"goal": "Win a conviction with only the evidence the judge admits. The jury hears nothing else.",
"opening": (
"At the Sunnyside Diner, Elena Vasquez left her wallet on the counter to "
"grab napkins, and it was gone. The prosecution says regular customer "
"Ray Porter took it. The defense says the State cannot prove it."
),
"threshold": 12,
"witnesses": [
{
"id": "elena",
"name": "Elena Vasquez",
"role": "Owner of the wallet",
"questions": [
{
"id": "ev1",
"text": "What did you do with your wallet at the counter?",
"answer": "I set it down to pay and turned to grab napkins. When I turned back it was gone.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. First-hand account, relevant.",
"out_reason": "",
},
{
"id": "ev2",
"text": "Did you give anyone permission to take your wallet?",
"answer": "No. I never gave anyone permission, especially not Ray.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. Relevant to whether the taking was unauthorized.",
"out_reason": "",
},
{
"id": "ev3",
"text": "You're certain Ray took it, aren't you?",
"answer": "I knew it was him right away.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Leading. On direct examination you may not suggest the answer.",
},
],
},
{
"id": "toni",
"name": "Toni Brooks",
"role": "Diner server",
"questions": [
{
"id": "tb1",
"text": "What did you see at the counter around 2 pm?",
"answer": "I saw Ray reach over the counter and slide the wallet into his jacket.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Personal observation of a material fact.",
"out_reason": "",
},
{
"id": "tb2",
"text": "Did Ray say anything when he was confronted?",
"answer": "He said, \"I was only going to borrow it for a minute.\"",
"probative": 2,
"admit": True,
"in_reason": "Admitted. A statement by a party is not hearsay.",
"out_reason": "",
},
{
"id": "tb3",
"text": "Ray is always causing trouble, isn't he?",
"answer": "He's caused trouble before.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Improper character evidence used to show guilt by disposition.",
},
],
},
{
"id": "park",
"name": "Detective Park",
"role": "Investigating officer",
"questions": [
{
"id": "jp1",
"text": "Was the diner's camera system working that day?",
"answer": "The counter camera was working and has a clear view of the register.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. Relevant context.",
"out_reason": "",
},
{
"id": "jp2",
"text": "What was recovered from the dumpster behind the diner?",
"answer": "Elena's empty wallet, with Ray's fingerprint on the clasp.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Foundation laid for the identification.",
"out_reason": "",
},
{
"id": "jp3",
"text": "Do you think Ray is guilty?",
"answer": "I'm sure of it.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Opinion on the ultimate issue. That is the jury's call, not a witness's.",
},
],
},
{
"id": "moe",
"name": "Moe Callahan",
"role": "Diner owner",
"questions": [
{
"id": "mc1",
"text": "Can you authenticate the counter camera recording from 2 pm?",
"answer": "Yes, this is our counter camera from 2 pm that day.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. The witness authenticates the recording.",
"out_reason": "",
},
{
"id": "mc2",
"text": "What does the register-area recording show?",
"answer": "It shows Ray leaning over the counter and the wallet disappearing into his coat.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Business record, relevant.",
"out_reason": "",
},
{
"id": "mc3",
"text": "What have customers said about Ray?",
"answer": "Regulars say he has been hard up for money lately.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Hearsay and reputation. Not probative of this particular theft.",
},
],
},
],
"exhibits": [
{
"id": "e1",
"name": "Counter camera recording",
"desc": "Shows Ray leaning over the counter and tucking a wallet into his coat.",
"probative": 3,
"admit": True,
"needs": "moe",
"in_reason": "Admitted. Recording authenticated by the owner.",
"out_reason": "No foundation. The recording has not been authenticated by a witness.",
},
{
"id": "e2",
"name": "Fingerprint report",
"desc": "A latent print on the wallet clasp, matched to Ray Porter's right thumb.",
"probative": 2,
"admit": True,
"needs": "park",
"in_reason": "Admitted. Chain of custody established by the detective.",
"out_reason": "No foundation. Chain of custody has not been established.",
},
{
"id": "e3",
"name": "Recovered wallet",
"desc": "Elena's empty wallet, recovered from the dumpster behind the diner.",
"probative": 3,
"admit": True,
"needs": "park",
"in_reason": "Admitted. Recovered and identified through the investigation.",
"out_reason": "No foundation. No witness has tied this wallet to the investigation.",
},
{
"id": "e4",
"name": "Anonymous online post",
"desc": "An anonymous post on the diner's page reading \"Ray Porter is a thief.\"",
"probative": 0,
"admit": False,
"needs": None,
"in_reason": "",
"out_reason": "Anonymous hearsay with no probative value. Excluded.",
},
],
},
"case3": {
"id": "case3",
"name": "The People v. Ivy Chen",
"charge": "Theft of a bicycle",
"defendant": "Ivy Chen",
"victim": "Oscar Reed",
"goal": "Win a conviction with only the evidence the judge admits. The jury hears nothing else.",
"opening": (
"Oscar Reed locked his bicycle to the library rack at 9 am and returned "
"to find the lock cut and the bike gone. The prosecution says fellow "
"student Ivy Chen took it. The defense says the State cannot prove it."
),
"threshold": 12,
"witnesses": [
{
"id": "oscar",
"name": "Oscar Reed",
"role": "Owner of the bicycle",
"questions": [
{
"id": "or1",
"text": "What did you do with your bicycle before class?",
"answer": "I locked it to the rack outside the library at 9 am before my class.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. First-hand account, relevant.",
"out_reason": "",
},
{
"id": "or2",
"text": "Did you give anyone permission to take it?",
"answer": "No. I never loaned it to anyone, least of all Ivy.",
"probative": 1,
"admit": True,
"in_reason": "Admitted. Relevant to whether the taking was unauthorized.",
"out_reason": "",
},
{
"id": "or3",
"text": "You're positive Ivy took it, right?",
"answer": "I was sure it was Ivy from the start.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Leading. On direct examination you may not suggest the answer.",
},
],
},
{
"id": "leah",
"name": "Leah Osei",
"role": "Student eyewitness",
"questions": [
{
"id": "lo1",
"text": "What did you see outside the library around noon?",
"answer": "I saw Ivy cut the lock off a blue bike and ride away on it.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Personal observation of a material fact.",
"out_reason": "",
},
{
"id": "lo2",
"text": "Did Ivy say anything when you asked about the bike?",
"answer": "They said, \"Mind your own business, I'm just borrowing it.\"",
"probative": 2,
"admit": True,
"in_reason": "Admitted. A statement by a party is not hearsay.",
"out_reason": "",
},
{
"id": "lo3",
"text": "Ivy is known for taking things, aren't they?",
"answer": "Ivy has got a reputation, sure.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Improper character evidence used to show guilt by disposition.",
},
],
},
{
"id": "reyes",
"name": "Detective Reyes",
"role": "Investigating officer",
"questions": [
{
"id": "ar1",
"text": "Was the bike rack area filmed?",
"answer": "The library has a camera covering the bike rack.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. Relevant context.",
"out_reason": "",
},
{
"id": "ar2",
"text": "What did you recover from Ivy's dorm room?",
"answer": "We found Oscar's bike in Ivy's dorm room with freshly cut lock marks.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Foundation laid for the identification.",
"out_reason": "",
},
{
"id": "ar3",
"text": "Who did it, in your view?",
"answer": "Ivy, obviously.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Opinion on the ultimate issue. That is the jury's call, not a witness's.",
},
],
},
{
"id": "nia",
"name": "Nia Bell",
"role": "Library security",
"questions": [
{
"id": "nb1",
"text": "Can you authenticate the library camera recording from noon?",
"answer": "Yes, this is our camera feed covering the bike rack.",
"probative": 0,
"admit": True,
"in_reason": "Admitted. The witness authenticates the recording.",
"out_reason": "",
},
{
"id": "nb2",
"text": "What does the recording show?",
"answer": "It shows Ivy cutting the lock and riding off on the blue bike.",
"probative": 2,
"admit": True,
"in_reason": "Admitted. Business record, relevant.",
"out_reason": "",
},
{
"id": "nb3",
"text": "What do students say about Ivy?",
"answer": "They say Ivy is always after something.",
"probative": 0,
"admit": False,
"in_reason": "",
"out_reason": "Hearsay and reputation. Not probative of this particular theft.",
},
],
},
],
"exhibits": [
{
"id": "e1",
"name": "Library camera recording",
"desc": "Shows Ivy cutting the bike lock and riding off on the bicycle.",
"probative": 3,
"admit": True,
"needs": "nia",
"in_reason": "Admitted. Recording authenticated by library security.",
"out_reason": "No foundation. The recording has not been authenticated by a witness.",
},
{
"id": "e2",
"name": "Cut lock",
"desc": "The severed bicycle lock recovered from the rack, severed by bolt cutters.",
"probative": 2,
"admit": True,
"needs": "reyes",
"in_reason": "Admitted. Chain of custody established by the detective.",
"out_reason": "No foundation. Chain of custody has not been established.",
},
{
"id": "e3",
"name": "Recovered bicycle",
"desc": "Oscar's blue bicycle, recovered from Ivy's dorm room.",
"probative": 3,
"admit": True,
"needs": "reyes",
"in_reason": "Admitted. Recovered and identified through the investigation.",
"out_reason": "No foundation. No witness has tied this bicycle to the investigation.",
},
{
"id": "e4",
"name": "Anonymous tip",
"desc": "An anonymous text message reading \"Ivy Chen steals bikes.\"",
"probative": 0,
"admit": False,
"needs": None,
"in_reason": "",
"out_reason": "Anonymous hearsay with no probative value. Excluded.",
},
],
},
}
TASK_IDS = task_ids(3, prefix="case")
def _witness(case: Dict[str, Any], wid: str) -> Dict[str, Any]:
for w in case["witnesses"]:
if w["id"] == wid:
return w
raise KeyError(wid)
def _question(witness: Dict[str, Any], qid: str) -> Dict[str, Any]:
for q in witness["questions"]:
if q["id"] == qid:
return q
raise KeyError(qid)
def _exhibit(case: Dict[str, Any], eid: str) -> Dict[str, Any]:
for e in case["exhibits"]:
if e["id"] == eid:
return e
raise KeyError(eid)
class Trial:
"""A single prosecution. State stays on the instance; the verdict comes only
from the admitted record."""
def __init__(self) -> None:
self.case: Dict[str, Any] = {}
self.task_id: str = ""
self.rng = rng_for("")
# -- lifecycle ---------------------------------------------------------
def reset(self, task_id: str = "") -> Dict[str, Any]:
case_id = pick_task(task_id, TASK_IDS, default="case1")
self.task_id = task_id or case_id
self.rng = rng_for(self.task_id)
self.case = CASES[case_id]
self.phase = "call"
self.on_stand: Optional[str] = None
self.asked: set[str] = set()
self.offered: set[str] = set()
self.testified: set[str] = set()
self.admitted: List[Dict[str, Any]] = []
self.excluded: List[Dict[str, str]] = []
self.transcript: List[Dict[str, str]] = []
self.last_answer: Optional[str] = None
self.last_answer_by: Optional[str] = None
self.judge_ruling: str = ""
self.done = False
self.verdict: Optional[str] = None
self.closing_text: str = ""
self._note = self.case["opening"]
self._log("note", "The court", self._note)
return self._observe(last_move=None)
# -- moves --------------------------------------------------------------
def _log(self, kind: str, who: str, text: str) -> None:
self.transcript.append({"kind": kind, "who": who, "text": text})
if len(self.transcript) > 10:
self.transcript = self.transcript[-10:]
def step(self, action: Any) -> tuple:
if self.done:
return self._observe(last_move=self.last_move), False, "The trial is over."
move = getattr(action, "move", "") or ""
move = move.strip()
legal = self._legal_moves()
if move not in legal:
return self._observe(last_move=None), False, f"'{move}' is not available right now."
self.last_move = move
if move.startswith("call:"):
wid = move.split(":", 1)[1]
self._do_call(wid)
elif move.startswith("ask:"):
qid = move.split(":", 1)[1]
self._do_ask(qid)
elif move.startswith("offer:"):
eid = move.split(":", 1)[1]
self._do_offer(eid)
elif move == "excuse":
self._do_excuse()
elif move == "rest":
self._do_rest()
elif move == "closing":
self._do_closing()
return self._observe(last_move=move), True, None
# -- each action ---------------------------------------------------------
def _do_call(self, wid: str) -> None:
w = _witness(self.case, wid)
self.on_stand = wid
self.phase = "stand"
self.judge_ruling = ""
self.last_answer_by = w["name"]
self.last_answer = f"{w['name']} takes the stand."
self._log("note", w["name"], "takes the stand")
def _do_excuse(self) -> None:
wid = self.on_stand
name = _witness(self.case, wid)["name"] if wid else "The witness"
self.on_stand = None
self.phase = "call"
self.judge_ruling = ""
self.last_answer = f"{name} steps down."
self.last_answer_by = None
self._log("note", name, "steps down")
def _do_ask(self, qid: str) -> None:
assert self.on_stand is not None
w = _witness(self.case, self.on_stand)
q = _question(w, qid)
self.asked.add(qid)
self.testified.add(self.on_stand)
self.last_answer_by = w["name"]
if q["admit"]:
self.admitted.append(
{
"kind": "testimony",
"source": w["name"],
"text": q["answer"],
"probative": q["probative"],
}
)
self.judge_ruling = q["in_reason"]
self._log("answer", w["name"], q["answer"])
self._log("ruling", "The judge", "Admitted. " + q["in_reason"].split(".", 1)[0])
else:
self.excluded.append({"source": w["name"], "text": q["answer"]})
self.judge_ruling = q["out_reason"]
self._log("answer", w["name"], q["answer"])
self._log("ruling", "The judge", "Excluded. " + q["out_reason"])
self.last_answer = q["answer"]
def _do_offer(self, eid: str) -> None:
e = _exhibit(self.case, eid)
if e["admit"] and e.get("needs") and e["needs"] not in self.testified:
self.judge_ruling = e["out_reason"]
self.last_answer_by = None
self.last_answer = f"Offered: {e['name']} — {e['desc']}"
self._log("ruling", "The judge", "Excluded (no foundation). " + e["out_reason"])
return
if e["admit"]:
self.offered.add(eid)
self.admitted.append(
{
"kind": "exhibit",
"source": e["name"],
"text": e["desc"],
"probative": e["probative"],
}
)
self.judge_ruling = e["in_reason"]
self._log("ruling", "The judge", "Admitted. " + e["in_reason"])
else:
self.offered.add(eid)
self.excluded.append({"source": e["name"], "text": e["desc"]})
self.judge_ruling = e["out_reason"]
self._log("ruling", "The judge", "Excluded. " + e["out_reason"])
self.last_answer_by = None
self.last_answer = f"Offered: {e['name']} — {e['desc']}"
def _do_rest(self) -> None:
self.on_stand = None
self.phase = "closing"
self.judge_ruling = ""
self.last_answer = "The State rests. It is time for closing arguments."
self.last_answer_by = None
self._log("note", "The prosecutor", "The State rests.")
def _do_closing(self) -> None:
admitted = self.admitted
bits = [a["text"] for a in admitted]
if admitted:
self.closing_text = (
"Ladies and gentlemen of the jury — you heard that " +
" and that ".join(bits) +
". On the record before you, the People ask you to convict."
)
else:
self.closing_text = (
"Ladies and gentlemen of the jury — the People presented no "
"admitted evidence for you to weigh."
)
total = sum(a["probative"] for a in admitted)
if total >= self.case["threshold"]:
self.verdict = "guilty"
else:
self.verdict = "not guilty"
self.phase = "verdict"
self.done = True
self.judge_ruling = ""
self.last_answer_by = None
self.last_answer = self._verdict_line()
self._log("verdict", "The jury", self._verdict_line())
def _verdict_line(self) -> str:
if self.verdict == "guilty":
return "Verdict: GUILTY of theft."
return "Verdict: NOT GUILTY."
# -- observation ---------------------------------------------------------
def _legal_moves(self) -> List[str]:
if self.done:
return []
if self.phase == "closing":
return ["closing"]
moves: List[str] = []
for w in self.case["witnesses"]:
if self.phase == "call":
moves.append("call:" + w["id"])
for e in self.case["exhibits"]:
if e["id"] not in self.offered:
moves.append("offer:" + e["id"])
if self.phase == "stand" and self.on_stand:
w = _witness(self.case, self.on_stand)
for q in w["questions"]:
if q["id"] not in self.asked:
moves.append("ask:" + q["id"])
moves.append("excuse")
moves.append("rest")
return moves
def _observe(self, last_move: Optional[str]) -> Dict[str, Any]:
reward = 0.0
if self.done:
reward = 1.0 if self.verdict == "guilty" else -1.0
witnesses = []
for w in self.case["witnesses"]:
if w["id"] == self.on_stand:
status = "on the stand"
elif w["id"] in self.testified:
status = "testified"
else:
status = ""
witnesses.append(
{"id": w["id"], "label": w["name"], "role": w["role"], "status": status}
)
exhibits = []
for e in self.case["exhibits"]:
if e["id"] in self.offered:
status = "admitted" if e["admit"] else "excluded"
else:
status = ""
exhibits.append(
{"id": e["id"], "label": e["name"], "desc": e["desc"], "status": status}
)
questions = []
if self.phase == "stand" and self.on_stand:
w = _witness(self.case, self.on_stand)
for q in w["questions"]:
questions.append(
{
"id": q["id"],
"label": q["text"],
"asked": q["id"] in self.asked,
}
)
on_stand = None
if self.on_stand:
w = _witness(self.case, self.on_stand)
on_stand = {"id": w["id"], "name": w["name"], "role": w["role"]}
admitted_record = [
{"kind": a["kind"], "source": a["source"], "text": a["text"]}
for a in self.admitted
]
verdict_label = ""
verdict_note = ""
if self.done:
verdict_label = "Guilty" if self.verdict == "guilty" else "Not guilty"
n_admitted = len(self.admitted)
verdict_note = (
f"The jury weighed only the {n_admitted} item(s) the judge admitted. "
+ self._verdict_line()
)
return base_observation(
reward=reward,
done=self.done,
legal_moves=self._legal_moves(),
last_move=last_move,
task_id=self.task_id,
case_id=self.case["id"],
case_name=self.case["name"],
charge=self.case["charge"],
defendant=self.case["defendant"],
victim=self.case["victim"],
goal=self.case["goal"],
phase=self.phase,
note=self._note,
witnesses=witnesses,
on_stand=on_stand,
questions=questions,
exhibits=exhibits,
admitted_record=admitted_record,
admitted_count=len(self.admitted),
excluded_count=len(self.excluded),
transcript=list(self.transcript),
last_answer=self.last_answer,
last_answer_by=self.last_answer_by,
judge_ruling=self.judge_ruling,
closing_text=self.closing_text if self.done else "",
verdict=self.verdict if self.done else None,
verdict_label=verdict_label,
verdict_note=verdict_note,
)