@miller-tech/uap 1.15.10 → 1.15.11
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
|
@@ -1134,6 +1134,28 @@ def _has_tool_definitions(anthropic_body: dict) -> bool:
|
|
|
1134
1134
|
return isinstance(tools, list) and len(tools) > 0
|
|
1135
1135
|
|
|
1136
1136
|
|
|
1137
|
+
def _should_use_guarded_non_stream(
|
|
1138
|
+
is_stream: bool,
|
|
1139
|
+
anthropic_body: dict,
|
|
1140
|
+
openai_body: dict,
|
|
1141
|
+
) -> bool:
|
|
1142
|
+
if not is_stream:
|
|
1143
|
+
return False
|
|
1144
|
+
|
|
1145
|
+
if PROXY_FORCE_NON_STREAM:
|
|
1146
|
+
return True
|
|
1147
|
+
|
|
1148
|
+
has_tools = _has_tool_definitions(anthropic_body)
|
|
1149
|
+
if PROXY_MALFORMED_TOOL_STREAM_STRICT and has_tools:
|
|
1150
|
+
return True
|
|
1151
|
+
|
|
1152
|
+
return (
|
|
1153
|
+
has_tools
|
|
1154
|
+
and openai_body.get("tool_choice") == "required"
|
|
1155
|
+
and (PROXY_MALFORMED_TOOL_GUARDRAIL or PROXY_GUARDRAIL_RETRY)
|
|
1156
|
+
)
|
|
1157
|
+
|
|
1158
|
+
|
|
1137
1159
|
def _message_has_tool_result(content) -> bool:
|
|
1138
1160
|
return isinstance(content, list) and any(
|
|
1139
1161
|
isinstance(block, dict) and block.get("type") == "tool_result"
|
|
@@ -3550,9 +3572,10 @@ async def messages(request: Request):
|
|
|
3550
3572
|
media_type="application/json",
|
|
3551
3573
|
)
|
|
3552
3574
|
|
|
3553
|
-
use_guarded_non_stream =
|
|
3554
|
-
|
|
3555
|
-
|
|
3575
|
+
use_guarded_non_stream = _should_use_guarded_non_stream(
|
|
3576
|
+
is_stream,
|
|
3577
|
+
body,
|
|
3578
|
+
openai_body,
|
|
3556
3579
|
)
|
|
3557
3580
|
if use_guarded_non_stream:
|
|
3558
3581
|
strict_body = dict(openai_body)
|
|
@@ -3623,10 +3646,14 @@ async def messages(request: Request):
|
|
|
3623
3646
|
logger.info(
|
|
3624
3647
|
"FORCED NON-STREAM: served stream response via guarded non-stream path"
|
|
3625
3648
|
)
|
|
3626
|
-
|
|
3649
|
+
elif PROXY_MALFORMED_TOOL_STREAM_STRICT and _has_tool_definitions(body):
|
|
3627
3650
|
logger.info(
|
|
3628
3651
|
"STRICT STREAM GUARDRAIL: served stream response via guarded non-stream path"
|
|
3629
3652
|
)
|
|
3653
|
+
else:
|
|
3654
|
+
logger.info(
|
|
3655
|
+
"REQUIRED TOOL STREAM GUARDRAIL: served stream response via guarded non-stream path"
|
|
3656
|
+
)
|
|
3630
3657
|
|
|
3631
3658
|
return StreamingResponse(
|
|
3632
3659
|
stream_anthropic_message(anthropic_resp),
|
|
@@ -100,6 +100,54 @@ class TestProxyConfigTuning(unittest.TestCase):
|
|
|
100
100
|
setattr(proxy, "PROXY_CONTEXT_PRUNE_TARGET_FRACTION", old_target)
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
class TestStreamGuardedPathSelection(unittest.TestCase):
|
|
104
|
+
def test_required_tool_turn_uses_guarded_non_stream(self):
|
|
105
|
+
old_force = getattr(proxy, "PROXY_FORCE_NON_STREAM")
|
|
106
|
+
old_strict = getattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT")
|
|
107
|
+
old_guard = getattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL")
|
|
108
|
+
old_retry = getattr(proxy, "PROXY_GUARDRAIL_RETRY")
|
|
109
|
+
try:
|
|
110
|
+
setattr(proxy, "PROXY_FORCE_NON_STREAM", False)
|
|
111
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT", False)
|
|
112
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL", True)
|
|
113
|
+
setattr(proxy, "PROXY_GUARDRAIL_RETRY", True)
|
|
114
|
+
|
|
115
|
+
selected = proxy._should_use_guarded_non_stream(
|
|
116
|
+
True,
|
|
117
|
+
{"tools": [{"name": "Read", "input_schema": {"type": "object"}}]},
|
|
118
|
+
{"tool_choice": "required"},
|
|
119
|
+
)
|
|
120
|
+
self.assertTrue(selected)
|
|
121
|
+
finally:
|
|
122
|
+
setattr(proxy, "PROXY_FORCE_NON_STREAM", old_force)
|
|
123
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT", old_strict)
|
|
124
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL", old_guard)
|
|
125
|
+
setattr(proxy, "PROXY_GUARDRAIL_RETRY", old_retry)
|
|
126
|
+
|
|
127
|
+
def test_auto_tool_turn_keeps_true_stream_when_strict_off(self):
|
|
128
|
+
old_force = getattr(proxy, "PROXY_FORCE_NON_STREAM")
|
|
129
|
+
old_strict = getattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT")
|
|
130
|
+
old_guard = getattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL")
|
|
131
|
+
old_retry = getattr(proxy, "PROXY_GUARDRAIL_RETRY")
|
|
132
|
+
try:
|
|
133
|
+
setattr(proxy, "PROXY_FORCE_NON_STREAM", False)
|
|
134
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT", False)
|
|
135
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL", True)
|
|
136
|
+
setattr(proxy, "PROXY_GUARDRAIL_RETRY", True)
|
|
137
|
+
|
|
138
|
+
selected = proxy._should_use_guarded_non_stream(
|
|
139
|
+
True,
|
|
140
|
+
{"tools": [{"name": "Read", "input_schema": {"type": "object"}}]},
|
|
141
|
+
{"tool_choice": "auto"},
|
|
142
|
+
)
|
|
143
|
+
self.assertFalse(selected)
|
|
144
|
+
finally:
|
|
145
|
+
setattr(proxy, "PROXY_FORCE_NON_STREAM", old_force)
|
|
146
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_STREAM_STRICT", old_strict)
|
|
147
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_GUARDRAIL", old_guard)
|
|
148
|
+
setattr(proxy, "PROXY_GUARDRAIL_RETRY", old_retry)
|
|
149
|
+
|
|
150
|
+
|
|
103
151
|
class TestMalformedToolGuardrail(unittest.TestCase):
|
|
104
152
|
def test_detects_malformed_tool_payload(self):
|
|
105
153
|
openai_resp = {
|