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 | 547 | self.assertEqual([e["event"] for e in events], ["node_start", "node_completed"]) |
| 548 | 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 | 571 | # also exercise the real HTTP-facing read path end to end (not just |
| 551 | 572 | # the module function) -- an empty file was exactly bug A1. |
| 552 | 573 | row = self.conn.execute( | ... | ... |
src/work_graph_orchestrate.py
| ... | ... | @@ -99,8 +99,17 @@ from src import ( |
| 99 | 99 | |
| 100 | 100 | |
| 101 | 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 | 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 | ... | ... |