From be662c6134cbd43fa9bebfe842c072b0bcaa7187 Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Fri, 10 Jul 2026 19:43:43 -0700 Subject: [PATCH] fix(task-agent): address Copilot review on the id projection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - wire_safe_tool_call_id: SHA-256 not SHA-1 for the deterministic token — matches the codebase convention for fingerprints (attachments, auth, session) and drops the SHA-1 scanner flag. Non-crypto use, ids unchanged in shape (tid_ + 32 hex); no test pins the literal value. - interactive.js: the two sub-agent child-id example comments now show the real minted shape (::r{run}s{step}::), not a stale form. (cherry picked from commit a5c3dc00fca21da626a728f48d0b63b1ff2f7f49) --- turnstone/core/lowering.py | 4 ++-- turnstone/shared_static/interactive.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/turnstone/core/lowering.py b/turnstone/core/lowering.py index c40c548e..d339b46d 100644 --- a/turnstone/core/lowering.py +++ b/turnstone/core/lowering.py @@ -308,7 +308,7 @@ _WIRE_TOOL_ID_RE = re.compile(r"[a-zA-Z0-9_-]{1,40}") def wire_safe_tool_call_id(tc_id: str) -> str: """Return *tc_id* unchanged if it already matches the conservative wire-legal shape (:data:`_WIRE_TOOL_ID_RE`), else a deterministic safe - token (``tid_`` + 32 hex chars of its SHA-1, 36 chars total). + token (``tid_`` + 32 hex chars of its SHA-256, 36 chars total). Determinism is the contract: the same original id maps to the same token in the assistant ``tool_use`` and its ``tool_result`` (intra-request @@ -320,7 +320,7 @@ def wire_safe_tool_call_id(tc_id: str) -> str: """ if _WIRE_TOOL_ID_RE.fullmatch(tc_id): return tc_id - return "tid_" + hashlib.sha1(tc_id.encode("utf-8", "surrogatepass")).hexdigest()[:32] + return "tid_" + hashlib.sha256(tc_id.encode("utf-8", "surrogatepass")).hexdigest()[:32] def legalize_tool_call_ids(messages: list[dict[str, Any]]) -> list[dict[str, Any]]: diff --git a/turnstone/shared_static/interactive.js b/turnstone/shared_static/interactive.js index 956e8eff..1954530b 100644 --- a/turnstone/shared_static/interactive.js +++ b/turnstone/shared_static/interactive.js @@ -653,7 +653,7 @@ class Pane { if (!el) { let target = this._toolRow(callId); if (!target) { - // A minted sub-agent child id ("::::") whose row hasn't + // A minted sub-agent child id ("::r{run}s{step}::") whose row hasn't // nested yet must NOT graft its stream onto the last top-level batch — // that mislabels a sub-tool's output as a main-harness tool's. Its row // arrives via the orphan flush; skip the chunk until then. @@ -3491,7 +3491,7 @@ class Pane { } let target = this._toolRow(callId); if (!target) { - // A minted sub-agent child id ("::::") whose row hasn't + // A minted sub-agent child id ("::r{run}s{step}::") whose row hasn't // nested yet must NOT graft its output onto the last top-level batch row // — that mislabels a sub-tool's result as a main-harness tool's. Its row // arrives via the orphan flush; skip until then.