@steve31415/baselib 3.29.0 → 3.30.0
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.
|
@@ -13,32 +13,35 @@ function classifyFinish(stopReason) {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Keywords
|
|
17
|
-
* Opus 5.5, 2026-09-22)
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Keywords Anthropic's constrained decoding rejects outright with a 400 —
|
|
17
|
+
* `output_config.format` (verified on Opus 5.5, 2026-09-22) and strict tools
|
|
18
|
+
* alike (verified on every forced-tool registry model, 2026-10-07). `minItems`
|
|
19
|
+
* is also rejected for values other than 0 or 1, handled separately;
|
|
20
|
+
* `minLength`/`maxLength`, `pattern`, `format` and nullable unions are
|
|
21
|
+
* accepted.
|
|
20
22
|
*/
|
|
21
|
-
const
|
|
23
|
+
const UNSUPPORTED_STRICT_KEYWORDS = [
|
|
22
24
|
'minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf',
|
|
23
25
|
'maxItems', 'uniqueItems',
|
|
24
26
|
];
|
|
25
27
|
/**
|
|
26
|
-
* Transform a portable JSON schema into the dialect Anthropic's
|
|
27
|
-
*
|
|
28
|
-
* `additionalProperties: false`, and the numeric/array
|
|
29
|
-
* dropped. The model then no longer enforces those
|
|
30
|
-
* the parsed result as they already must for
|
|
31
|
-
*
|
|
32
|
-
* caller's schema object is reused across
|
|
28
|
+
* Transform a portable JSON schema into the dialect Anthropic's constrained
|
|
29
|
+
* decoding accepts (`output_config.format` and `strict: true` tools): every
|
|
30
|
+
* object schema must set `additionalProperties: false`, and the numeric/array
|
|
31
|
+
* bounds listed above are dropped. The model then no longer enforces those
|
|
32
|
+
* bounds — callers validate the parsed result as they already must for
|
|
33
|
+
* truncation. Optional properties stay optional (unlike OpenAI's strict
|
|
34
|
+
* dialect). Returns a deep copy — the caller's schema object is reused across
|
|
35
|
+
* failover attempts.
|
|
33
36
|
*/
|
|
34
|
-
function
|
|
37
|
+
function toAnthropicStrictSchema(node) {
|
|
35
38
|
if (Array.isArray(node))
|
|
36
|
-
return node.map(
|
|
39
|
+
return node.map(toAnthropicStrictSchema);
|
|
37
40
|
if (node === null || typeof node !== 'object')
|
|
38
41
|
return node;
|
|
39
42
|
const out = {};
|
|
40
43
|
for (const [key, value] of Object.entries(node)) {
|
|
41
|
-
if (
|
|
44
|
+
if (UNSUPPORTED_STRICT_KEYWORDS.includes(key))
|
|
42
45
|
continue;
|
|
43
46
|
if (key === 'minItems' && typeof value === 'number' && value > 1)
|
|
44
47
|
continue;
|
|
@@ -46,10 +49,10 @@ function toOutputFormatSchema(node) {
|
|
|
46
49
|
// property that happens to be named `minimum` is kept.
|
|
47
50
|
if ((key === 'properties' || key === '$defs' || key === 'definitions')
|
|
48
51
|
&& value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
49
|
-
out[key] = Object.fromEntries(Object.entries(value).map(([k, v]) => [k,
|
|
52
|
+
out[key] = Object.fromEntries(Object.entries(value).map(([k, v]) => [k, toAnthropicStrictSchema(v)]));
|
|
50
53
|
continue;
|
|
51
54
|
}
|
|
52
|
-
out[key] =
|
|
55
|
+
out[key] = toAnthropicStrictSchema(value);
|
|
53
56
|
}
|
|
54
57
|
const type = out.type;
|
|
55
58
|
if (type === 'object' || (Array.isArray(type) && type.includes('object'))) {
|
|
@@ -87,20 +90,25 @@ export const anthropicProvider = {
|
|
|
87
90
|
? [{ type: 'text', text: request.systemPrompt, cache_control: { type: 'ephemeral' } }]
|
|
88
91
|
: request.systemPrompt;
|
|
89
92
|
}
|
|
90
|
-
// JSON schema: a forced tool_use call where the model allows it,
|
|
91
|
-
// structured outputs (Opus 5.5 rejects forced tool_choice).
|
|
93
|
+
// JSON schema: a forced, strict tool_use call where the model allows it,
|
|
94
|
+
// else structured outputs (Opus 5.5 rejects forced tool_choice). Both
|
|
95
|
+
// constrain decoding to the schema. A tool without `strict: true` is not
|
|
96
|
+
// enforced: Sonnet 5 returned an array property as a JSON string (digest,
|
|
97
|
+
// 2026-10-06), Opus 4.8 one wrapped in leaked tool-call markup (podcasts,
|
|
98
|
+
// 2026-09-15).
|
|
92
99
|
const useOutputFormat = request.jsonSchema !== undefined && !request.supportsForcedToolChoice;
|
|
93
100
|
if (request.jsonSchema && useOutputFormat) {
|
|
94
101
|
body.output_config = {
|
|
95
102
|
...body.output_config,
|
|
96
|
-
format: { type: 'json_schema', schema:
|
|
103
|
+
format: { type: 'json_schema', schema: toAnthropicStrictSchema(request.jsonSchema.schema) },
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
else if (request.jsonSchema) {
|
|
100
107
|
body.tools = [{
|
|
101
108
|
name: request.jsonSchema.name,
|
|
102
109
|
description: `Generate structured output matching the ${request.jsonSchema.name} schema`,
|
|
103
|
-
input_schema: request.jsonSchema.schema,
|
|
110
|
+
input_schema: toAnthropicStrictSchema(request.jsonSchema.schema),
|
|
111
|
+
strict: true,
|
|
104
112
|
}];
|
|
105
113
|
body.tool_choice = { type: 'tool', name: request.jsonSchema.name };
|
|
106
114
|
}
|
|
@@ -37,10 +37,10 @@ function makeNullable(propSchema) {
|
|
|
37
37
|
* Transform a portable JSON schema into the shape OpenAI's strict Structured
|
|
38
38
|
* Outputs mode requires: every object must set `additionalProperties: false`
|
|
39
39
|
* and list ALL of its properties in `required`. Callers author one portable
|
|
40
|
-
* schema
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* schema; this keeps the OpenAI-specific dialect local to this adapter,
|
|
41
|
+
* mirroring the Gemini adapter's `stripUnsupportedSchemaFields` and the
|
|
42
|
+
* Anthropic adapter's `toAnthropicStrictSchema` (which closes objects but keeps
|
|
43
|
+
* optional fields optional). Returns a deep copy — the
|
|
44
44
|
* caller's schema object is never mutated (it is reused across failover attempts).
|
|
45
45
|
*/
|
|
46
46
|
function toStrictSchema(node) {
|
package/package.json
CHANGED