@miller-tech/uap 1.20.43 → 1.20.45
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
|
@@ -2472,8 +2472,21 @@ def _completion_blockers(
|
|
|
2472
2472
|
def _sanitize_tool_schema_for_llama(schema):
|
|
2473
2473
|
"""Remove JSON Schema keywords that generate unsupported regex grammar.
|
|
2474
2474
|
|
|
2475
|
-
llama.cpp's tool grammar generator can fail on regex-heavy schema fields
|
|
2476
|
-
|
|
2475
|
+
llama.cpp's tool grammar generator can fail on regex-heavy schema fields:
|
|
2476
|
+
|
|
2477
|
+
- "pattern" / "patternProperties" — regex strings (e.g. "\\w").
|
|
2478
|
+
- "format" — string formats. llama.cpp's json-schema-to-grammar turns
|
|
2479
|
+
"format": "date" / "date-time" / "time" / "uuid" into grammar rules
|
|
2480
|
+
built from `\\d`, which its own GBNF parser then rejects with
|
|
2481
|
+
`error parsing grammar: unknown escape at \\d...` → `failed to parse
|
|
2482
|
+
grammar`. Observed on MCP tools with date fields (Atlassian
|
|
2483
|
+
getJiraIssue, tempo bulkCreateWorklogs). "format" is an advisory
|
|
2484
|
+
annotation — dropping it just leaves the field as an unconstrained
|
|
2485
|
+
string in the tool-call grammar, which is correct behaviour.
|
|
2486
|
+
|
|
2487
|
+
All three are stripped only when they appear as schema *keywords*, not
|
|
2488
|
+
when they are property *names* (a tool may legitimately have a parameter
|
|
2489
|
+
literally called "pattern" or "format").
|
|
2477
2490
|
"""
|
|
2478
2491
|
|
|
2479
2492
|
removed = 0
|
|
@@ -2486,7 +2499,7 @@ def _sanitize_tool_schema_for_llama(schema):
|
|
|
2486
2499
|
for key, value in node.items():
|
|
2487
2500
|
key_is_property_name = parent_key in property_map_keys
|
|
2488
2501
|
if (
|
|
2489
|
-
key
|
|
2502
|
+
key in ("pattern", "format")
|
|
2490
2503
|
and isinstance(value, str)
|
|
2491
2504
|
and not key_is_property_name
|
|
2492
2505
|
):
|
|
@@ -8440,7 +8453,7 @@ async def models():
|
|
|
8440
8453
|
{"id": "claude-haiku-4-5-20251001", "object": "model"},
|
|
8441
8454
|
{"id": "claude-sonnet-4-6", "object": "model"},
|
|
8442
8455
|
{"id": "claude-opus-4-7", "object": "model"},
|
|
8443
|
-
{"id": "qwen36-
|
|
8456
|
+
{"id": "qwen36-35b-a3b-iq4xs", "object": "model"},
|
|
8444
8457
|
]
|
|
8445
8458
|
}
|
|
8446
8459
|
|
|
@@ -284,6 +284,79 @@ class TestToolSchemaSanitization(unittest.TestCase):
|
|
|
284
284
|
self.assertIn("pattern", params["required"])
|
|
285
285
|
self.assertEqual(params["properties"]["pattern"]["type"], "string")
|
|
286
286
|
|
|
287
|
+
def test_convert_tools_strips_format_fields(self):
|
|
288
|
+
"""A string field with "format": "date" must have format stripped.
|
|
289
|
+
llama.cpp's json-schema-to-grammar turns format:date/date-time/etc.
|
|
290
|
+
into `\\d`-based grammar rules that its own GBNF parser then rejects
|
|
291
|
+
('unknown escape at \\d' -> 'failed to parse grammar'). Observed on
|
|
292
|
+
MCP tools like tempo bulkCreateWorklogs (a worklogEntries[].date
|
|
293
|
+
field) and Atlassian getJiraIssue."""
|
|
294
|
+
anthropic_tools = [
|
|
295
|
+
{
|
|
296
|
+
"name": "bulkCreateWorklogs",
|
|
297
|
+
"description": "test",
|
|
298
|
+
"input_schema": {
|
|
299
|
+
"type": "object",
|
|
300
|
+
"properties": {
|
|
301
|
+
"worklogEntries": {
|
|
302
|
+
"type": "array",
|
|
303
|
+
"items": {
|
|
304
|
+
"type": "object",
|
|
305
|
+
"properties": {
|
|
306
|
+
"date": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"format": "date",
|
|
309
|
+
},
|
|
310
|
+
"started": {
|
|
311
|
+
"type": "string",
|
|
312
|
+
"format": "date-time",
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
converted = proxy._convert_anthropic_tools_to_openai(anthropic_tools)
|
|
323
|
+
item = converted[0]["function"]["parameters"]["properties"][
|
|
324
|
+
"worklogEntries"
|
|
325
|
+
]["items"]
|
|
326
|
+
self.assertNotIn("format", item["properties"]["date"])
|
|
327
|
+
self.assertNotIn("format", item["properties"]["started"])
|
|
328
|
+
# The field itself and its type survive — only the format hint goes.
|
|
329
|
+
self.assertEqual(item["properties"]["date"]["type"], "string")
|
|
330
|
+
|
|
331
|
+
def test_convert_tools_keeps_property_named_format(self):
|
|
332
|
+
"""A tool parameter literally named "format" (e.g. an output-format
|
|
333
|
+
selector) must NOT be stripped — only the format *keyword* is."""
|
|
334
|
+
anthropic_tools = [
|
|
335
|
+
{
|
|
336
|
+
"name": "ExportTool",
|
|
337
|
+
"description": "test",
|
|
338
|
+
"input_schema": {
|
|
339
|
+
"type": "object",
|
|
340
|
+
"required": ["format"],
|
|
341
|
+
"properties": {
|
|
342
|
+
"format": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"enum": ["json", "csv", "yaml"],
|
|
345
|
+
"description": "Output format",
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
converted = proxy._convert_anthropic_tools_to_openai(anthropic_tools)
|
|
353
|
+
params = converted[0]["function"]["parameters"]
|
|
354
|
+
self.assertIn("format", params["required"])
|
|
355
|
+
self.assertEqual(params["properties"]["format"]["type"], "string")
|
|
356
|
+
self.assertEqual(
|
|
357
|
+
params["properties"]["format"]["enum"], ["json", "csv", "yaml"]
|
|
358
|
+
)
|
|
359
|
+
|
|
287
360
|
|
|
288
361
|
class TestStreamGuardedPathSelection(unittest.TestCase):
|
|
289
362
|
def test_required_tool_turn_uses_guarded_non_stream(self):
|
|
@@ -5028,12 +5101,13 @@ class TestModelsEndpoint(unittest.TestCase):
|
|
|
5028
5101
|
self.assertIn("claude-sonnet-4-6", ids)
|
|
5029
5102
|
self.assertIn("claude-opus-4-7", ids)
|
|
5030
5103
|
|
|
5031
|
-
# Local model — what llama-server actually serves.
|
|
5032
|
-
#
|
|
5033
|
-
#
|
|
5034
|
-
# Requests for this ID route
|
|
5035
|
-
# passthrough sentinel set.
|
|
5036
|
-
self.assertIn("qwen36-
|
|
5104
|
+
# Local model — what llama-server actually serves. Tracks the
|
|
5105
|
+
# active model: qwen36-35b-a3b-iq4xs as of the 2026-05-17 switch
|
|
5106
|
+
# back to Qwen3.6-35B-A3B MoE from the 27B dense (see
|
|
5107
|
+
# project_active_server memory). Requests for this ID route
|
|
5108
|
+
# locally even with the __local_only__ passthrough sentinel set.
|
|
5109
|
+
self.assertIn("qwen36-35b-a3b-iq4xs", ids)
|
|
5110
|
+
self.assertNotIn("qwen36-27b-iq4xs", ids)
|
|
5037
5111
|
self.assertNotIn("qwen35-a3b-iq4xs", ids)
|
|
5038
5112
|
|
|
5039
5113
|
def test_models_endpoint_drops_stale_4_6_dated_variants(self):
|