@miller-tech/uap 1.20.44 → 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
|
):
|
|
@@ -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):
|