Spaces:
Running on Zero
Running on Zero
miau commited on
Commit ·
88e4b2b
1
Parent(s): 2b105f8
Ignore OpenClaude metadata when detecting user intent
Browse files- openai_compat.py +21 -1
- 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 =
|
| 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,
|