nuabase 2.3.7 → 2.3.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/CHANGELOG.md +26 -0
- package/dist/cjs/chunks/{logger-Co5uZG0A.cjs → strict-json-schema-DUE7RTxG.cjs} +87 -0
- package/dist/cjs/index.cjs +47 -14
- package/dist/cjs/local-agent.cjs +4 -90
- package/dist/esm/chunks/{logger-DnkHzkX_.mjs → strict-json-schema-DI9qiH5h.mjs} +87 -1
- package/dist/esm/index.mjs +44 -11
- package/dist/esm/local-agent.mjs +1 -87
- package/dist/types/nua-llm-core/modules/engine/http/http-engine.d.ts +3 -2
- package/dist/types/nua-llm-core/modules/engine/http/provider-config.d.ts +5 -0
- package/package.json +3 -10
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# nuabase
|
|
2
|
+
|
|
3
|
+
## 2.3.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Ship the changelog in the npm package
|
|
8
|
+
|
|
9
|
+
## 2.3.10
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 0303881: The "fast" model alias now uses `openai/gpt-oss-120b` on Groq instead of the preview `qwen/qwen3.8-27b`. On Groq models that support strict structured outputs, casts now enforce the output schema natively instead of describing it in the prompt.
|
|
14
|
+
|
|
15
|
+
## 2.3.9
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Format the release script with Prettier
|
|
20
|
+
|
|
21
|
+
## 2.3.8
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Publish the packed tarball with npm, so 2FA is approved in the browser
|
|
26
|
+
Release nuabase through changesets and the release train
|
|
@@ -87,4 +87,91 @@ function requireLogger() {
|
|
|
87
87
|
return logger;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
var strictJsonSchema = {};
|
|
91
|
+
|
|
92
|
+
var hasRequiredStrictJsonSchema;
|
|
93
|
+
function requireStrictJsonSchema() {
|
|
94
|
+
if (hasRequiredStrictJsonSchema) return strictJsonSchema;
|
|
95
|
+
hasRequiredStrictJsonSchema = 1;
|
|
96
|
+
Object.defineProperty(strictJsonSchema, "__esModule", { value: true });
|
|
97
|
+
strictJsonSchema.toStrictSchema = toStrictSchema;
|
|
98
|
+
const STRICT_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
99
|
+
"patternProperties",
|
|
100
|
+
"propertyNames",
|
|
101
|
+
"unevaluatedProperties",
|
|
102
|
+
"dependentRequired",
|
|
103
|
+
"dependentSchemas",
|
|
104
|
+
"if",
|
|
105
|
+
"then",
|
|
106
|
+
"else",
|
|
107
|
+
"not",
|
|
108
|
+
"allOf",
|
|
109
|
+
"oneOf"
|
|
110
|
+
]);
|
|
111
|
+
function toStrictSchema(schema) {
|
|
112
|
+
return strictNode(schema);
|
|
113
|
+
}
|
|
114
|
+
function strictNode(node) {
|
|
115
|
+
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const schema = node;
|
|
119
|
+
for (const key of Object.keys(schema)) {
|
|
120
|
+
if (STRICT_UNSUPPORTED_KEYWORDS.has(key))
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const result = { ...schema };
|
|
124
|
+
delete result.$schema;
|
|
125
|
+
const isObject = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.properties !== void 0;
|
|
126
|
+
if (isObject) {
|
|
127
|
+
const properties = schema.properties ?? {};
|
|
128
|
+
if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const required = new Set(schema.required ?? []);
|
|
132
|
+
const shapedProperties = {};
|
|
133
|
+
for (const [name, child] of Object.entries(properties)) {
|
|
134
|
+
if (!required.has(name))
|
|
135
|
+
return null;
|
|
136
|
+
const shaped = strictNode(child);
|
|
137
|
+
if (!shaped)
|
|
138
|
+
return null;
|
|
139
|
+
shapedProperties[name] = shaped;
|
|
140
|
+
}
|
|
141
|
+
result.properties = shapedProperties;
|
|
142
|
+
result.required = Object.keys(shapedProperties);
|
|
143
|
+
result.additionalProperties = false;
|
|
144
|
+
}
|
|
145
|
+
if (schema.items !== void 0) {
|
|
146
|
+
const shaped = strictNode(schema.items);
|
|
147
|
+
if (!shaped)
|
|
148
|
+
return null;
|
|
149
|
+
result.items = shaped;
|
|
150
|
+
}
|
|
151
|
+
if (schema.prefixItems !== void 0)
|
|
152
|
+
return null;
|
|
153
|
+
if (schema.anyOf !== void 0) {
|
|
154
|
+
const variants = schema.anyOf.map(strictNode);
|
|
155
|
+
if (variants.some((v) => v === null))
|
|
156
|
+
return null;
|
|
157
|
+
result.anyOf = variants;
|
|
158
|
+
}
|
|
159
|
+
for (const defsKey of ["$defs", "definitions"]) {
|
|
160
|
+
if (schema[defsKey] !== void 0) {
|
|
161
|
+
const defs = {};
|
|
162
|
+
for (const [name, child] of Object.entries(schema[defsKey])) {
|
|
163
|
+
const shaped = strictNode(child);
|
|
164
|
+
if (!shaped)
|
|
165
|
+
return null;
|
|
166
|
+
defs[name] = shaped;
|
|
167
|
+
}
|
|
168
|
+
result[defsKey] = defs;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
return strictJsonSchema;
|
|
174
|
+
}
|
|
175
|
+
|
|
90
176
|
exports.requireLogger = requireLogger;
|
|
177
|
+
exports.requireStrictJsonSchema = requireStrictJsonSchema;
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var strictJsonSchema = require('./chunks/strict-json-schema-DUE7RTxG.cjs');
|
|
4
4
|
var zod = require('zod');
|
|
5
5
|
|
|
6
6
|
var dist = {};
|
|
@@ -9841,7 +9841,7 @@ function requireProviderConfig() {
|
|
|
9841
9841
|
};
|
|
9842
9842
|
};
|
|
9843
9843
|
exports$1.normalizeGeminiUsage = normalizeGeminiUsage;
|
|
9844
|
-
const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt }, apiKey) => {
|
|
9844
|
+
const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt, responseSchema }, apiKey) => {
|
|
9845
9845
|
const messages = [];
|
|
9846
9846
|
messages.push({ role: "user", content: prompt });
|
|
9847
9847
|
if (assistantPrefillPrompt) {
|
|
@@ -9854,7 +9854,13 @@ function requireProviderConfig() {
|
|
|
9854
9854
|
max_completion_tokens: maxTokens,
|
|
9855
9855
|
top_p: 1,
|
|
9856
9856
|
stream: false,
|
|
9857
|
-
stop: null
|
|
9857
|
+
stop: null,
|
|
9858
|
+
...responseSchema && {
|
|
9859
|
+
response_format: {
|
|
9860
|
+
type: "json_schema",
|
|
9861
|
+
json_schema: { name: "response", strict: true, schema: responseSchema }
|
|
9862
|
+
}
|
|
9863
|
+
}
|
|
9858
9864
|
};
|
|
9859
9865
|
const headers = {
|
|
9860
9866
|
"Content-Type": "application/json",
|
|
@@ -9981,6 +9987,12 @@ function requireProviderConfig() {
|
|
|
9981
9987
|
providerId: "groq",
|
|
9982
9988
|
apiOperation: "chat/completions",
|
|
9983
9989
|
errorLabel: "Groq",
|
|
9990
|
+
// https://console.groq.com/docs/structured-outputs
|
|
9991
|
+
strictSchemaModels: /* @__PURE__ */ new Set([
|
|
9992
|
+
"openai/gpt-oss-120b",
|
|
9993
|
+
"openai/gpt-oss-20b",
|
|
9994
|
+
"qwen/qwen3.8-27b"
|
|
9995
|
+
]),
|
|
9984
9996
|
buildRequest: buildOpenAiStyleRequest("https://api.groq.com/openai/v1/chat/completions"),
|
|
9985
9997
|
parseResponse: parseOpenAiStyleResponse("Groq")
|
|
9986
9998
|
},
|
|
@@ -10028,7 +10040,7 @@ function requireModelInfo() {
|
|
|
10028
10040
|
exports$1.MODEL_ALIASES = {
|
|
10029
10041
|
fast: [
|
|
10030
10042
|
{ provider: "cerebras", model: "qwen-3.8-27b" },
|
|
10031
|
-
{ provider: "groq", model: "
|
|
10043
|
+
{ provider: "groq", model: "openai/gpt-oss-120b" },
|
|
10032
10044
|
{ provider: "openrouter", model: "z-ai/glm-5.2" }
|
|
10033
10045
|
],
|
|
10034
10046
|
gemini: [
|
|
@@ -10128,7 +10140,7 @@ function requireProviderCall() {
|
|
|
10128
10140
|
hasRequiredProviderCall = 1;
|
|
10129
10141
|
Object.defineProperty(providerCall, "__esModule", { value: true });
|
|
10130
10142
|
providerCall.callProvider = callProvider;
|
|
10131
|
-
const logger_1 =
|
|
10143
|
+
const logger_1 = strictJsonSchema.requireLogger();
|
|
10132
10144
|
const provider_config_1 = requireProviderConfig();
|
|
10133
10145
|
async function callProvider(call, logger) {
|
|
10134
10146
|
const { target, apiOperation, request } = call;
|
|
@@ -10181,6 +10193,7 @@ function requireHttpEngine() {
|
|
|
10181
10193
|
hasRequiredHttpEngine = 1;
|
|
10182
10194
|
Object.defineProperty(httpEngine, "__esModule", { value: true });
|
|
10183
10195
|
httpEngine.HttpEngine = void 0;
|
|
10196
|
+
const strict_json_schema_1 = strictJsonSchema.requireStrictJsonSchema();
|
|
10184
10197
|
const provider_call_1 = requireProviderCall();
|
|
10185
10198
|
const provider_config_1 = requireProviderConfig();
|
|
10186
10199
|
const FATAL_HTTP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404]);
|
|
@@ -10189,35 +10202,55 @@ function requireHttpEngine() {
|
|
|
10189
10202
|
this.target = target;
|
|
10190
10203
|
this.logger = logger;
|
|
10191
10204
|
}
|
|
10192
|
-
/**
|
|
10193
|
-
nativeSchema() {
|
|
10194
|
-
|
|
10205
|
+
/** Enforced in strict mode on models whose provider supports it; other models get the schema in the prompt. */
|
|
10206
|
+
nativeSchema(envelopeSchema) {
|
|
10207
|
+
const { provider, model } = this.target;
|
|
10208
|
+
if (!provider_config_1.providerConfigs[provider].strictSchemaModels?.has(model))
|
|
10209
|
+
return null;
|
|
10210
|
+
return (0, strict_json_schema_1.toStrictSchema)(envelopeSchema);
|
|
10195
10211
|
}
|
|
10196
10212
|
async attempt(request) {
|
|
10197
10213
|
const { provider, model, apiKey } = this.target;
|
|
10198
10214
|
const config = provider_config_1.providerConfigs[provider];
|
|
10215
|
+
const responseSchema = request.enforcement.kind === "native" ? request.enforcement.schema : void 0;
|
|
10199
10216
|
const call = await (0, provider_call_1.callProvider)({
|
|
10200
10217
|
target: this.target,
|
|
10201
10218
|
apiOperation: config.apiOperation,
|
|
10202
10219
|
maxTokens: request.maxTokens,
|
|
10203
|
-
request: config.buildRequest({ prompt: request.prompt, model, maxTokens: request.maxTokens }, apiKey),
|
|
10220
|
+
request: config.buildRequest({ prompt: request.prompt, model, maxTokens: request.maxTokens, responseSchema }, apiKey),
|
|
10204
10221
|
parseResponse: config.parseResponse,
|
|
10205
10222
|
responseLength: (reply) => reply.text.length,
|
|
10206
10223
|
usage: (reply) => reply.usage
|
|
10207
10224
|
}, this.logger);
|
|
10208
10225
|
if (call.kind === "failed") {
|
|
10209
|
-
return { kind: "failed", failure: failureForStatus(call.status, call.message) };
|
|
10226
|
+
return { kind: "failed", failure: failureForStatus(call.status, call.message, responseSchema !== void 0) };
|
|
10227
|
+
}
|
|
10228
|
+
const answer = responseSchema ? readEnvelope(call.reply.text) : { kind: "text", text: call.reply.text };
|
|
10229
|
+
if (!answer) {
|
|
10230
|
+
return {
|
|
10231
|
+
kind: "failed",
|
|
10232
|
+
failure: { kind: "transient", message: `Structured output is not valid JSON: ${call.reply.text}` }
|
|
10233
|
+
};
|
|
10210
10234
|
}
|
|
10211
10235
|
return {
|
|
10212
10236
|
kind: "answered",
|
|
10213
|
-
answer
|
|
10237
|
+
answer,
|
|
10214
10238
|
usage: call.reply.usage,
|
|
10215
10239
|
origin: { engine: "http", provider, model }
|
|
10216
10240
|
};
|
|
10217
10241
|
}
|
|
10218
10242
|
}
|
|
10219
10243
|
httpEngine.HttpEngine = HttpEngine;
|
|
10220
|
-
function
|
|
10244
|
+
function readEnvelope(text) {
|
|
10245
|
+
try {
|
|
10246
|
+
return { kind: "structured", envelope: JSON.parse(text) };
|
|
10247
|
+
} catch {
|
|
10248
|
+
return null;
|
|
10249
|
+
}
|
|
10250
|
+
}
|
|
10251
|
+
function failureForStatus(status, message, sentSchema) {
|
|
10252
|
+
if (sentSchema && status === 400)
|
|
10253
|
+
return { kind: "schema-rejected", message };
|
|
10221
10254
|
const fatal = status !== void 0 && FATAL_HTTP_STATUSES.has(status);
|
|
10222
10255
|
return { kind: fatal ? "fatal" : "transient", message };
|
|
10223
10256
|
}
|
|
@@ -10231,7 +10264,7 @@ function requireProviderEngines() {
|
|
|
10231
10264
|
Object.defineProperty(providerEngines, "__esModule", { value: true });
|
|
10232
10265
|
providerEngines.ProviderEngines = void 0;
|
|
10233
10266
|
providerEngines.providerEngines = providerEngines$1;
|
|
10234
|
-
const logger_1 =
|
|
10267
|
+
const logger_1 = strictJsonSchema.requireLogger();
|
|
10235
10268
|
const nua_errors_1 = requireNuaErrors();
|
|
10236
10269
|
const model_info_1 = requireModelInfo();
|
|
10237
10270
|
const http_engine_1 = requireHttpEngine();
|
|
@@ -11178,7 +11211,7 @@ function requireDist() {
|
|
|
11178
11211
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
11179
11212
|
exports$1.runAgentLoop = exports$1.runAgent = exports$1.parseListSchema = exports$1.listSchema = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerEngines = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.LLM_PROVIDER_IDS = void 0;
|
|
11180
11213
|
__exportStar(requireNuaLlmClient(), exports$1);
|
|
11181
|
-
__exportStar(
|
|
11214
|
+
__exportStar(strictJsonSchema.requireLogger(), exports$1);
|
|
11182
11215
|
__exportStar(requireTypes(), exports$1);
|
|
11183
11216
|
__exportStar(requireNuaErrors(), exports$1);
|
|
11184
11217
|
var provider_config_1 = requireProviderConfig();
|
package/dist/cjs/local-agent.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var strictJsonSchema = require('./chunks/strict-json-schema-DUE7RTxG.cjs');
|
|
4
4
|
var node_module = require('node:module');
|
|
5
5
|
|
|
6
6
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -168,99 +168,13 @@ function requireClaudeCode() {
|
|
|
168
168
|
|
|
169
169
|
var codex = {};
|
|
170
170
|
|
|
171
|
-
var strictJsonSchema = {};
|
|
172
|
-
|
|
173
|
-
var hasRequiredStrictJsonSchema;
|
|
174
|
-
function requireStrictJsonSchema() {
|
|
175
|
-
if (hasRequiredStrictJsonSchema) return strictJsonSchema;
|
|
176
|
-
hasRequiredStrictJsonSchema = 1;
|
|
177
|
-
Object.defineProperty(strictJsonSchema, "__esModule", { value: true });
|
|
178
|
-
strictJsonSchema.toStrictSchema = toStrictSchema;
|
|
179
|
-
const STRICT_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
180
|
-
"patternProperties",
|
|
181
|
-
"propertyNames",
|
|
182
|
-
"unevaluatedProperties",
|
|
183
|
-
"dependentRequired",
|
|
184
|
-
"dependentSchemas",
|
|
185
|
-
"if",
|
|
186
|
-
"then",
|
|
187
|
-
"else",
|
|
188
|
-
"not",
|
|
189
|
-
"allOf",
|
|
190
|
-
"oneOf"
|
|
191
|
-
]);
|
|
192
|
-
function toStrictSchema(schema) {
|
|
193
|
-
return strictNode(schema);
|
|
194
|
-
}
|
|
195
|
-
function strictNode(node) {
|
|
196
|
-
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
const schema = node;
|
|
200
|
-
for (const key of Object.keys(schema)) {
|
|
201
|
-
if (STRICT_UNSUPPORTED_KEYWORDS.has(key))
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
const result = { ...schema };
|
|
205
|
-
delete result.$schema;
|
|
206
|
-
const isObject = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.properties !== void 0;
|
|
207
|
-
if (isObject) {
|
|
208
|
-
const properties = schema.properties ?? {};
|
|
209
|
-
if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
const required = new Set(schema.required ?? []);
|
|
213
|
-
const shapedProperties = {};
|
|
214
|
-
for (const [name, child] of Object.entries(properties)) {
|
|
215
|
-
if (!required.has(name))
|
|
216
|
-
return null;
|
|
217
|
-
const shaped = strictNode(child);
|
|
218
|
-
if (!shaped)
|
|
219
|
-
return null;
|
|
220
|
-
shapedProperties[name] = shaped;
|
|
221
|
-
}
|
|
222
|
-
result.properties = shapedProperties;
|
|
223
|
-
result.required = Object.keys(shapedProperties);
|
|
224
|
-
result.additionalProperties = false;
|
|
225
|
-
}
|
|
226
|
-
if (schema.items !== void 0) {
|
|
227
|
-
const shaped = strictNode(schema.items);
|
|
228
|
-
if (!shaped)
|
|
229
|
-
return null;
|
|
230
|
-
result.items = shaped;
|
|
231
|
-
}
|
|
232
|
-
if (schema.prefixItems !== void 0)
|
|
233
|
-
return null;
|
|
234
|
-
if (schema.anyOf !== void 0) {
|
|
235
|
-
const variants = schema.anyOf.map(strictNode);
|
|
236
|
-
if (variants.some((v) => v === null))
|
|
237
|
-
return null;
|
|
238
|
-
result.anyOf = variants;
|
|
239
|
-
}
|
|
240
|
-
for (const defsKey of ["$defs", "definitions"]) {
|
|
241
|
-
if (schema[defsKey] !== void 0) {
|
|
242
|
-
const defs = {};
|
|
243
|
-
for (const [name, child] of Object.entries(schema[defsKey])) {
|
|
244
|
-
const shaped = strictNode(child);
|
|
245
|
-
if (!shaped)
|
|
246
|
-
return null;
|
|
247
|
-
defs[name] = shaped;
|
|
248
|
-
}
|
|
249
|
-
result[defsKey] = defs;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
return strictJsonSchema;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
171
|
var hasRequiredCodex;
|
|
258
172
|
function requireCodex() {
|
|
259
173
|
if (hasRequiredCodex) return codex;
|
|
260
174
|
hasRequiredCodex = 1;
|
|
261
175
|
Object.defineProperty(codex, "__esModule", { value: true });
|
|
262
176
|
codex.codexAdapter = void 0;
|
|
263
|
-
const strict_json_schema_1 = requireStrictJsonSchema();
|
|
177
|
+
const strict_json_schema_1 = strictJsonSchema.requireStrictJsonSchema();
|
|
264
178
|
const failure_classification_1 = requireFailureClassification();
|
|
265
179
|
const SCHEMA_FILE = "output-schema.json";
|
|
266
180
|
const LAST_MESSAGE_FILE = "last-message.txt";
|
|
@@ -781,7 +695,7 @@ function requireLocalAgentEngine() {
|
|
|
781
695
|
hasRequiredLocalAgentEngine = 1;
|
|
782
696
|
Object.defineProperty(localAgentEngine, "__esModule", { value: true });
|
|
783
697
|
localAgentEngine.LocalAgentEngine = void 0;
|
|
784
|
-
const logger_1 =
|
|
698
|
+
const logger_1 = strictJsonSchema.requireLogger();
|
|
785
699
|
const process_runner_1 = requireProcessRunner();
|
|
786
700
|
class LocalAgentEngine {
|
|
787
701
|
constructor(runner, model) {
|
|
@@ -940,7 +854,7 @@ function requireCreateLocalAgent() {
|
|
|
940
854
|
Object.defineProperty(createLocalAgent, "__esModule", { value: true });
|
|
941
855
|
createLocalAgent.localAgent = localAgent;
|
|
942
856
|
createLocalAgent.findLocalAgent = findLocalAgent;
|
|
943
|
-
const logger_1 =
|
|
857
|
+
const logger_1 = strictJsonSchema.requireLogger();
|
|
944
858
|
const adapters_1 = requireAdapters();
|
|
945
859
|
const agent_id_1 = requireAgentId();
|
|
946
860
|
const detect_1 = requireDetect();
|
|
@@ -85,4 +85,90 @@ function requireLogger() {
|
|
|
85
85
|
return logger;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
var strictJsonSchema = {};
|
|
89
|
+
|
|
90
|
+
var hasRequiredStrictJsonSchema;
|
|
91
|
+
function requireStrictJsonSchema() {
|
|
92
|
+
if (hasRequiredStrictJsonSchema) return strictJsonSchema;
|
|
93
|
+
hasRequiredStrictJsonSchema = 1;
|
|
94
|
+
Object.defineProperty(strictJsonSchema, "__esModule", { value: true });
|
|
95
|
+
strictJsonSchema.toStrictSchema = toStrictSchema;
|
|
96
|
+
const STRICT_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
97
|
+
"patternProperties",
|
|
98
|
+
"propertyNames",
|
|
99
|
+
"unevaluatedProperties",
|
|
100
|
+
"dependentRequired",
|
|
101
|
+
"dependentSchemas",
|
|
102
|
+
"if",
|
|
103
|
+
"then",
|
|
104
|
+
"else",
|
|
105
|
+
"not",
|
|
106
|
+
"allOf",
|
|
107
|
+
"oneOf"
|
|
108
|
+
]);
|
|
109
|
+
function toStrictSchema(schema) {
|
|
110
|
+
return strictNode(schema);
|
|
111
|
+
}
|
|
112
|
+
function strictNode(node) {
|
|
113
|
+
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const schema = node;
|
|
117
|
+
for (const key of Object.keys(schema)) {
|
|
118
|
+
if (STRICT_UNSUPPORTED_KEYWORDS.has(key))
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const result = { ...schema };
|
|
122
|
+
delete result.$schema;
|
|
123
|
+
const isObject = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.properties !== void 0;
|
|
124
|
+
if (isObject) {
|
|
125
|
+
const properties = schema.properties ?? {};
|
|
126
|
+
if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const required = new Set(schema.required ?? []);
|
|
130
|
+
const shapedProperties = {};
|
|
131
|
+
for (const [name, child] of Object.entries(properties)) {
|
|
132
|
+
if (!required.has(name))
|
|
133
|
+
return null;
|
|
134
|
+
const shaped = strictNode(child);
|
|
135
|
+
if (!shaped)
|
|
136
|
+
return null;
|
|
137
|
+
shapedProperties[name] = shaped;
|
|
138
|
+
}
|
|
139
|
+
result.properties = shapedProperties;
|
|
140
|
+
result.required = Object.keys(shapedProperties);
|
|
141
|
+
result.additionalProperties = false;
|
|
142
|
+
}
|
|
143
|
+
if (schema.items !== void 0) {
|
|
144
|
+
const shaped = strictNode(schema.items);
|
|
145
|
+
if (!shaped)
|
|
146
|
+
return null;
|
|
147
|
+
result.items = shaped;
|
|
148
|
+
}
|
|
149
|
+
if (schema.prefixItems !== void 0)
|
|
150
|
+
return null;
|
|
151
|
+
if (schema.anyOf !== void 0) {
|
|
152
|
+
const variants = schema.anyOf.map(strictNode);
|
|
153
|
+
if (variants.some((v) => v === null))
|
|
154
|
+
return null;
|
|
155
|
+
result.anyOf = variants;
|
|
156
|
+
}
|
|
157
|
+
for (const defsKey of ["$defs", "definitions"]) {
|
|
158
|
+
if (schema[defsKey] !== void 0) {
|
|
159
|
+
const defs = {};
|
|
160
|
+
for (const [name, child] of Object.entries(schema[defsKey])) {
|
|
161
|
+
const shaped = strictNode(child);
|
|
162
|
+
if (!shaped)
|
|
163
|
+
return null;
|
|
164
|
+
defs[name] = shaped;
|
|
165
|
+
}
|
|
166
|
+
result[defsKey] = defs;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
return strictJsonSchema;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { requireStrictJsonSchema as a, requireLogger as r };
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as requireLogger } from './chunks/
|
|
1
|
+
import { r as requireLogger, a as requireStrictJsonSchema } from './chunks/strict-json-schema-DI9qiH5h.mjs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export { z } from 'zod';
|
|
4
4
|
|
|
@@ -9840,7 +9840,7 @@ function requireProviderConfig() {
|
|
|
9840
9840
|
};
|
|
9841
9841
|
};
|
|
9842
9842
|
exports$1.normalizeGeminiUsage = normalizeGeminiUsage;
|
|
9843
|
-
const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt }, apiKey) => {
|
|
9843
|
+
const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt, responseSchema }, apiKey) => {
|
|
9844
9844
|
const messages = [];
|
|
9845
9845
|
messages.push({ role: "user", content: prompt });
|
|
9846
9846
|
if (assistantPrefillPrompt) {
|
|
@@ -9853,7 +9853,13 @@ function requireProviderConfig() {
|
|
|
9853
9853
|
max_completion_tokens: maxTokens,
|
|
9854
9854
|
top_p: 1,
|
|
9855
9855
|
stream: false,
|
|
9856
|
-
stop: null
|
|
9856
|
+
stop: null,
|
|
9857
|
+
...responseSchema && {
|
|
9858
|
+
response_format: {
|
|
9859
|
+
type: "json_schema",
|
|
9860
|
+
json_schema: { name: "response", strict: true, schema: responseSchema }
|
|
9861
|
+
}
|
|
9862
|
+
}
|
|
9857
9863
|
};
|
|
9858
9864
|
const headers = {
|
|
9859
9865
|
"Content-Type": "application/json",
|
|
@@ -9980,6 +9986,12 @@ function requireProviderConfig() {
|
|
|
9980
9986
|
providerId: "groq",
|
|
9981
9987
|
apiOperation: "chat/completions",
|
|
9982
9988
|
errorLabel: "Groq",
|
|
9989
|
+
// https://console.groq.com/docs/structured-outputs
|
|
9990
|
+
strictSchemaModels: /* @__PURE__ */ new Set([
|
|
9991
|
+
"openai/gpt-oss-120b",
|
|
9992
|
+
"openai/gpt-oss-20b",
|
|
9993
|
+
"qwen/qwen3.8-27b"
|
|
9994
|
+
]),
|
|
9983
9995
|
buildRequest: buildOpenAiStyleRequest("https://api.groq.com/openai/v1/chat/completions"),
|
|
9984
9996
|
parseResponse: parseOpenAiStyleResponse("Groq")
|
|
9985
9997
|
},
|
|
@@ -10027,7 +10039,7 @@ function requireModelInfo() {
|
|
|
10027
10039
|
exports$1.MODEL_ALIASES = {
|
|
10028
10040
|
fast: [
|
|
10029
10041
|
{ provider: "cerebras", model: "qwen-3.8-27b" },
|
|
10030
|
-
{ provider: "groq", model: "
|
|
10042
|
+
{ provider: "groq", model: "openai/gpt-oss-120b" },
|
|
10031
10043
|
{ provider: "openrouter", model: "z-ai/glm-5.2" }
|
|
10032
10044
|
],
|
|
10033
10045
|
gemini: [
|
|
@@ -10180,6 +10192,7 @@ function requireHttpEngine() {
|
|
|
10180
10192
|
hasRequiredHttpEngine = 1;
|
|
10181
10193
|
Object.defineProperty(httpEngine, "__esModule", { value: true });
|
|
10182
10194
|
httpEngine.HttpEngine = void 0;
|
|
10195
|
+
const strict_json_schema_1 = requireStrictJsonSchema();
|
|
10183
10196
|
const provider_call_1 = requireProviderCall();
|
|
10184
10197
|
const provider_config_1 = requireProviderConfig();
|
|
10185
10198
|
const FATAL_HTTP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404]);
|
|
@@ -10188,35 +10201,55 @@ function requireHttpEngine() {
|
|
|
10188
10201
|
this.target = target;
|
|
10189
10202
|
this.logger = logger;
|
|
10190
10203
|
}
|
|
10191
|
-
/**
|
|
10192
|
-
nativeSchema() {
|
|
10193
|
-
|
|
10204
|
+
/** Enforced in strict mode on models whose provider supports it; other models get the schema in the prompt. */
|
|
10205
|
+
nativeSchema(envelopeSchema) {
|
|
10206
|
+
const { provider, model } = this.target;
|
|
10207
|
+
if (!provider_config_1.providerConfigs[provider].strictSchemaModels?.has(model))
|
|
10208
|
+
return null;
|
|
10209
|
+
return (0, strict_json_schema_1.toStrictSchema)(envelopeSchema);
|
|
10194
10210
|
}
|
|
10195
10211
|
async attempt(request) {
|
|
10196
10212
|
const { provider, model, apiKey } = this.target;
|
|
10197
10213
|
const config = provider_config_1.providerConfigs[provider];
|
|
10214
|
+
const responseSchema = request.enforcement.kind === "native" ? request.enforcement.schema : void 0;
|
|
10198
10215
|
const call = await (0, provider_call_1.callProvider)({
|
|
10199
10216
|
target: this.target,
|
|
10200
10217
|
apiOperation: config.apiOperation,
|
|
10201
10218
|
maxTokens: request.maxTokens,
|
|
10202
|
-
request: config.buildRequest({ prompt: request.prompt, model, maxTokens: request.maxTokens }, apiKey),
|
|
10219
|
+
request: config.buildRequest({ prompt: request.prompt, model, maxTokens: request.maxTokens, responseSchema }, apiKey),
|
|
10203
10220
|
parseResponse: config.parseResponse,
|
|
10204
10221
|
responseLength: (reply) => reply.text.length,
|
|
10205
10222
|
usage: (reply) => reply.usage
|
|
10206
10223
|
}, this.logger);
|
|
10207
10224
|
if (call.kind === "failed") {
|
|
10208
|
-
return { kind: "failed", failure: failureForStatus(call.status, call.message) };
|
|
10225
|
+
return { kind: "failed", failure: failureForStatus(call.status, call.message, responseSchema !== void 0) };
|
|
10226
|
+
}
|
|
10227
|
+
const answer = responseSchema ? readEnvelope(call.reply.text) : { kind: "text", text: call.reply.text };
|
|
10228
|
+
if (!answer) {
|
|
10229
|
+
return {
|
|
10230
|
+
kind: "failed",
|
|
10231
|
+
failure: { kind: "transient", message: `Structured output is not valid JSON: ${call.reply.text}` }
|
|
10232
|
+
};
|
|
10209
10233
|
}
|
|
10210
10234
|
return {
|
|
10211
10235
|
kind: "answered",
|
|
10212
|
-
answer
|
|
10236
|
+
answer,
|
|
10213
10237
|
usage: call.reply.usage,
|
|
10214
10238
|
origin: { engine: "http", provider, model }
|
|
10215
10239
|
};
|
|
10216
10240
|
}
|
|
10217
10241
|
}
|
|
10218
10242
|
httpEngine.HttpEngine = HttpEngine;
|
|
10219
|
-
function
|
|
10243
|
+
function readEnvelope(text) {
|
|
10244
|
+
try {
|
|
10245
|
+
return { kind: "structured", envelope: JSON.parse(text) };
|
|
10246
|
+
} catch {
|
|
10247
|
+
return null;
|
|
10248
|
+
}
|
|
10249
|
+
}
|
|
10250
|
+
function failureForStatus(status, message, sentSchema) {
|
|
10251
|
+
if (sentSchema && status === 400)
|
|
10252
|
+
return { kind: "schema-rejected", message };
|
|
10220
10253
|
const fatal = status !== void 0 && FATAL_HTTP_STATUSES.has(status);
|
|
10221
10254
|
return { kind: fatal ? "fatal" : "transient", message };
|
|
10222
10255
|
}
|
package/dist/esm/local-agent.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as requireLogger } from './chunks/
|
|
1
|
+
import { a as requireStrictJsonSchema, r as requireLogger } from './chunks/strict-json-schema-DI9qiH5h.mjs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
|
|
4
4
|
var localAgent$1 = {};
|
|
@@ -165,92 +165,6 @@ function requireClaudeCode() {
|
|
|
165
165
|
|
|
166
166
|
var codex = {};
|
|
167
167
|
|
|
168
|
-
var strictJsonSchema = {};
|
|
169
|
-
|
|
170
|
-
var hasRequiredStrictJsonSchema;
|
|
171
|
-
function requireStrictJsonSchema() {
|
|
172
|
-
if (hasRequiredStrictJsonSchema) return strictJsonSchema;
|
|
173
|
-
hasRequiredStrictJsonSchema = 1;
|
|
174
|
-
Object.defineProperty(strictJsonSchema, "__esModule", { value: true });
|
|
175
|
-
strictJsonSchema.toStrictSchema = toStrictSchema;
|
|
176
|
-
const STRICT_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
177
|
-
"patternProperties",
|
|
178
|
-
"propertyNames",
|
|
179
|
-
"unevaluatedProperties",
|
|
180
|
-
"dependentRequired",
|
|
181
|
-
"dependentSchemas",
|
|
182
|
-
"if",
|
|
183
|
-
"then",
|
|
184
|
-
"else",
|
|
185
|
-
"not",
|
|
186
|
-
"allOf",
|
|
187
|
-
"oneOf"
|
|
188
|
-
]);
|
|
189
|
-
function toStrictSchema(schema) {
|
|
190
|
-
return strictNode(schema);
|
|
191
|
-
}
|
|
192
|
-
function strictNode(node) {
|
|
193
|
-
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
const schema = node;
|
|
197
|
-
for (const key of Object.keys(schema)) {
|
|
198
|
-
if (STRICT_UNSUPPORTED_KEYWORDS.has(key))
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
const result = { ...schema };
|
|
202
|
-
delete result.$schema;
|
|
203
|
-
const isObject = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.properties !== void 0;
|
|
204
|
-
if (isObject) {
|
|
205
|
-
const properties = schema.properties ?? {};
|
|
206
|
-
if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
|
|
207
|
-
return null;
|
|
208
|
-
}
|
|
209
|
-
const required = new Set(schema.required ?? []);
|
|
210
|
-
const shapedProperties = {};
|
|
211
|
-
for (const [name, child] of Object.entries(properties)) {
|
|
212
|
-
if (!required.has(name))
|
|
213
|
-
return null;
|
|
214
|
-
const shaped = strictNode(child);
|
|
215
|
-
if (!shaped)
|
|
216
|
-
return null;
|
|
217
|
-
shapedProperties[name] = shaped;
|
|
218
|
-
}
|
|
219
|
-
result.properties = shapedProperties;
|
|
220
|
-
result.required = Object.keys(shapedProperties);
|
|
221
|
-
result.additionalProperties = false;
|
|
222
|
-
}
|
|
223
|
-
if (schema.items !== void 0) {
|
|
224
|
-
const shaped = strictNode(schema.items);
|
|
225
|
-
if (!shaped)
|
|
226
|
-
return null;
|
|
227
|
-
result.items = shaped;
|
|
228
|
-
}
|
|
229
|
-
if (schema.prefixItems !== void 0)
|
|
230
|
-
return null;
|
|
231
|
-
if (schema.anyOf !== void 0) {
|
|
232
|
-
const variants = schema.anyOf.map(strictNode);
|
|
233
|
-
if (variants.some((v) => v === null))
|
|
234
|
-
return null;
|
|
235
|
-
result.anyOf = variants;
|
|
236
|
-
}
|
|
237
|
-
for (const defsKey of ["$defs", "definitions"]) {
|
|
238
|
-
if (schema[defsKey] !== void 0) {
|
|
239
|
-
const defs = {};
|
|
240
|
-
for (const [name, child] of Object.entries(schema[defsKey])) {
|
|
241
|
-
const shaped = strictNode(child);
|
|
242
|
-
if (!shaped)
|
|
243
|
-
return null;
|
|
244
|
-
defs[name] = shaped;
|
|
245
|
-
}
|
|
246
|
-
result[defsKey] = defs;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return result;
|
|
250
|
-
}
|
|
251
|
-
return strictJsonSchema;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
168
|
var hasRequiredCodex;
|
|
255
169
|
function requireCodex() {
|
|
256
170
|
if (hasRequiredCodex) return codex;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Logger } from "../../../lib/logger";
|
|
2
|
+
import { JsonSchema } from "../../../lib/schema-utils";
|
|
2
3
|
import { AttemptOutcome, AttemptRequest, LlmEngine } from "../llm-engine";
|
|
3
4
|
import { ProviderTarget } from "./provider-call";
|
|
4
5
|
/** Answers cast attempts on one model of an LLM provider's HTTP API. */
|
|
@@ -6,7 +7,7 @@ export declare class HttpEngine implements LlmEngine {
|
|
|
6
7
|
private readonly target;
|
|
7
8
|
private readonly logger;
|
|
8
9
|
constructor(target: ProviderTarget, logger: Logger);
|
|
9
|
-
/**
|
|
10
|
-
nativeSchema(): null;
|
|
10
|
+
/** Enforced in strict mode on models whose provider supports it; other models get the schema in the prompt. */
|
|
11
|
+
nativeSchema(envelopeSchema: JsonSchema): JsonSchema | null;
|
|
11
12
|
attempt(request: AttemptRequest): Promise<AttemptOutcome>;
|
|
12
13
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JsonSchema } from "../../../lib/schema-utils";
|
|
1
2
|
export type ProviderRequestBase = {
|
|
2
3
|
url: string;
|
|
3
4
|
method?: string;
|
|
@@ -15,6 +16,8 @@ export interface ProviderRequestOptions {
|
|
|
15
16
|
model: string;
|
|
16
17
|
maxTokens: number;
|
|
17
18
|
assistantPrefillPrompt?: string;
|
|
19
|
+
/** A JSON schema the provider enforces on the reply, in strict mode. */
|
|
20
|
+
responseSchema?: JsonSchema;
|
|
18
21
|
}
|
|
19
22
|
export type NormalizedUsage = {
|
|
20
23
|
promptTokens: number;
|
|
@@ -30,6 +33,8 @@ export interface ProviderConfig {
|
|
|
30
33
|
providerId: LlmProviderId;
|
|
31
34
|
apiOperation: string;
|
|
32
35
|
errorLabel: string;
|
|
36
|
+
/** Models that can enforce a response JSON schema in strict mode. */
|
|
37
|
+
strictSchemaModels?: ReadonlySet<string>;
|
|
33
38
|
buildRequest(options: ProviderRequestOptions, apiKey: string): ProviderRequestBase;
|
|
34
39
|
parseResponse(response: Response): Promise<ProviderParsedResponse>;
|
|
35
40
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuabase",
|
|
3
3
|
"description": "Nuabase TypeScript client to create typed functions from LLM prompts",
|
|
4
|
-
"version": "2.3.
|
|
4
|
+
"version": "2.3.11",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Jasim A Basheer <jasim@nuabase.com>",
|
|
7
7
|
"engines": {
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"zod": "^4.1.5"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"ajv": "^8.17.1",
|
|
63
62
|
"@eslint/js": "^9.35.0",
|
|
64
63
|
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
|
65
64
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
@@ -70,29 +69,23 @@
|
|
|
70
69
|
"@types/jest": "^30.0.0",
|
|
71
70
|
"@types/node": "^24.3.3",
|
|
72
71
|
"@types/signale": "^1",
|
|
73
|
-
"
|
|
74
|
-
"chalk": "^5.6.2",
|
|
72
|
+
"ajv": "^8.17.1",
|
|
75
73
|
"esbuild": "^0.25.9",
|
|
76
74
|
"eslint": "^9.35.0",
|
|
77
75
|
"eventsource": "^4.0.0",
|
|
78
76
|
"fs-extra": "^11.3.1",
|
|
79
77
|
"jest": "^30.1.3",
|
|
80
78
|
"knip": "^5.63.1",
|
|
81
|
-
"new-github-release-url": "^2.0.0",
|
|
82
|
-
"open": "^10.2.0",
|
|
83
79
|
"prettier": "^3.6.2",
|
|
84
80
|
"rimraf": "^6.0.1",
|
|
85
81
|
"rollup": "^4.50.1",
|
|
86
82
|
"rollup-plugin-esbuild": "^6.2.1",
|
|
87
83
|
"rollup-plugin-node-externals": "^8.1.1",
|
|
88
84
|
"signale": "^1.4.0",
|
|
89
|
-
"simple-git": "^3.28.0",
|
|
90
85
|
"ts-jest": "^29.4.1",
|
|
91
86
|
"tsx": "^4.20.5",
|
|
92
87
|
"typescript": "^5.9.2",
|
|
93
88
|
"typescript-eslint": "^8.43.0",
|
|
94
|
-
"version-next": "^1.0.2",
|
|
95
|
-
"yargs": "^18.0.0",
|
|
96
89
|
"zod": "^4.1.5",
|
|
97
90
|
"zx": "^8.8.1",
|
|
98
91
|
"nua-llm-core": "1.0.0"
|
|
@@ -108,7 +101,7 @@
|
|
|
108
101
|
"lint": "eslint --cache .",
|
|
109
102
|
"jest": "jest",
|
|
110
103
|
"test": "pnpm run prettier:check && pnpm run typecheck && pnpm run lint && pnpm run jest && pnpm run build && pnpm run pack:test",
|
|
111
|
-
"release": "
|
|
104
|
+
"release": "tsx scripts/release",
|
|
112
105
|
"knip": "knip"
|
|
113
106
|
}
|
|
114
107
|
}
|