miau commited on
Commit
88e4b2b
·
1 Parent(s): 2b105f8

Ignore OpenClaude metadata when detecting user intent

Browse files
Files changed (2) hide show
  1. openai_compat.py +21 -1
  2. test_openai_compat.py +21 -0
openai_compat.py CHANGED
@@ -119,6 +119,10 @@ NO_TOOLS_RE = re.compile(
119
  r"without"
120
  r")\s+(?:as?\s+)?(?:ferramentas?|tools?)\b"
121
  )
 
 
 
 
122
 
123
 
124
  @dataclass(frozen=True)
@@ -158,6 +162,22 @@ def _content_text(content: Any) -> str:
158
  return "" if content is None else str(content)
159
 
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  def _call_arguments(value: Any) -> dict[str, Any]:
162
  if isinstance(value, Mapping):
163
  return dict(value)
@@ -307,7 +327,7 @@ def _latest_user_request(messages: object) -> str:
307
  and str(message.get("role", "")).casefold() == "user"
308
  and not _is_synthetic_continuation(message)
309
  ):
310
- text = _content_text(message.get("content")).strip()
311
  if text:
312
  requests.append(text)
313
  if not requests:
 
119
  r"without"
120
  r")\s+(?:as?\s+)?(?:ferramentas?|tools?)\b"
121
  )
122
+ OPENCLAUDE_METADATA_BLOCK_RE = re.compile(
123
+ r"<(?P<tag>available-deferred-tools|system-reminder)\b[^>]*>.*?</(?P=tag)>",
124
+ re.DOTALL | re.IGNORECASE,
125
+ )
126
 
127
 
128
  @dataclass(frozen=True)
 
162
  return "" if content is None else str(content)
163
 
164
 
165
+ def _user_request_text(content: Any) -> str:
166
+ """Remove OpenClaude's injected metadata before classifying user intent.
167
+
168
+ OpenClaude places deferred-tool lists, skill descriptions, and snip markers
169
+ inside a user-role message. Those blocks can contain words such as
170
+ ``create``, ``code``, or ``test``; treating them as the user's request can
171
+ incorrectly force ``tool_choice=required`` for a plain greeting.
172
+ """
173
+ text = _content_text(content)
174
+ previous = None
175
+ while text != previous:
176
+ previous = text
177
+ text = OPENCLAUDE_METADATA_BLOCK_RE.sub("", text)
178
+ return text.strip()
179
+
180
+
181
  def _call_arguments(value: Any) -> dict[str, Any]:
182
  if isinstance(value, Mapping):
183
  return dict(value)
 
327
  and str(message.get("role", "")).casefold() == "user"
328
  and not _is_synthetic_continuation(message)
329
  ):
330
+ text = _user_request_text(message.get("content"))
331
  if text:
332
  requests.append(text)
333
  if not requests:
test_openai_compat.py CHANGED
@@ -146,6 +146,27 @@ class OpenAICompatibilityTests(unittest.TestCase):
146
  self.assertFalse(state.active)
147
  self.assertEqual(resolve_tool_choice("required", state), "none")
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  def test_forced_tool_choice_is_case_insensitive_and_restrictive(self) -> None:
150
  tools, mode = select_tools(
151
  TOOLS,
 
146
  self.assertFalse(state.active)
147
  self.assertEqual(resolve_tool_choice("required", state), "none")
148
 
149
+ def test_openclaude_metadata_does_not_become_user_intent(self) -> None:
150
+ state = analyze_tool_flow(
151
+ [
152
+ {
153
+ "role": "user",
154
+ "content": (
155
+ "<available-deferred-tools>\nWebSearch\n"
156
+ "</available-deferred-tools>\n"
157
+ "<system-reminder>Use this skill to create code "
158
+ "and run tests.</system-reminder>\n"
159
+ "oi\n"
160
+ "<system-reminder>snip_id=abc</system-reminder>"
161
+ ),
162
+ }
163
+ ],
164
+ TOOLS,
165
+ )
166
+ self.assertFalse(state.active)
167
+ self.assertFalse(state.requires_tool)
168
+ self.assertEqual(resolve_tool_choice("required", state), "none")
169
+
170
  def test_forced_tool_choice_is_case_insensitive_and_restrictive(self) -> None:
171
  tools, mode = select_tools(
172
  TOOLS,