Commit 169d1bae20458cb1cd0f538c8ec0ae15a4f5c8d2
1 parent
01987427
graphlemon: auto-commit uncommitted changes for 46748e02-6e65-49f5-a3ae-2f2bdea9…
…3d96-main-checkout-drift
Showing
2 changed files
with
31 additions
and
1 deletions
src/test_work_graph_orchestrate.py
| @@ -547,6 +547,27 @@ class RunFnLogsExecutionEventsTest(RunGraphTestBase): | @@ -547,6 +547,27 @@ class RunFnLogsExecutionEventsTest(RunGraphTestBase): | ||
| 547 | self.assertEqual([e["event"] for e in events], ["node_start", "node_completed"]) | 547 | self.assertEqual([e["event"] for e in events], ["node_start", "node_completed"]) |
| 548 | self.assertEqual(events[1]["output"], {"content": "brd text"}) | 548 | self.assertEqual(events[1]["output"], {"content": "brd text"}) |
| 549 | 549 | ||
| 550 | + def test_non_ascii_content_written_as_real_utf8_not_escaped(self): | ||
| 551 | + # User-reported (2026-08-13): v_log_viewer reads this .jsonl file's | ||
| 552 | + # raw bytes back and displays each line AS-IS (never JSON.parse()s | ||
| 553 | + # it), unlike every other json.dumps() call in this codebase whose | ||
| 554 | + # output always gets re-parsed before display. Without | ||
| 555 | + # ensure_ascii=False, real Chinese content here showed up in the | ||
| 556 | + # console as literal \uXXXX escape sequences instead of the actual | ||
| 557 | + # characters. | ||
| 558 | + manifest = {"nodes": [{"node_id": "brd", "depends_on": []}], "edges": []} | ||
| 559 | + with patch.object( | ||
| 560 | + org_node_trigger, "trigger_org_node_structured", return_value={"content": "期望行为:真实中文内容"} | ||
| 561 | + ): | ||
| 562 | + wgo.run_graph( | ||
| 563 | + self.conn, "run-1", "planner", "planner-doc-writing", "/tmp/proj-1", manifest, | ||
| 564 | + lambda node, outputs: "p", _IN_SCHEMA, _OUT_SCHEMA, | ||
| 565 | + ) | ||
| 566 | + | ||
| 567 | + raw_content = execution_log.get_log(self.conn, self._node_exec_id())["content"] | ||
| 568 | + self.assertIn("期望行为:真实中文内容", raw_content) | ||
| 569 | + self.assertNotIn("\\u671f", raw_content) # 期 == 期, the escaped form this bug produced | ||
| 570 | + | ||
| 550 | # also exercise the real HTTP-facing read path end to end (not just | 571 | # also exercise the real HTTP-facing read path end to end (not just |
| 551 | # the module function) -- an empty file was exactly bug A1. | 572 | # the module function) -- an empty file was exactly bug A1. |
| 552 | row = self.conn.execute( | 573 | row = self.conn.execute( |
src/work_graph_orchestrate.py
| @@ -99,8 +99,17 @@ from src import ( | @@ -99,8 +99,17 @@ from src import ( | ||
| 99 | 99 | ||
| 100 | 100 | ||
| 101 | def _log_event(conn, node_exec_id, event_type, **payload): | 101 | def _log_event(conn, node_exec_id, event_type, **payload): |
| 102 | + # ensure_ascii=False (2026-08-13, user-reported): this is the ONLY | ||
| 103 | + # json.dumps() call in the codebase whose output is displayed as raw | ||
| 104 | + # TEXT (v_log_viewer reads the .jsonl file's bytes back and shows each | ||
| 105 | + # line as-is, never JSON.parse()s it back into structured data) -- | ||
| 106 | + # every other json.dumps() call here stores data that's always | ||
| 107 | + # JSON.parse()d/json.loads()d again before display, so the default | ||
| 108 | + # \uXXXX escaping round-trips invisibly there. Here it doesn't: real | ||
| 109 | + # Chinese (or any non-ASCII) content in `payload` showed up as literal | ||
| 110 | + # \uXXXX escape sequences in the console instead of the actual text. | ||
| 102 | execution_log.append_log( | 111 | execution_log.append_log( |
| 103 | - conn, node_exec_id, json.dumps({"event": event_type, **payload}) + "\n" | 112 | + conn, node_exec_id, json.dumps({"event": event_type, **payload}, ensure_ascii=False) + "\n" |
| 104 | ) | 113 | ) |
| 105 | 114 | ||
| 106 | 115 |