@miller-tech/uap 1.15.3 → 1.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1789,6 +1789,7 @@ _TOOL_ARG_MARKERS = (
|
|
|
1789
1789
|
"<tool_call",
|
|
1790
1790
|
"</tool_call",
|
|
1791
1791
|
"<function=",
|
|
1792
|
+
"</function",
|
|
1792
1793
|
"</think>",
|
|
1793
1794
|
)
|
|
1794
1795
|
|
|
@@ -1817,6 +1818,7 @@ def _strip_tool_markup_artifacts(text: str) -> str:
|
|
|
1817
1818
|
cleaned = re.sub(r"</?tool_call[^>]*>", "", cleaned, flags=re.IGNORECASE)
|
|
1818
1819
|
cleaned = re.sub(r"</?think>", "", cleaned, flags=re.IGNORECASE)
|
|
1819
1820
|
cleaned = re.sub(r"<function=[^>]*>", "", cleaned, flags=re.IGNORECASE)
|
|
1821
|
+
cleaned = re.sub(r"</function>", "", cleaned, flags=re.IGNORECASE)
|
|
1820
1822
|
return cleaned.strip()
|
|
1821
1823
|
|
|
1822
1824
|
|
|
@@ -2284,7 +2286,13 @@ def _looks_malformed_tool_payload(text: str) -> bool:
|
|
|
2284
2286
|
if _contains_tool_call_apology(text):
|
|
2285
2287
|
return True
|
|
2286
2288
|
|
|
2287
|
-
primary_markers = (
|
|
2289
|
+
primary_markers = (
|
|
2290
|
+
"</parameter",
|
|
2291
|
+
"<parameter",
|
|
2292
|
+
"<tool_call",
|
|
2293
|
+
"<function=",
|
|
2294
|
+
"</function",
|
|
2295
|
+
)
|
|
2288
2296
|
if any(marker in lowered for marker in primary_markers):
|
|
2289
2297
|
return True
|
|
2290
2298
|
|
|
@@ -122,6 +122,28 @@ class TestMalformedToolGuardrail(unittest.TestCase):
|
|
|
122
122
|
}
|
|
123
123
|
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
124
124
|
|
|
125
|
+
def test_detects_closing_function_tag_payload(self):
|
|
126
|
+
openai_resp = {
|
|
127
|
+
"choices": [
|
|
128
|
+
{
|
|
129
|
+
"finish_reason": "stop",
|
|
130
|
+
"message": {
|
|
131
|
+
"content": (
|
|
132
|
+
"Bash(find /home/cogtek/dev/miller-tech/universal-agent-protocol -maxdepth 1 "
|
|
133
|
+
'\\( -type f -name "*.md" -o -type f -name "*.json" \\)\n'
|
|
134
|
+
"</function>"
|
|
135
|
+
),
|
|
136
|
+
"tool_calls": [],
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
anthropic_body = {
|
|
142
|
+
"tools": [{"name": "Bash", "input_schema": {"type": "object"}}],
|
|
143
|
+
"messages": [{"role": "user", "content": "list root docs/json files"}],
|
|
144
|
+
}
|
|
145
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
146
|
+
|
|
125
147
|
def test_detects_think_tag_with_repeated_policy_phrase(self):
|
|
126
148
|
openai_resp = {
|
|
127
149
|
"choices": [
|
|
@@ -611,6 +633,39 @@ class TestMalformedToolGuardrail(unittest.TestCase):
|
|
|
611
633
|
self.assertEqual(issue.kind, "malformed_payload")
|
|
612
634
|
self.assertIn("malformed pseudo tool payload", issue.reason)
|
|
613
635
|
|
|
636
|
+
def test_preflight_flags_closing_function_tag_inside_arguments(self):
|
|
637
|
+
old_preflight = getattr(proxy, "PROXY_TOOL_ARGS_PREFLIGHT")
|
|
638
|
+
try:
|
|
639
|
+
setattr(proxy, "PROXY_TOOL_ARGS_PREFLIGHT", True)
|
|
640
|
+
openai_resp = {
|
|
641
|
+
"choices": [
|
|
642
|
+
{
|
|
643
|
+
"finish_reason": "tool_calls",
|
|
644
|
+
"message": {
|
|
645
|
+
"content": "",
|
|
646
|
+
"tool_calls": [
|
|
647
|
+
{
|
|
648
|
+
"id": "call_1",
|
|
649
|
+
"function": {
|
|
650
|
+
"name": "Bash",
|
|
651
|
+
"arguments": '{"command":"pwd\\n</function>"}',
|
|
652
|
+
},
|
|
653
|
+
}
|
|
654
|
+
],
|
|
655
|
+
},
|
|
656
|
+
}
|
|
657
|
+
]
|
|
658
|
+
}
|
|
659
|
+
anthropic_body = {
|
|
660
|
+
"tools": [{"name": "Bash", "input_schema": {"type": "object"}}]
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
issue = proxy._classify_tool_response_issue(openai_resp, anthropic_body)
|
|
664
|
+
self.assertEqual(issue.kind, "invalid_tool_args")
|
|
665
|
+
self.assertIn("malformed markup fragments", issue.reason)
|
|
666
|
+
finally:
|
|
667
|
+
setattr(proxy, "PROXY_TOOL_ARGS_PREFLIGHT", old_preflight)
|
|
668
|
+
|
|
614
669
|
def test_required_tool_turn_without_tool_call_is_flagged(self):
|
|
615
670
|
openai_resp = {
|
|
616
671
|
"choices": [
|
|
@@ -661,6 +716,34 @@ class TestMalformedToolGuardrail(unittest.TestCase):
|
|
|
661
716
|
self.assertNotIn("</think>", args)
|
|
662
717
|
self.assertNotIn("</parameter>", args)
|
|
663
718
|
|
|
719
|
+
def test_markup_repair_strips_closing_function_tag(self):
|
|
720
|
+
openai_resp = {
|
|
721
|
+
"choices": [
|
|
722
|
+
{
|
|
723
|
+
"finish_reason": "tool_calls",
|
|
724
|
+
"message": {
|
|
725
|
+
"content": "",
|
|
726
|
+
"tool_calls": [
|
|
727
|
+
{
|
|
728
|
+
"id": "call_1",
|
|
729
|
+
"function": {
|
|
730
|
+
"name": "Bash",
|
|
731
|
+
"arguments": '{"command":"pwd\\n</function>"}',
|
|
732
|
+
},
|
|
733
|
+
}
|
|
734
|
+
],
|
|
735
|
+
},
|
|
736
|
+
}
|
|
737
|
+
]
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
repaired, count = proxy._repair_tool_call_markup(openai_resp)
|
|
741
|
+
self.assertEqual(count, 1)
|
|
742
|
+
args = json.loads(
|
|
743
|
+
repaired["choices"][0]["message"]["tool_calls"][0]["function"]["arguments"]
|
|
744
|
+
)
|
|
745
|
+
self.assertEqual(args["command"], "pwd")
|
|
746
|
+
|
|
664
747
|
def test_markup_repair_recovers_json_after_tag_stripping(self):
|
|
665
748
|
openai_resp = {
|
|
666
749
|
"choices": [
|