@north-light/crouter 0.3.191 → 0.3.192

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.
@@ -1,6 +1,6 @@
1
1
  // Run with: node --import tsx/esm --test src/pi-extensions/__tests__/canvas-structured-output.test.ts
2
2
  //
3
- // Regression: Codex strict function schemas require every property in `required`.
3
+ // Regression: strict function schemas require all properties and closed object shapes.
4
4
  import { after, test } from 'node:test';
5
5
  import assert from 'node:assert/strict';
6
6
  import { mkdtempSync, rmSync } from 'node:fs';
@@ -37,9 +37,15 @@ test('optional submit fields remain optional through a strict provider tool sche
37
37
  commit: { type: 'string' },
38
38
  verification: { type: 'string' },
39
39
  blocker: { type: 'string' },
40
+ details: {
41
+ type: 'object',
42
+ properties: {
43
+ summary: { type: 'string' },
44
+ },
45
+ required: ['summary'],
46
+ },
40
47
  },
41
- required: ['status', 'verification'],
42
- additionalProperties: false,
48
+ required: ['status', 'verification', 'details'],
43
49
  };
44
50
  writeOutputSchema('structured-output-test', 'oneoff', schema);
45
51
  let definition;
@@ -51,10 +57,12 @@ test('optional submit fields remain optional through a strict provider tool sche
51
57
  });
52
58
  assert.ok(definition, 'the pending request registers submit');
53
59
  const parameters = definition['parameters'];
54
- assert.deepEqual(parameters.required, ['status', 'commit', 'verification', 'blocker']);
60
+ assert.deepEqual(parameters.required, ['status', 'commit', 'verification', 'blocker', 'details']);
55
61
  assert.deepEqual(parameters.properties.commit, { anyOf: [{ type: 'string' }, { type: 'null' }] });
56
62
  assert.deepEqual(parameters.properties.blocker, { anyOf: [{ type: 'string' }, { type: 'null' }] });
57
- assert.deepEqual(schema.required, ['status', 'verification'], 'the stored request keeps its original optionality');
63
+ assert.equal(parameters.additionalProperties, false);
64
+ assert.equal(parameters.properties.details.additionalProperties, false);
65
+ assert.deepEqual(schema.required, ['status', 'verification', 'details'], 'the stored request keeps its original optionality');
58
66
  const [providerTool] = convertResponsesTools([definition], {
59
67
  strict: false,
60
68
  supportsStrictMode: true,
@@ -47,6 +47,10 @@ function strictToolSchema(schema) {
47
47
  }
48
48
  }
49
49
  const properties = transformed['properties'];
50
+ const isObjectSchema = transformed['type'] === 'object'
51
+ || (properties !== null && typeof properties === 'object' && !Array.isArray(properties));
52
+ if (isObjectSchema)
53
+ transformed['additionalProperties'] = false;
50
54
  if (properties === null || typeof properties !== 'object' || Array.isArray(properties))
51
55
  return transformed;
52
56
  const required = new Set(Array.isArray(source['required']) ? source['required'].filter((name) => typeof name === 'string') : []);
@@ -125,9 +129,9 @@ export function registerCanvasStructuredOutput(pi) {
125
129
  'Use submit to answer the pending one-off structured-output request before stopping or going dormant.',
126
130
  'After one-off submit succeeds, continue with any remaining work normally.',
127
131
  ],
128
- // OpenAI strict tools require every property to be required. Optional fields
129
- // become nullable in the provider-only schema and null is removed before the
130
- // original result is persisted.
132
+ // Strict provider tools require every property to be required and every
133
+ // object to reject undeclared properties. Optional fields become nullable
134
+ // in the provider-only schema and null is removed before persistence.
131
135
  parameters: strictToolSchema(request.schema),
132
136
  constrainedSampling: { type: 'json_schema', strict: 'prefer' },
133
137
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.191",
3
+ "version": "0.3.192",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.191",
3
+ "version": "0.3.192",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.191",
9
+ "version": "0.3.192",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {