|
@@ -379,11 +379,52 @@ class TriageAnalyzer:
|
|
|
parts.append("Return only the updated brief as plain text.")
|
|
parts.append("Return only the updated brief as plain text.")
|
|
|
return "\n\n".join(parts)
|
|
return "\n\n".join(parts)
|
|
|
|
|
|
|
|
- def _unwrap_tool_call(self, text: str) -> str:
|
|
|
|
|
- """Unwrap a stray model tool-call envelope into its plain brief payload.
|
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def _first_arg_start(text: str) -> int:
|
|
|
|
|
+ name_at = text.find("updated_brief")
|
|
|
|
|
+ if name_at != -1:
|
|
|
|
|
+ cursor = name_at + len("updated_brief")
|
|
|
|
|
+ while cursor < len(text) and text[cursor] == " ":
|
|
|
|
|
+ cursor += 1
|
|
|
|
|
+ if cursor < len(text) and text[cursor] == "=":
|
|
|
|
|
+ return cursor + 1
|
|
|
|
|
+ call_at = text.find("update_brief(")
|
|
|
|
|
+ if call_at == -1:
|
|
|
|
|
+ call_at = text.find("update_brief (")
|
|
|
|
|
+ return call_at + len("update_brief(") if call_at != -1 else 0
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def _first_quote(text: str, start: int) -> tuple[int, str]:
|
|
|
|
|
+ opening = -1
|
|
|
|
|
+ quote = "'"
|
|
|
|
|
+ for candidate in ("'", '"'):
|
|
|
|
|
+ index = text.find(candidate, start)
|
|
|
|
|
+ if index != -1 and (opening == -1 or index < opening):
|
|
|
|
|
+ opening, quote = index, candidate
|
|
|
|
|
+ return opening, quote
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def _arg_boundary_quote(text: str, opening: int, quote: str) -> int:
|
|
|
|
|
+ index = opening + 1
|
|
|
|
|
+ while True:
|
|
|
|
|
+ candidate = text.find(quote, index)
|
|
|
|
|
+ if candidate == -1:
|
|
|
|
|
+ return -1
|
|
|
|
|
+ after = candidate + 1
|
|
|
|
|
+ while after < len(text) and text[after] == " ":
|
|
|
|
|
+ after += 1
|
|
|
|
|
+ if after >= len(text) or text[after] in ",)]<":
|
|
|
|
|
+ return candidate
|
|
|
|
|
+ index = candidate + 1
|
|
|
|
|
+
|
|
|
|
|
+ def _unwrap_tool_call(self, text: str) -> str | None:
|
|
|
|
|
+ """Unwrap a stray tool-call envelope into its first plain argument value.
|
|
|
|
|
|
|
|
Only fires when an explicit wrapper marker is present so clean markdown
|
|
Only fires when an explicit wrapper marker is present so clean markdown
|
|
|
- containing ``[``, ``(``, or ``'`` is passed through untouched.
|
|
|
|
|
|
|
+ containing ``[``, ``(``, or ``'`` is passed through untouched. The first
|
|
|
|
|
+ argument is taken up to its closing quote boundary, so a multi-argument
|
|
|
|
|
+ call never swallows the separators; an envelope that cannot be reduced to
|
|
|
|
|
+ a clean payload is rejected (None) rather than stored verbatim.
|
|
|
"""
|
|
"""
|
|
|
markers = ("<|tool_call_start|>", "<|tool_call_end|>", "update_brief(", "update_brief (")
|
|
markers = ("<|tool_call_start|>", "<|tool_call_end|>", "update_brief(", "update_brief (")
|
|
|
if not any(marker in text for marker in markers):
|
|
if not any(marker in text for marker in markers):
|
|
@@ -394,17 +435,19 @@ class TriageAnalyzer:
|
|
|
text = text.split("<|tool_call_end|>", 1)[0]
|
|
text = text.split("<|tool_call_end|>", 1)[0]
|
|
|
text = text.strip()
|
|
text = text.strip()
|
|
|
if "update_brief(" not in text and "update_brief (" not in text:
|
|
if "update_brief(" not in text and "update_brief (" not in text:
|
|
|
|
|
+ if any(token in text for token in ("<|", "previous_brief=", "mode=")):
|
|
|
|
|
+ return None
|
|
|
return text
|
|
return text
|
|
|
- # Extract the argument between the first and last matching quote. The
|
|
|
|
|
- # payload itself may contain apostrophes, so pair on the LAST quote of
|
|
|
|
|
- # whichever delimiter opens first.
|
|
|
|
|
- positions = [(text.find(quote), quote) for quote in ("'", '"') if text.find(quote) != -1]
|
|
|
|
|
- if positions:
|
|
|
|
|
- first, quote = min(positions)
|
|
|
|
|
- last = text.rfind(quote)
|
|
|
|
|
- if last > first:
|
|
|
|
|
- text = text[first + 1 : last]
|
|
|
|
|
- return text.strip()
|
|
|
|
|
|
|
+ opening, quote = self._first_quote(text, self._first_arg_start(text))
|
|
|
|
|
+ if opening == -1:
|
|
|
|
|
+ return None
|
|
|
|
|
+ closing = self._arg_boundary_quote(text, opening, quote)
|
|
|
|
|
+ if closing == -1:
|
|
|
|
|
+ return None
|
|
|
|
|
+ value = text[opening + 1 : closing].strip()
|
|
|
|
|
+ if any(token in value for token in ("<|", "previous_brief=", "mode=")):
|
|
|
|
|
+ return None
|
|
|
|
|
+ return value
|
|
|
|
|
|
|
|
def parse_brief(self, text) -> str | None:
|
|
def parse_brief(self, text) -> str | None:
|
|
|
"""Strip a code fence and any stray tool-call envelope; None when empty."""
|
|
"""Strip a code fence and any stray tool-call envelope; None when empty."""
|