|
|
@@ -796,9 +796,17 @@ def quiet_result(evt):
|
|
|
return True
|
|
|
|
|
|
|
|
|
+def same_session(a, b):
|
|
|
+ """PORT of sameSession: equal, or either side unlabelled."""
|
|
|
+ return a == b or a is None or b is None
|
|
|
+
|
|
|
+
|
|
|
def match_result_index(rows, index):
|
|
|
"""PORT of matchResultIndex: the first tool_result after the
|
|
|
- call when it matches turn/session/tool; -1 otherwise."""
|
|
|
+ call is its own (one call per turn). The live wire's result
|
|
|
+ payloads carry no turn of their own - matching rides on order,
|
|
|
+ tool name and session; a turn mismatch (both present) is the
|
|
|
+ only rejection."""
|
|
|
evt = rows[index]
|
|
|
payload = evt.get("payload") or {}
|
|
|
if not isinstance(payload.get("turn"), int):
|
|
|
@@ -807,8 +815,9 @@ def match_result_index(rows, index):
|
|
|
other = rows[j]
|
|
|
if other.get("kind") == "tool_result":
|
|
|
other_payload = other.get("payload") or {}
|
|
|
- if other_payload.get("turn") == payload.get("turn") \
|
|
|
- and other.get("session_id") == evt.get("session_id") \
|
|
|
+ other_turn = other_payload.get("turn")
|
|
|
+ if (other_turn is None or other_turn == payload.get("turn")) \
|
|
|
+ and same_session(other.get("session_id"), evt.get("session_id")) \
|
|
|
and str_text(other_payload.get("tool")) == str_text(payload.get("tool")):
|
|
|
return j
|
|
|
return -1
|
|
|
@@ -834,7 +843,7 @@ def folded_quiet_calls(rows):
|
|
|
continue
|
|
|
has_companion = any(
|
|
|
rows[k].get("kind") == companion
|
|
|
- and rows[k].get("session_id") == evt.get("session_id")
|
|
|
+ and same_session(rows[k].get("session_id"), evt.get("session_id"))
|
|
|
for k in range(index + 1, result_index))
|
|
|
if has_companion and quiet_result(rows[result_index]):
|
|
|
folded.add(index)
|
|
|
@@ -1236,18 +1245,24 @@ QUIET_ACK = json.dumps({"ok": True, "recorded": True})
|
|
|
FAILED_ACK = json.dumps({"ok": False, "error": "web callback unreachable"})
|
|
|
|
|
|
|
|
|
-def progress_trio(result_inner=QUIET_ACK, with_companion=True):
|
|
|
+def progress_trio(result_inner=QUIET_ACK, with_companion=True,
|
|
|
+ result_turn=None):
|
|
|
"""The live-tail's repetitive trio: an update_progress call,
|
|
|
the progress event carrying the same text, then the ack
|
|
|
- result."""
|
|
|
+ result. The live wire's result payloads carry NO turn of their
|
|
|
+ own (the payload is {tool, result}); pass result_turn to model
|
|
|
+ a turn-stamped result."""
|
|
|
rows = [{"id": 1, "kind": "tool_call", "session_id": 201, "payload": {
|
|
|
"turn": 1551, "tool": "update_progress",
|
|
|
"args": json.dumps({"text": "Segfault located"})}}]
|
|
|
if with_companion:
|
|
|
rows.append({"id": 2, "kind": "progress", "session_id": 201,
|
|
|
"payload": {"text": "Segfault located"}})
|
|
|
- rows.append({"id": 3, "kind": "tool_result", "session_id": 201, "payload": {
|
|
|
- "turn": 1551, "tool": "update_progress", "result": result_inner}})
|
|
|
+ result_payload = {"tool": "update_progress", "result": result_inner}
|
|
|
+ if result_turn is not None:
|
|
|
+ result_payload["turn"] = result_turn
|
|
|
+ rows.append({"id": 3, "kind": "tool_result", "session_id": 201,
|
|
|
+ "payload": result_payload})
|
|
|
return rows
|
|
|
|
|
|
|
|
|
@@ -1257,9 +1272,20 @@ class QuietFoldingTests(unittest.TestCase):
|
|
|
unfolds both."""
|
|
|
|
|
|
def test_quiet_trio_folds_call_and_result(self):
|
|
|
+ """The live wire's shape: the result carries no turn."""
|
|
|
folded = folded_quiet_calls(progress_trio())
|
|
|
self.assertEqual(folded, {0, 2})
|
|
|
|
|
|
+ def test_turn_stamped_result_also_folds(self):
|
|
|
+ folded = folded_quiet_calls(progress_trio(result_turn=1551))
|
|
|
+ self.assertEqual(folded, {0, 2})
|
|
|
+
|
|
|
+ def test_turn_mismatch_never_folds(self):
|
|
|
+ """A result stamped with another turn is not this call's
|
|
|
+ answer."""
|
|
|
+ self.assertEqual(
|
|
|
+ folded_quiet_calls(progress_trio(result_turn=9999)), set())
|
|
|
+
|
|
|
def test_failed_ack_unfolds_the_pair(self):
|
|
|
self.assertEqual(folded_quiet_calls(progress_trio(FAILED_ACK)), set())
|
|
|
|
|
|
@@ -1279,14 +1305,14 @@ class QuietFoldingTests(unittest.TestCase):
|
|
|
"turn": 5, "tool": "run_command",
|
|
|
"args": json.dumps({"command": "ls"})}},
|
|
|
{"id": 2, "kind": "tool_result", "session_id": 201, "payload": {
|
|
|
- "turn": 5, "tool": "run_command", "result": QUIET_ACK}},
|
|
|
+ "tool": "run_command", "result": QUIET_ACK}},
|
|
|
]
|
|
|
self.assertEqual(folded_quiet_calls(rows), set())
|
|
|
|
|
|
|
|
|
class ResultAttachmentTests(unittest.TestCase):
|
|
|
- """A non-folded call carries its result as an attached block;
|
|
|
- the result never renders as a separate row."""
|
|
|
+ """A non-folded call carries its result as an attached block
|
|
|
+ INSIDE its row; the result never renders as a separate row."""
|
|
|
|
|
|
def test_call_and_result_pair_up(self):
|
|
|
rows = [
|
|
|
@@ -1294,7 +1320,7 @@ class ResultAttachmentTests(unittest.TestCase):
|
|
|
"turn": 5, "tool": "run_command",
|
|
|
"args": json.dumps({"command": "make"})}},
|
|
|
{"id": 11, "kind": "tool_result", "session_id": 7, "payload": {
|
|
|
- "turn": 5, "tool": "run_command",
|
|
|
+ "tool": "run_command",
|
|
|
"result": json.dumps({"ok": True, "exit_code": 0,
|
|
|
"stdout": "built\n", "stderr": "",
|
|
|
"duration_ms": 900})}},
|
|
|
@@ -1303,6 +1329,23 @@ class ResultAttachmentTests(unittest.TestCase):
|
|
|
self.assertEqual(calls_by_id, {10: 11})
|
|
|
self.assertEqual(rides_by_id, {11: True})
|
|
|
|
|
|
+ def test_turn_less_live_result_pairs_up(self):
|
|
|
+ """The live wire's shape: the result carries no turn, so
|
|
|
+ matching rides on order, tool and session."""
|
|
|
+ rows = [
|
|
|
+ {"id": 20, "kind": "tool_call", "session_id": 201, "payload": {
|
|
|
+ "turn": 1731, "tool": "run_command",
|
|
|
+ "args": json.dumps({"command": "make test"})}},
|
|
|
+ {"id": 21, "kind": "tool_result", "session_id": 201, "payload": {
|
|
|
+ "tool": "run_command",
|
|
|
+ "result": json.dumps({"ok": True, "exit_code": 0,
|
|
|
+ "stdout": "ok\n", "stderr": "",
|
|
|
+ "duration_ms": 25000})}},
|
|
|
+ ]
|
|
|
+ calls_by_id, rides_by_id = attach_pairs(rows, set())
|
|
|
+ self.assertEqual(calls_by_id, {20: 21})
|
|
|
+ self.assertEqual(rides_by_id, {21: True})
|
|
|
+
|
|
|
def test_folded_pair_attaches_nothing(self):
|
|
|
calls_by_id, rides_by_id = attach_pairs(
|
|
|
progress_trio(), folded_quiet_calls(progress_trio()))
|