modelmix 4.5.16 → 4.5.18
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/README.md +91 -5
- package/index.js +9 -1
- package/package.json +1 -1
- package/skills/modelmix/SKILL.md +48 -2
- package/test/tokens.test.js +12 -0
package/README.md
CHANGED
|
@@ -343,7 +343,7 @@ const result = await model.json(
|
|
|
343
343
|
|
|
344
344
|
### Enhanced descriptors
|
|
345
345
|
|
|
346
|
-
Descriptions support **descriptor objects** with `description`, `required`, `enum`, and `
|
|
346
|
+
Descriptions support **descriptor objects** with `description`, `required`, `enum`, `default`, and `nullable`:
|
|
347
347
|
|
|
348
348
|
```javascript
|
|
349
349
|
const result = await model.json(
|
|
@@ -359,11 +359,97 @@ const result = await model.json(
|
|
|
359
359
|
| Property | Type | Default | Description |
|
|
360
360
|
| --- | --- | --- | --- |
|
|
361
361
|
| `description` | `string` | — | Field description for the model |
|
|
362
|
-
| `required` | `boolean` | `true` | If `false`, field is removed from `required` and type becomes nullable |
|
|
363
|
-
| `enum` | `array` | — |
|
|
364
|
-
| `default` | `any` | — | Default value for the
|
|
362
|
+
| `required` | `boolean` | `true` | If `false`, field is removed from `required` and its type becomes nullable |
|
|
363
|
+
| `enum` | `array` | — | Restricts the field to specific values. Including `null` in the array auto-makes the type nullable |
|
|
364
|
+
| `default` | `any` | — | Default value hint for the model |
|
|
365
|
+
| `nullable` | `boolean` | `false` | If `true`, makes the type nullable without removing from `required` |
|
|
365
366
|
|
|
366
|
-
You can mix strings and descriptor objects freely in the same descriptions parameter
|
|
367
|
+
You can mix plain strings and descriptor objects freely in the same descriptions parameter:
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
const result = await model.json(
|
|
371
|
+
{ name: 'Martin', age: 22, status: 'active' },
|
|
372
|
+
{
|
|
373
|
+
name: 'Full name', // plain string
|
|
374
|
+
age: { description: 'Age in years', required: false }, // optional field
|
|
375
|
+
status: { description: 'Account status', enum: ['active', 'inactive', 'banned'], default: 'active' }
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Nested object descriptions
|
|
381
|
+
|
|
382
|
+
Pass a nested object as the description value to describe fields inside a nested object:
|
|
383
|
+
|
|
384
|
+
```javascript
|
|
385
|
+
const result = await model.json(
|
|
386
|
+
{ user: { name: 'Alice', age: 30 } },
|
|
387
|
+
{
|
|
388
|
+
user: { name: 'Full name of the user', age: 'Age in years' }
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
To describe the object field itself (e.g. mark it optional) **and** its nested fields, use the `description` / `required` descriptor for the parent key, which applies only to the parent, while still passing nested descriptions as its own separate key:
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
// Mark the parent optional but don't describe its children
|
|
397
|
+
const result = await model.json(
|
|
398
|
+
{ user: { name: 'Alice', age: 30 } },
|
|
399
|
+
{ user: { description: 'User details', required: false } }
|
|
400
|
+
);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Array item descriptions
|
|
404
|
+
|
|
405
|
+
Pass descriptions for the items of an array by wrapping the descriptions in an array:
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
const result = await model.json(
|
|
409
|
+
{ countries: [{ name: 'France', capital: 'Paris' }] },
|
|
410
|
+
{ countries: [{ name: 'Country name', capital: 'Capital city in uppercase' }] }
|
|
411
|
+
);
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
To mark the array field itself optional while keeping item descriptions, use a descriptor on the key:
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
const result = await model.json(
|
|
418
|
+
{ tags: ['admin'] },
|
|
419
|
+
{ tags: { description: 'List of user roles', required: false } }
|
|
420
|
+
);
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Automatic type and format detection
|
|
424
|
+
|
|
425
|
+
`generateJsonSchema` infers types and formats automatically from the example values:
|
|
426
|
+
|
|
427
|
+
| Example value | Inferred schema |
|
|
428
|
+
| --- | --- |
|
|
429
|
+
| `42` | `{ type: 'integer' }` |
|
|
430
|
+
| `19.99` | `{ type: 'number' }` |
|
|
431
|
+
| `true` / `false` | `{ type: 'boolean' }` |
|
|
432
|
+
| `null` | `{ type: 'null' }` |
|
|
433
|
+
| `'hello'` | `{ type: 'string' }` |
|
|
434
|
+
| `'user@example.com'` | `{ type: 'string', format: 'email' }` |
|
|
435
|
+
| `'1990-01-01'` | `{ type: 'string', format: 'date', description: 'Date in format YYYY-MM-DD' }` |
|
|
436
|
+
| `'14:30'` | `{ type: 'string', format: 'time', description: 'Time in format HH:MM' }` |
|
|
437
|
+
| `'09:15:45'` | `{ type: 'string', format: 'time', description: 'Time in format HH:MM:SS' }` |
|
|
438
|
+
| `[{ … }]` | `{ type: 'array', items: { … } }` — schema inferred from the first element |
|
|
439
|
+
| `{ … }` | `{ type: 'object', properties: { … }, required: […] }` |
|
|
440
|
+
|
|
441
|
+
When a field carries an `enum` that includes `null`, or has `required: false` or `nullable: true`, its type is widened to `[type, 'null']`. For example:
|
|
442
|
+
|
|
443
|
+
```javascript
|
|
444
|
+
// enum with null → type becomes ['string', 'null']
|
|
445
|
+
{ description: 'Gender', enum: ['m', 'f', null] }
|
|
446
|
+
|
|
447
|
+
// required: false → removes from required[] and type becomes ['string', 'null']
|
|
448
|
+
{ description: 'Nickname', required: false }
|
|
449
|
+
|
|
450
|
+
// nullable: true → type becomes ['string', 'null'] but stays in required[]
|
|
451
|
+
{ description: 'Middle name', nullable: true }
|
|
452
|
+
```
|
|
367
453
|
|
|
368
454
|
### Array auto-wrap
|
|
369
455
|
|
package/index.js
CHANGED
|
@@ -37,6 +37,8 @@ const MODEL_PRICING = {
|
|
|
37
37
|
// OpenAI
|
|
38
38
|
'gpt-realtime-mini': [0.60, 2.40],
|
|
39
39
|
'gpt-realtime': [4.00, 16.00],
|
|
40
|
+
'gpt-5.5-pro': [30.00, 180.00],
|
|
41
|
+
'gpt-5.5': [5.00, 30.00],
|
|
40
42
|
'gpt-5.4': [2.50, 15.00],
|
|
41
43
|
'gpt-5.4-pro': [30, 180.00],
|
|
42
44
|
'gpt-5.4-mini': [0.75, 4.50],
|
|
@@ -319,7 +321,13 @@ class ModelMix {
|
|
|
319
321
|
}
|
|
320
322
|
gpt54pro({ options = {}, config = {} } = {}) {
|
|
321
323
|
return this.attach('gpt-5.4-pro', new MixOpenAIResponses({ options, config }));
|
|
322
|
-
}
|
|
324
|
+
}
|
|
325
|
+
gpt55({ options = {}, config = {} } = {}) {
|
|
326
|
+
return this.attach('gpt-5.5', new MixOpenAIResponses({ options, config }));
|
|
327
|
+
}
|
|
328
|
+
gpt55pro({ options = {}, config = {} } = {}) {
|
|
329
|
+
return this.attach('gpt-5.5-pro', new MixOpenAIResponses({ options, config }));
|
|
330
|
+
}
|
|
323
331
|
gptRealtime({ options = {}, config = {} } = {}) {
|
|
324
332
|
return this.attach('gpt-realtime', new MixOpenAIWebSocket({ options, config }));
|
|
325
333
|
}
|
package/package.json
CHANGED
package/skills/modelmix/SKILL.md
CHANGED
|
@@ -176,7 +176,53 @@ const result = await model.json(
|
|
|
176
176
|
);
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
Descriptor properties:
|
|
179
|
+
Descriptor properties:
|
|
180
|
+
|
|
181
|
+
| Property | Type | Notes |
|
|
182
|
+
| --- | --- | --- |
|
|
183
|
+
| `description` | string | Field description for the model |
|
|
184
|
+
| `required` | boolean (default `true`) | `false` → removes from `required[]` **and** makes type nullable |
|
|
185
|
+
| `enum` | array | Restricts allowed values. Including `null` auto-makes the type nullable |
|
|
186
|
+
| `default` | any | Default value hint |
|
|
187
|
+
| `nullable` | boolean (default `false`) | `true` → makes type nullable but keeps field in `required[]` |
|
|
188
|
+
|
|
189
|
+
#### Nested object descriptions
|
|
190
|
+
|
|
191
|
+
Pass a plain object as the description value to annotate fields inside a nested object:
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
model.json(
|
|
195
|
+
{ user: { name: 'Alice', age: 30 } },
|
|
196
|
+
{ user: { name: 'Full name', age: 'Age in years' } }
|
|
197
|
+
);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
To mark the object itself as optional, use a descriptor (only `description`/`required`/`nullable` keys) — it applies to the parent, not the children:
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
model.json(
|
|
204
|
+
{ user: { name: 'Alice', age: 30 } },
|
|
205
|
+
{ user: { description: 'User details', required: false } }
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### Array item descriptions
|
|
210
|
+
|
|
211
|
+
Wrap descriptions in an array to annotate items of an array field:
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
model.json(
|
|
215
|
+
{ countries: [{ name: 'France', capital: 'Paris' }] },
|
|
216
|
+
{ countries: [{ name: 'Country name', capital: 'Capital in uppercase' }] }
|
|
217
|
+
);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
#### Automatic type and format detection
|
|
221
|
+
|
|
222
|
+
Schema types are inferred from example values: `integer` (whole numbers), `number` (floats), `boolean`, `null`, `string`, and special formats:
|
|
223
|
+
- `'user@example.com'` → `{ type: 'string', format: 'email' }`
|
|
224
|
+
- `'1990-01-01'` → `{ type: 'string', format: 'date' }`
|
|
225
|
+
- `'14:30'` / `'09:15:45'` → `{ type: 'string', format: 'time' }`
|
|
180
226
|
|
|
181
227
|
#### Array auto-wrap
|
|
182
228
|
|
|
@@ -390,7 +436,7 @@ const model = ModelMix.new({
|
|
|
390
436
|
- Store API keys in `.env` and load with `dotenv/config` or `process.loadEnvFile()`. Never hardcode keys.
|
|
391
437
|
- Chain models for resilience: primary model first, fallbacks after.
|
|
392
438
|
- When using MCP tools or `addTool()`, set `max_history` to at least 3 — tool call/response pairs consume history slots.
|
|
393
|
-
- Use `.json()` for structured output instead of parsing text manually. Use descriptor objects `{ description, required, enum, default }` for richer schema control.
|
|
439
|
+
- Use `.json()` for structured output instead of parsing text manually. Use descriptor objects `{ description, required, enum, default, nullable }` for richer schema control.
|
|
394
440
|
- Use `.message()` for simple text, `.raw()` when you need tokens/thinking/toolCalls.
|
|
395
441
|
- For thinking models, append `think` to the method name (e.g. `sonnet45think()`).
|
|
396
442
|
- Template placeholders use `{key}` syntax in both system prompts and user messages.
|
package/test/tokens.test.js
CHANGED
|
@@ -76,6 +76,18 @@ describe('Token Usage Tracking', () => {
|
|
|
76
76
|
expect(request.prompt_cache_retention).to.equal('24h');
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
it('should register GPT-5.5 shortcuts with OpenAI Responses provider', function () {
|
|
80
|
+
const model = ModelMix.new()
|
|
81
|
+
.gpt55()
|
|
82
|
+
.gpt55pro();
|
|
83
|
+
|
|
84
|
+
expect(model.models).to.have.length(2);
|
|
85
|
+
expect(model.models[0].key).to.equal('gpt-5.5');
|
|
86
|
+
expect(model.models[1].key).to.equal('gpt-5.5-pro');
|
|
87
|
+
expect(model.models[0].provider).to.be.instanceOf(MixOpenAIResponses);
|
|
88
|
+
expect(model.models[1].provider).to.be.instanceOf(MixOpenAIResponses);
|
|
89
|
+
});
|
|
90
|
+
|
|
79
91
|
it('should track tokens in OpenAI response', async function () {
|
|
80
92
|
this.timeout(30000);
|
|
81
93
|
|