@miller-tech/uap 1.13.13 → 1.13.15
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/dist/.tsbuildinfo +1 -1
- package/dist/benchmarks/speculative-autotune.d.ts +46 -0
- package/dist/benchmarks/speculative-autotune.d.ts.map +1 -0
- package/dist/benchmarks/speculative-autotune.js +145 -0
- package/dist/benchmarks/speculative-autotune.js.map +1 -0
- package/dist/bin/cli.js +2 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/llama-server-optimize.js +176 -0
- package/dist/bin/llama-server-optimize.js.map +1 -1
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +18 -0
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1 -0
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/systemd-services.d.ts +12 -0
- package/dist/cli/systemd-services.d.ts.map +1 -0
- package/dist/cli/systemd-services.js +179 -0
- package/dist/cli/systemd-services.js.map +1 -0
- package/docs/INDEX.md +1 -0
- package/docs/benchmarks/SPECULATIVE_DECODING_JOURNEY_2026-03.md +221 -0
- package/docs/deployment/QWEN35_LLAMA_CPP.md +76 -0
- package/docs/deployment/UAP_LLAMA_ANTHROPIC_PROXY_BOOTSTRAP.md +279 -0
- package/package.json +1 -1
- package/tools/agents/scripts/anthropic_proxy.py +1444 -197
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +525 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _load_proxy_module():
|
|
9
|
+
proxy_path = Path(__file__).resolve().parents[1] / "scripts" / "anthropic_proxy.py"
|
|
10
|
+
spec = importlib.util.spec_from_file_location("anthropic_proxy", proxy_path)
|
|
11
|
+
assert spec is not None and spec.loader is not None
|
|
12
|
+
module = importlib.util.module_from_spec(spec)
|
|
13
|
+
spec.loader.exec_module(module)
|
|
14
|
+
return module
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
proxy = _load_proxy_module()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestStreamingReasoningFallback(unittest.TestCase):
|
|
21
|
+
def test_fallback_disabled_returns_none(self):
|
|
22
|
+
text = proxy._build_reasoning_fallback_text(
|
|
23
|
+
["<think>hidden</think>"], mode="off"
|
|
24
|
+
)
|
|
25
|
+
self.assertIsNone(text)
|
|
26
|
+
|
|
27
|
+
def test_visible_mode_returns_raw_text(self):
|
|
28
|
+
raw = '<think>internal</think> {"x":1}'
|
|
29
|
+
text = proxy._build_reasoning_fallback_text([raw], mode="visible")
|
|
30
|
+
self.assertEqual(text, raw)
|
|
31
|
+
|
|
32
|
+
def test_sanitized_mode_strips_think_tags(self):
|
|
33
|
+
text = proxy._build_reasoning_fallback_text(
|
|
34
|
+
["<think>plan</think>\n user visible output"], mode="sanitized"
|
|
35
|
+
)
|
|
36
|
+
self.assertEqual(text, "plan user visible output")
|
|
37
|
+
|
|
38
|
+
def test_sanitized_mode_truncates_long_text(self):
|
|
39
|
+
old_limit = getattr(proxy, "PROXY_STREAM_REASONING_MAX_CHARS")
|
|
40
|
+
setattr(proxy, "PROXY_STREAM_REASONING_MAX_CHARS", 12)
|
|
41
|
+
try:
|
|
42
|
+
text = proxy._build_reasoning_fallback_text(
|
|
43
|
+
["1234567890ABCDE"], mode="sanitized"
|
|
44
|
+
)
|
|
45
|
+
self.assertEqual(text, "1234567890AB...")
|
|
46
|
+
finally:
|
|
47
|
+
setattr(proxy, "PROXY_STREAM_REASONING_MAX_CHARS", old_limit)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestProxyConfigTuning(unittest.TestCase):
|
|
51
|
+
def test_max_tokens_floor_is_configurable(self):
|
|
52
|
+
old_floor = getattr(proxy, "PROXY_MAX_TOKENS_FLOOR")
|
|
53
|
+
setattr(proxy, "PROXY_MAX_TOKENS_FLOOR", 4096)
|
|
54
|
+
try:
|
|
55
|
+
self.assertEqual(proxy._resolve_max_tokens_request(400), 4096)
|
|
56
|
+
self.assertEqual(proxy._resolve_max_tokens_request(9000), 9000)
|
|
57
|
+
finally:
|
|
58
|
+
setattr(proxy, "PROXY_MAX_TOKENS_FLOOR", old_floor)
|
|
59
|
+
|
|
60
|
+
def test_max_tokens_floor_can_be_disabled(self):
|
|
61
|
+
old_floor = getattr(proxy, "PROXY_MAX_TOKENS_FLOOR")
|
|
62
|
+
setattr(proxy, "PROXY_MAX_TOKENS_FLOOR", 0)
|
|
63
|
+
try:
|
|
64
|
+
self.assertEqual(proxy._resolve_max_tokens_request(400), 400)
|
|
65
|
+
finally:
|
|
66
|
+
setattr(proxy, "PROXY_MAX_TOKENS_FLOOR", old_floor)
|
|
67
|
+
|
|
68
|
+
def test_prune_target_fraction_uses_config_or_default(self):
|
|
69
|
+
old_target = getattr(proxy, "PROXY_CONTEXT_PRUNE_TARGET_FRACTION")
|
|
70
|
+
try:
|
|
71
|
+
setattr(proxy, "PROXY_CONTEXT_PRUNE_TARGET_FRACTION", 0.55)
|
|
72
|
+
self.assertEqual(proxy._resolve_prune_target_fraction(), 0.55)
|
|
73
|
+
|
|
74
|
+
setattr(proxy, "PROXY_CONTEXT_PRUNE_TARGET_FRACTION", 1.2)
|
|
75
|
+
self.assertEqual(proxy._resolve_prune_target_fraction(), 0.65)
|
|
76
|
+
finally:
|
|
77
|
+
setattr(proxy, "PROXY_CONTEXT_PRUNE_TARGET_FRACTION", old_target)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class TestMalformedToolGuardrail(unittest.TestCase):
|
|
81
|
+
def test_detects_malformed_tool_payload(self):
|
|
82
|
+
openai_resp = {
|
|
83
|
+
"choices": [
|
|
84
|
+
{
|
|
85
|
+
"finish_reason": "stop",
|
|
86
|
+
"message": {
|
|
87
|
+
"content": (
|
|
88
|
+
'Analyzing lifecycle... </parameter> = {"description":"you MUST call a tool"}\n'
|
|
89
|
+
'</parameter> = {"description":"you MUST call a tool"}'
|
|
90
|
+
),
|
|
91
|
+
"tool_calls": [],
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
anthropic_body = {
|
|
97
|
+
"tools": [{"name": "Read", "input_schema": {"type": "object"}}],
|
|
98
|
+
"messages": [{"role": "user", "content": "fix this"}],
|
|
99
|
+
}
|
|
100
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
101
|
+
|
|
102
|
+
def test_detects_think_tag_with_repeated_policy_phrase(self):
|
|
103
|
+
openai_resp = {
|
|
104
|
+
"choices": [
|
|
105
|
+
{
|
|
106
|
+
"finish_reason": "stop",
|
|
107
|
+
"message": {
|
|
108
|
+
"content": (
|
|
109
|
+
"I have not yet fixed it, you MUST call a tool to make the fix.\n"
|
|
110
|
+
"</think>\n"
|
|
111
|
+
"I have not yet fixed it, you MUST call a tool to make the fix."
|
|
112
|
+
),
|
|
113
|
+
"tool_calls": [],
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
anthropic_body = {
|
|
119
|
+
"tools": [{"name": "Edit", "input_schema": {"type": "object"}}],
|
|
120
|
+
"messages": [{"role": "user", "content": "fix it"}],
|
|
121
|
+
}
|
|
122
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
123
|
+
|
|
124
|
+
def test_detects_policy_echo_loop_without_tags(self):
|
|
125
|
+
openai_resp = {
|
|
126
|
+
"choices": [
|
|
127
|
+
{
|
|
128
|
+
"finish_reason": "stop",
|
|
129
|
+
"message": {
|
|
130
|
+
"content": (
|
|
131
|
+
"You MUST call a tool to make the fix. "
|
|
132
|
+
"Do not summarize the issue and stop. "
|
|
133
|
+
"You MUST call a tool to make the fix."
|
|
134
|
+
),
|
|
135
|
+
"tool_calls": [],
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
anthropic_body = {
|
|
141
|
+
"tools": [{"name": "Edit", "input_schema": {"type": "object"}}],
|
|
142
|
+
"messages": [{"role": "user", "content": "fix it"}],
|
|
143
|
+
}
|
|
144
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
145
|
+
|
|
146
|
+
def test_detects_policy_snippet_echo(self):
|
|
147
|
+
openai_resp = {
|
|
148
|
+
"choices": [
|
|
149
|
+
{
|
|
150
|
+
"finish_reason": "stop",
|
|
151
|
+
"message": {
|
|
152
|
+
"content": (
|
|
153
|
+
"If you have identified a problem, keep going. "
|
|
154
|
+
"Do not summarize the issue and stop."
|
|
155
|
+
),
|
|
156
|
+
"tool_calls": [],
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
anthropic_body = {
|
|
162
|
+
"tools": [{"name": "Read", "input_schema": {"type": "object"}}],
|
|
163
|
+
"messages": [{"role": "user", "content": "continue"}],
|
|
164
|
+
}
|
|
165
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
166
|
+
|
|
167
|
+
def test_clean_tool_call_response_is_not_malformed(self):
|
|
168
|
+
openai_resp = {
|
|
169
|
+
"choices": [
|
|
170
|
+
{
|
|
171
|
+
"finish_reason": "tool_calls",
|
|
172
|
+
"message": {
|
|
173
|
+
"content": "",
|
|
174
|
+
"tool_calls": [
|
|
175
|
+
{
|
|
176
|
+
"id": "call_1",
|
|
177
|
+
"function": {
|
|
178
|
+
"name": "Read",
|
|
179
|
+
"arguments": '{"file_path":"README.md"}',
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
anthropic_body = {
|
|
188
|
+
"tools": [{"name": "Read", "input_schema": {"type": "object"}}],
|
|
189
|
+
"messages": [{"role": "user", "content": "read file"}],
|
|
190
|
+
}
|
|
191
|
+
self.assertFalse(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
192
|
+
|
|
193
|
+
def test_tool_call_missing_required_field_is_malformed(self):
|
|
194
|
+
openai_resp = {
|
|
195
|
+
"choices": [
|
|
196
|
+
{
|
|
197
|
+
"finish_reason": "tool_calls",
|
|
198
|
+
"message": {
|
|
199
|
+
"content": "",
|
|
200
|
+
"tool_calls": [
|
|
201
|
+
{
|
|
202
|
+
"id": "call_1",
|
|
203
|
+
"function": {
|
|
204
|
+
"name": "run_cmd",
|
|
205
|
+
"arguments": "{}",
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
anthropic_body = {
|
|
214
|
+
"tools": [
|
|
215
|
+
{
|
|
216
|
+
"name": "run_cmd",
|
|
217
|
+
"input_schema": {
|
|
218
|
+
"type": "object",
|
|
219
|
+
"properties": {"command": {"type": "string"}},
|
|
220
|
+
"required": ["command"],
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
"messages": [{"role": "user", "content": "run command"}],
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
228
|
+
|
|
229
|
+
def test_tool_call_wrong_argument_type_is_malformed(self):
|
|
230
|
+
openai_resp = {
|
|
231
|
+
"choices": [
|
|
232
|
+
{
|
|
233
|
+
"finish_reason": "tool_calls",
|
|
234
|
+
"message": {
|
|
235
|
+
"content": "",
|
|
236
|
+
"tool_calls": [
|
|
237
|
+
{
|
|
238
|
+
"id": "call_1",
|
|
239
|
+
"function": {
|
|
240
|
+
"name": "run_cmd",
|
|
241
|
+
"arguments": '{"command": 123}',
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
anthropic_body = {
|
|
250
|
+
"tools": [
|
|
251
|
+
{
|
|
252
|
+
"name": "run_cmd",
|
|
253
|
+
"input_schema": {
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {"command": {"type": "string"}},
|
|
256
|
+
"required": ["command"],
|
|
257
|
+
},
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
"messages": [{"role": "user", "content": "run command"}],
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
264
|
+
|
|
265
|
+
def test_tool_call_empty_required_string_is_malformed(self):
|
|
266
|
+
openai_resp = {
|
|
267
|
+
"choices": [
|
|
268
|
+
{
|
|
269
|
+
"finish_reason": "tool_calls",
|
|
270
|
+
"message": {
|
|
271
|
+
"content": "",
|
|
272
|
+
"tool_calls": [
|
|
273
|
+
{
|
|
274
|
+
"id": "call_1",
|
|
275
|
+
"function": {
|
|
276
|
+
"name": "run_cmd",
|
|
277
|
+
"arguments": '{"command": ""}',
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
anthropic_body = {
|
|
286
|
+
"tools": [
|
|
287
|
+
{
|
|
288
|
+
"name": "run_cmd",
|
|
289
|
+
"input_schema": {
|
|
290
|
+
"type": "object",
|
|
291
|
+
"properties": {"command": {"type": "string"}},
|
|
292
|
+
"required": ["command"],
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
],
|
|
296
|
+
"messages": [{"role": "user", "content": "run command"}],
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
300
|
+
|
|
301
|
+
def test_tool_call_required_string_with_markup_is_malformed(self):
|
|
302
|
+
openai_resp = {
|
|
303
|
+
"choices": [
|
|
304
|
+
{
|
|
305
|
+
"finish_reason": "tool_calls",
|
|
306
|
+
"message": {
|
|
307
|
+
"content": "",
|
|
308
|
+
"tool_calls": [
|
|
309
|
+
{
|
|
310
|
+
"id": "call_1",
|
|
311
|
+
"function": {
|
|
312
|
+
"name": "run_cmd",
|
|
313
|
+
"arguments": '{"command": "</parameter> injected"}',
|
|
314
|
+
},
|
|
315
|
+
}
|
|
316
|
+
],
|
|
317
|
+
},
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
anthropic_body = {
|
|
322
|
+
"tools": [
|
|
323
|
+
{
|
|
324
|
+
"name": "run_cmd",
|
|
325
|
+
"input_schema": {
|
|
326
|
+
"type": "object",
|
|
327
|
+
"properties": {"command": {"type": "string"}},
|
|
328
|
+
"required": ["command"],
|
|
329
|
+
},
|
|
330
|
+
}
|
|
331
|
+
],
|
|
332
|
+
"messages": [{"role": "user", "content": "run command"}],
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
336
|
+
|
|
337
|
+
def test_tool_call_optional_string_with_markup_is_malformed(self):
|
|
338
|
+
openai_resp = {
|
|
339
|
+
"choices": [
|
|
340
|
+
{
|
|
341
|
+
"finish_reason": "tool_calls",
|
|
342
|
+
"message": {
|
|
343
|
+
"content": "",
|
|
344
|
+
"tool_calls": [
|
|
345
|
+
{
|
|
346
|
+
"id": "call_1",
|
|
347
|
+
"function": {
|
|
348
|
+
"name": "run_cmd",
|
|
349
|
+
"arguments": '{"command": "echo ok", "note": "<tool_call>bad</tool_call>"}',
|
|
350
|
+
},
|
|
351
|
+
}
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
}
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
anthropic_body = {
|
|
358
|
+
"tools": [
|
|
359
|
+
{
|
|
360
|
+
"name": "run_cmd",
|
|
361
|
+
"input_schema": {
|
|
362
|
+
"type": "object",
|
|
363
|
+
"properties": {
|
|
364
|
+
"command": {"type": "string"},
|
|
365
|
+
"note": {"type": "string"},
|
|
366
|
+
},
|
|
367
|
+
"required": ["command"],
|
|
368
|
+
},
|
|
369
|
+
}
|
|
370
|
+
],
|
|
371
|
+
"messages": [{"role": "user", "content": "run command"}],
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
self.assertTrue(proxy._is_malformed_tool_response(openai_resp, anthropic_body))
|
|
375
|
+
|
|
376
|
+
def test_malformed_retry_body_restores_full_tools_and_caps_tokens(self):
|
|
377
|
+
old_cap = getattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_MAX_TOKENS")
|
|
378
|
+
old_temp = getattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_TEMPERATURE")
|
|
379
|
+
old_disable = getattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS")
|
|
380
|
+
try:
|
|
381
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_MAX_TOKENS", 512)
|
|
382
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_TEMPERATURE", 0)
|
|
383
|
+
setattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS", True)
|
|
384
|
+
|
|
385
|
+
openai_body = {
|
|
386
|
+
"model": "test",
|
|
387
|
+
"max_tokens": 4000,
|
|
388
|
+
"tools": [{"type": "function", "function": {"name": "Read"}}],
|
|
389
|
+
}
|
|
390
|
+
anthropic_body = {
|
|
391
|
+
"tools": [
|
|
392
|
+
{"name": "Read", "input_schema": {"type": "object"}},
|
|
393
|
+
{"name": "Edit", "input_schema": {"type": "object"}},
|
|
394
|
+
{"name": "Write", "input_schema": {"type": "object"}},
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
retry = proxy._build_malformed_retry_body(openai_body, anthropic_body)
|
|
399
|
+
self.assertEqual(retry["stream"], False)
|
|
400
|
+
self.assertEqual(retry["tool_choice"], "required")
|
|
401
|
+
self.assertEqual(retry["temperature"], 0)
|
|
402
|
+
self.assertEqual(retry["max_tokens"], 512)
|
|
403
|
+
self.assertEqual(len(retry["tools"]), 3)
|
|
404
|
+
self.assertFalse(retry["enable_thinking"])
|
|
405
|
+
finally:
|
|
406
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_MAX_TOKENS", old_cap)
|
|
407
|
+
setattr(proxy, "PROXY_MALFORMED_TOOL_RETRY_TEMPERATURE", old_temp)
|
|
408
|
+
setattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS", old_disable)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class TestToolTurnControls(unittest.TestCase):
|
|
412
|
+
def test_tool_narrowing_reduces_tool_count(self):
|
|
413
|
+
old_narrow = getattr(proxy, "PROXY_TOOL_NARROWING")
|
|
414
|
+
old_keep = getattr(proxy, "PROXY_TOOL_NARROWING_KEEP")
|
|
415
|
+
old_min = getattr(proxy, "PROXY_TOOL_NARROWING_MIN_TOOLS")
|
|
416
|
+
try:
|
|
417
|
+
setattr(proxy, "PROXY_TOOL_NARROWING", True)
|
|
418
|
+
setattr(proxy, "PROXY_TOOL_NARROWING_KEEP", 2)
|
|
419
|
+
setattr(proxy, "PROXY_TOOL_NARROWING_MIN_TOOLS", 3)
|
|
420
|
+
|
|
421
|
+
body = {
|
|
422
|
+
"model": "test",
|
|
423
|
+
"messages": [
|
|
424
|
+
{
|
|
425
|
+
"role": "user",
|
|
426
|
+
"content": "run tests and fix the failing test quickly",
|
|
427
|
+
}
|
|
428
|
+
],
|
|
429
|
+
"tools": [
|
|
430
|
+
{
|
|
431
|
+
"name": "Read",
|
|
432
|
+
"description": "Read file",
|
|
433
|
+
"input_schema": {"type": "object"},
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"name": "Edit",
|
|
437
|
+
"description": "Edit file",
|
|
438
|
+
"input_schema": {"type": "object"},
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
"name": "RunTests",
|
|
442
|
+
"description": "Run unit tests",
|
|
443
|
+
"input_schema": {"type": "object"},
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"name": "Deploy",
|
|
447
|
+
"description": "Deploy app",
|
|
448
|
+
"input_schema": {"type": "object"},
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
}
|
|
452
|
+
openai = proxy.build_openai_request(
|
|
453
|
+
body, proxy.SessionMonitor(context_window=262144)
|
|
454
|
+
)
|
|
455
|
+
self.assertEqual(len(openai.get("tools", [])), 2)
|
|
456
|
+
names = [t.get("function", {}).get("name") for t in openai.get("tools", [])]
|
|
457
|
+
self.assertIn("RunTests", names)
|
|
458
|
+
finally:
|
|
459
|
+
setattr(proxy, "PROXY_TOOL_NARROWING", old_narrow)
|
|
460
|
+
setattr(proxy, "PROXY_TOOL_NARROWING_KEEP", old_keep)
|
|
461
|
+
setattr(proxy, "PROXY_TOOL_NARROWING_MIN_TOOLS", old_min)
|
|
462
|
+
|
|
463
|
+
def test_disable_thinking_flag_sets_enable_thinking_false(self):
|
|
464
|
+
old_disable = getattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS")
|
|
465
|
+
try:
|
|
466
|
+
setattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS", True)
|
|
467
|
+
body = {
|
|
468
|
+
"model": "test",
|
|
469
|
+
"messages": [{"role": "user", "content": "use tool"}],
|
|
470
|
+
"tools": [
|
|
471
|
+
{
|
|
472
|
+
"name": "Read",
|
|
473
|
+
"description": "Read file",
|
|
474
|
+
"input_schema": {"type": "object"},
|
|
475
|
+
}
|
|
476
|
+
],
|
|
477
|
+
}
|
|
478
|
+
openai = proxy.build_openai_request(
|
|
479
|
+
body, proxy.SessionMonitor(context_window=262144)
|
|
480
|
+
)
|
|
481
|
+
self.assertIn("enable_thinking", openai)
|
|
482
|
+
self.assertFalse(openai["enable_thinking"])
|
|
483
|
+
finally:
|
|
484
|
+
setattr(proxy, "PROXY_DISABLE_THINKING_ON_TOOL_TURNS", old_disable)
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
class TestSessionContaminationBreaker(unittest.TestCase):
|
|
488
|
+
def test_contamination_breaker_trims_and_resets_streak(self):
|
|
489
|
+
old_enabled = getattr(proxy, "PROXY_SESSION_CONTAMINATION_BREAKER")
|
|
490
|
+
old_threshold = getattr(proxy, "PROXY_SESSION_CONTAMINATION_THRESHOLD")
|
|
491
|
+
old_keep = getattr(proxy, "PROXY_SESSION_CONTAMINATION_KEEP_LAST")
|
|
492
|
+
try:
|
|
493
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_BREAKER", True)
|
|
494
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_THRESHOLD", 2)
|
|
495
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_KEEP_LAST", 3)
|
|
496
|
+
|
|
497
|
+
monitor = proxy.SessionMonitor(context_window=262144)
|
|
498
|
+
monitor.malformed_tool_streak = 2
|
|
499
|
+
body = {
|
|
500
|
+
"messages": [
|
|
501
|
+
{"role": "user", "content": "start"},
|
|
502
|
+
{"role": "assistant", "content": "a1"},
|
|
503
|
+
{"role": "user", "content": "u2"},
|
|
504
|
+
{"role": "assistant", "content": "a3"},
|
|
505
|
+
{"role": "user", "content": "u4"},
|
|
506
|
+
{"role": "assistant", "content": "a5"},
|
|
507
|
+
]
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
updated = proxy._maybe_apply_session_contamination_breaker(
|
|
511
|
+
body, monitor, "session-test"
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
self.assertEqual(monitor.malformed_tool_streak, 0)
|
|
515
|
+
self.assertEqual(monitor.contamination_resets, 1)
|
|
516
|
+
self.assertEqual(len(updated["messages"]), 5)
|
|
517
|
+
self.assertIn("SESSION RESET", updated["messages"][1]["content"])
|
|
518
|
+
finally:
|
|
519
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_BREAKER", old_enabled)
|
|
520
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_THRESHOLD", old_threshold)
|
|
521
|
+
setattr(proxy, "PROXY_SESSION_CONTAMINATION_KEEP_LAST", old_keep)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
if __name__ == "__main__":
|
|
525
|
+
unittest.main()
|