kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: fix JSON schema parsing in @agentic/core
rodzic
938be099df
commit
66f8c1e900
|
@ -1,5 +1,5 @@
|
||||||
import type { AdminDeployment, Tool } from '@agentic/platform-types'
|
import type { AdminDeployment, Tool } from '@agentic/platform-types'
|
||||||
import { assert } from '@agentic/platform-core'
|
import { assert, HttpError } from '@agentic/platform-core'
|
||||||
|
|
||||||
import type { GatewayHonoContext } from './types'
|
import type { GatewayHonoContext } from './types'
|
||||||
import { cfValidateJsonSchema } from './cf-validate-json-schema'
|
import { cfValidateJsonSchema } from './cf-validate-json-schema'
|
||||||
|
@ -14,6 +14,7 @@ export async function getToolArgsFromRequest(
|
||||||
deployment: AdminDeployment
|
deployment: AdminDeployment
|
||||||
}
|
}
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, any>> {
|
||||||
|
const logger = ctx.get('logger')
|
||||||
const request = ctx.req.raw
|
const request = ctx.req.raw
|
||||||
assert(
|
assert(
|
||||||
deployment.origin.type !== 'raw',
|
deployment.origin.type !== 'raw',
|
||||||
|
@ -50,17 +51,29 @@ export async function getToolArgsFromRequest(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
incomingRequestArgsRaw = (await request.json()) as Record<string, any>
|
incomingRequestArgsRaw = (await request.json()) as Record<string, any>
|
||||||
} catch {
|
} catch (err) {
|
||||||
// If the request body is not JSON or malformed, ignore it for now.
|
// Error if the request body is not JSON or is malformed.
|
||||||
// TODO: need to improve on this logic.
|
logger.error('Error parsing incoming request body', request, err)
|
||||||
|
throw new HttpError({
|
||||||
|
message: 'Invalid request body json',
|
||||||
|
statusCode: 400,
|
||||||
|
cause: err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log(
|
||||||
|
// 'incomingRequestArgsRaw',
|
||||||
|
// typeof incomingRequestArgsRaw,
|
||||||
|
// request.headers,
|
||||||
|
// incomingRequestArgsRaw
|
||||||
|
// )
|
||||||
|
|
||||||
// TODO: Proper support for empty params with POST requests
|
// TODO: Proper support for empty params with POST requests
|
||||||
assert(incomingRequestArgsRaw, 400, 'Invalid empty request body')
|
assert(incomingRequestArgsRaw, 400, 'Invalid empty request body')
|
||||||
assert(
|
assert(
|
||||||
typeof incomingRequestArgsRaw === 'object',
|
typeof incomingRequestArgsRaw === 'object',
|
||||||
400,
|
400,
|
||||||
'Invalid request body'
|
`Invalid request body: expected type "object", received type "${typeof incomingRequestArgsRaw}"`
|
||||||
)
|
)
|
||||||
assert(!Array.isArray(incomingRequestArgsRaw), 400, 'Invalid request body')
|
assert(!Array.isArray(incomingRequestArgsRaw), 400, 'Invalid request body')
|
||||||
return incomingRequestArgsRaw
|
return incomingRequestArgsRaw
|
||||||
|
|
|
@ -41,8 +41,6 @@ async function main() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log()
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Second call to OpenAI to generate a text response
|
// Second call to OpenAI to generate a text response
|
||||||
const res = await openai.responses.create({
|
const res = await openai.responses.create({
|
||||||
|
|
|
@ -40,8 +40,6 @@ async function main() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log()
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Second call to OpenAI to generate a text response
|
// Second call to OpenAI to generate a text response
|
||||||
const res = await openai.chat.completions.create({
|
const res = await openai.chat.completions.create({
|
||||||
|
@ -51,7 +49,7 @@ async function main() {
|
||||||
tools: searchTool.functions.toolSpecs
|
tools: searchTool.functions.toolSpecs
|
||||||
})
|
})
|
||||||
const message = res.choices?.[0]?.message
|
const message = res.choices?.[0]?.message
|
||||||
console.log(message)
|
console.log(message?.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,20 +183,26 @@ function getSchema(parameters: any[], type: string) {
|
||||||
...paramSchema,
|
...paramSchema,
|
||||||
...handleNullableSchema(param.schema)
|
...handleNullableSchema(param.schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('examples' in param) {
|
if ('examples' in param) {
|
||||||
paramSchema.examples = getExamples(param.examples)
|
paramSchema.examples = getExamples(param.examples)
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.properties[param.name] = paramSchema
|
schema.properties[param.name] = paramSchema
|
||||||
} else {
|
} else {
|
||||||
if ('examples' in paramSchema) {
|
if ('examples' in paramSchema) {
|
||||||
paramSchema.examples = getExamples(paramSchema.examples)
|
paramSchema.examples = getExamples(paramSchema.examples)
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.properties[param.name] = param.nullable
|
schema.properties[param.name] = param.nullable
|
||||||
? handleNullable(paramSchema)
|
? handleNullable(paramSchema)
|
||||||
: paramSchema
|
: paramSchema
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support openai strict mode by default (all params must be required,
|
||||||
|
// and optional params without defaults must be nullable)
|
||||||
|
|
||||||
schema.required = getRequiredParams(params)
|
schema.required = getRequiredParams(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,9 @@ export class AgenticToolClient extends AIFunctionsProvider {
|
||||||
name: tool.name,
|
name: tool.name,
|
||||||
description: tool.description ?? '',
|
description: tool.description ?? '',
|
||||||
inputSchema: createJsonSchema(tool.inputSchema),
|
inputSchema: createJsonSchema(tool.inputSchema),
|
||||||
|
// TODO: we should make sure all agentic tools support OpenAI strict
|
||||||
|
// mode by default.
|
||||||
|
strict: false,
|
||||||
execute: async (json) => {
|
execute: async (json) => {
|
||||||
return ky
|
return ky
|
||||||
.post(
|
.post(
|
||||||
|
|
|
@ -476,7 +476,7 @@ catalogs:
|
||||||
version: 3.25.67
|
version: 3.25.67
|
||||||
zod-to-json-schema:
|
zod-to-json-schema:
|
||||||
specifier: ^3.24.5
|
specifier: ^3.24.5
|
||||||
version: 3.24.5
|
version: 3.24.6
|
||||||
zod-validation-error:
|
zod-validation-error:
|
||||||
specifier: ^3.5.2
|
specifier: ^3.5.2
|
||||||
version: 3.5.2
|
version: 3.5.2
|
||||||
|
@ -1429,7 +1429,7 @@ importers:
|
||||||
version: 5.1.0
|
version: 5.1.0
|
||||||
zod-to-json-schema:
|
zod-to-json-schema:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 3.24.5(zod@3.25.67)
|
version: 3.24.6(zod@3.25.67)
|
||||||
|
|
||||||
packages/validators:
|
packages/validators:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1473,6 +1473,9 @@ importers:
|
||||||
ky:
|
ky:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.8.1
|
version: 1.8.1
|
||||||
|
openai-zod-to-json-schema:
|
||||||
|
specifier: ^1.1.1
|
||||||
|
version: 1.1.1(zod@3.25.67)
|
||||||
p-throttle:
|
p-throttle:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 6.2.0
|
version: 6.2.0
|
||||||
|
@ -1482,9 +1485,6 @@ importers:
|
||||||
zod:
|
zod:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 3.25.67
|
version: 3.25.67
|
||||||
zod-to-json-schema:
|
|
||||||
specifier: 'catalog:'
|
|
||||||
version: 3.24.5(zod@3.25.67)
|
|
||||||
zod-validation-error:
|
zod-validation-error:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 3.5.2(zod@3.25.67)
|
version: 3.5.2(zod@3.25.67)
|
||||||
|
@ -6338,11 +6338,6 @@ packages:
|
||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
browserslist@4.25.0:
|
|
||||||
resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==}
|
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
browserslist@4.25.1:
|
browserslist@4.25.1:
|
||||||
resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==}
|
resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==}
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
|
@ -6436,9 +6431,6 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
three: '>=0.126.1'
|
three: '>=0.126.1'
|
||||||
|
|
||||||
caniuse-lite@1.0.30001723:
|
|
||||||
resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==}
|
|
||||||
|
|
||||||
caniuse-lite@1.0.30001726:
|
caniuse-lite@1.0.30001726:
|
||||||
resolution: {integrity: sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==}
|
resolution: {integrity: sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==}
|
||||||
|
|
||||||
|
@ -7109,9 +7101,6 @@ packages:
|
||||||
ee-first@1.1.1:
|
ee-first@1.1.1:
|
||||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.167:
|
|
||||||
resolution: {integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==}
|
|
||||||
|
|
||||||
electron-to-chromium@1.5.177:
|
electron-to-chromium@1.5.177:
|
||||||
resolution: {integrity: sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==}
|
resolution: {integrity: sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==}
|
||||||
|
|
||||||
|
@ -9514,8 +9503,8 @@ packages:
|
||||||
resolution: {integrity: sha512-8EcOGJk/JXFaoGjeFM53Z3zBnwOpKtZeu5X0wts67WqA1PTnsmwRgUw9aGAsQ5V6cuTfJUv282h1ypFgDGPDSA==}
|
resolution: {integrity: sha512-8EcOGJk/JXFaoGjeFM53Z3zBnwOpKtZeu5X0wts67WqA1PTnsmwRgUw9aGAsQ5V6cuTfJUv282h1ypFgDGPDSA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
openai-zod-to-json-schema@1.0.3:
|
openai-zod-to-json-schema@1.1.1:
|
||||||
resolution: {integrity: sha512-CFU+KtOmX1dk2nPCZcGYgbrI3YLJJgMSehx1mLbH1A2fsRmZevHzMau6vFIhtkCpHWkGQ3ossA4a0OzVHlGrkw==}
|
resolution: {integrity: sha512-WIsQn2aXqqhRKVoDAQ7UG2W7K6q4FuJL7sn6lrj4bIHC6bbTYNFDfIw10yWCW3GX/zP2Psvubcmcb2NOCnSzsA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.23.8
|
zod: ^3.23.8
|
||||||
|
@ -11644,11 +11633,6 @@ packages:
|
||||||
zod-from-json-schema@0.0.5:
|
zod-from-json-schema@0.0.5:
|
||||||
resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==}
|
resolution: {integrity: sha512-zYEoo86M1qpA1Pq6329oSyHLS785z/mTwfr9V1Xf/ZLhuuBGaMlDGu/pDVGVUe4H4oa1EFgWZT53DP0U3oT9CQ==}
|
||||||
|
|
||||||
zod-to-json-schema@3.24.5:
|
|
||||||
resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
|
|
||||||
peerDependencies:
|
|
||||||
zod: ^3.24.1
|
|
||||||
|
|
||||||
zod-to-json-schema@3.24.6:
|
zod-to-json-schema@3.24.6:
|
||||||
resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
|
resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -11713,7 +11697,7 @@ snapshots:
|
||||||
delay: 6.0.0
|
delay: 6.0.0
|
||||||
jsonrepair: 3.12.0
|
jsonrepair: 3.12.0
|
||||||
ky: 1.8.1
|
ky: 1.8.1
|
||||||
openai-zod-to-json-schema: 1.0.3(zod@3.25.67)
|
openai-zod-to-json-schema: 1.1.1(zod@3.25.67)
|
||||||
p-throttle: 6.2.0
|
p-throttle: 6.2.0
|
||||||
type-fest: 4.41.0
|
type-fest: 4.41.0
|
||||||
zod: 3.25.67
|
zod: 3.25.67
|
||||||
|
@ -16690,14 +16674,13 @@ snapshots:
|
||||||
|
|
||||||
'@types/pg-pool@2.0.6':
|
'@types/pg-pool@2.0.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/pg': 8.6.1
|
'@types/pg': 8.15.4
|
||||||
|
|
||||||
'@types/pg@8.15.4':
|
'@types/pg@8.15.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.0.7
|
'@types/node': 24.0.7
|
||||||
pg-protocol: 1.10.3
|
pg-protocol: 1.10.3
|
||||||
pg-types: 2.2.0
|
pg-types: 2.2.0
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@types/pg@8.6.1':
|
'@types/pg@8.6.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -17165,8 +17148,8 @@ snapshots:
|
||||||
|
|
||||||
autoprefixer@10.4.21(postcss@8.5.6):
|
autoprefixer@10.4.21(postcss@8.5.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.25.0
|
browserslist: 4.25.1
|
||||||
caniuse-lite: 1.0.30001723
|
caniuse-lite: 1.0.30001726
|
||||||
fraction.js: 4.3.7
|
fraction.js: 4.3.7
|
||||||
normalize-range: 0.1.2
|
normalize-range: 0.1.2
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
|
@ -17300,13 +17283,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
browserslist@4.25.0:
|
|
||||||
dependencies:
|
|
||||||
caniuse-lite: 1.0.30001723
|
|
||||||
electron-to-chromium: 1.5.167
|
|
||||||
node-releases: 2.0.19
|
|
||||||
update-browserslist-db: 1.1.3(browserslist@4.25.0)
|
|
||||||
|
|
||||||
browserslist@4.25.1:
|
browserslist@4.25.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
caniuse-lite: 1.0.30001726
|
caniuse-lite: 1.0.30001726
|
||||||
|
@ -17417,8 +17393,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
three: 0.177.0
|
three: 0.177.0
|
||||||
|
|
||||||
caniuse-lite@1.0.30001723: {}
|
|
||||||
|
|
||||||
caniuse-lite@1.0.30001726: {}
|
caniuse-lite@1.0.30001726: {}
|
||||||
|
|
||||||
cannon-es-debugger@1.0.0(cannon-es@0.20.0)(three@0.177.0)(typescript@5.8.3):
|
cannon-es-debugger@1.0.0(cannon-es@0.20.0)(three@0.177.0)(typescript@5.8.3):
|
||||||
|
@ -17954,8 +17928,6 @@ snapshots:
|
||||||
|
|
||||||
ee-first@1.1.1: {}
|
ee-first@1.1.1: {}
|
||||||
|
|
||||||
electron-to-chromium@1.5.167: {}
|
|
||||||
|
|
||||||
electron-to-chromium@1.5.177: {}
|
electron-to-chromium@1.5.177: {}
|
||||||
|
|
||||||
email-validator@2.0.4: {}
|
email-validator@2.0.4: {}
|
||||||
|
@ -20778,7 +20750,7 @@ snapshots:
|
||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
'@swc/helpers': 0.5.15
|
'@swc/helpers': 0.5.15
|
||||||
busboy: 1.6.0
|
busboy: 1.6.0
|
||||||
caniuse-lite: 1.0.30001723
|
caniuse-lite: 1.0.30001726
|
||||||
postcss: 8.4.31
|
postcss: 8.4.31
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
@ -20983,7 +20955,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ky: 1.8.1
|
ky: 1.8.1
|
||||||
|
|
||||||
openai-zod-to-json-schema@1.0.3(zod@3.25.67):
|
openai-zod-to-json-schema@1.1.1(zod@3.25.67):
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.67
|
zod: 3.25.67
|
||||||
|
|
||||||
|
@ -23074,12 +23046,6 @@ snapshots:
|
||||||
|
|
||||||
unpipe@1.0.0: {}
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
update-browserslist-db@1.1.3(browserslist@4.25.0):
|
|
||||||
dependencies:
|
|
||||||
browserslist: 4.25.0
|
|
||||||
escalade: 3.2.0
|
|
||||||
picocolors: 1.1.1
|
|
||||||
|
|
||||||
update-browserslist-db@1.1.3(browserslist@4.25.1):
|
update-browserslist-db@1.1.3(browserslist@4.25.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.25.1
|
browserslist: 4.25.1
|
||||||
|
@ -23473,10 +23439,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.67
|
zod: 3.25.67
|
||||||
|
|
||||||
zod-to-json-schema@3.24.5(zod@3.25.67):
|
|
||||||
dependencies:
|
|
||||||
zod: 3.25.67
|
|
||||||
|
|
||||||
zod-to-json-schema@3.24.6(zod@3.25.67):
|
zod-to-json-schema@3.24.6(zod@3.25.67):
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.67
|
zod: 3.25.67
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
../.. | WARN `node_modules` is present. Lockfile only installation will make it out-of-date
|
||||||
|
../.. | Progress: resolved 1, reused 0, downloaded 0, added 0
|
|
@ -35,7 +35,7 @@
|
||||||
"delay": "catalog:",
|
"delay": "catalog:",
|
||||||
"jsonrepair": "catalog:",
|
"jsonrepair": "catalog:",
|
||||||
"ky": "catalog:",
|
"ky": "catalog:",
|
||||||
"zod-to-json-schema": "catalog:",
|
"openai-zod-to-json-schema": "^1.1.1",
|
||||||
"p-throttle": "catalog:",
|
"p-throttle": "catalog:",
|
||||||
"type-fest": "catalog:",
|
"type-fest": "catalog:",
|
||||||
"zod-validation-error": "catalog:"
|
"zod-validation-error": "catalog:"
|
||||||
|
|
|
@ -114,7 +114,7 @@ export function createAIFunction<
|
||||||
const args = input.function_call?.arguments
|
const args = input.function_call?.arguments
|
||||||
assert(
|
assert(
|
||||||
args,
|
args,
|
||||||
`Missing required function_call.arguments for function ${name}`
|
`Missing required function_call.arguments for function "${name}"`
|
||||||
)
|
)
|
||||||
return inputAgenticSchema.parse(args)
|
return inputAgenticSchema.parse(args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { z } from 'zod'
|
import type { z } from 'zod'
|
||||||
|
import { jsonrepair } from 'jsonrepair'
|
||||||
|
|
||||||
import type * as types from './types'
|
import type * as types from './types'
|
||||||
import { parseStructuredOutput } from './parse-structured-output'
|
import { parseStructuredOutput } from './parse-structured-output'
|
||||||
|
@ -102,7 +103,7 @@ export function asZodOrJsonSchema<TData>(
|
||||||
export function createJsonSchema<TData = unknown>(
|
export function createJsonSchema<TData = unknown>(
|
||||||
jsonSchema: types.JSONSchema,
|
jsonSchema: types.JSONSchema,
|
||||||
{
|
{
|
||||||
parse = (value) => value as TData,
|
parse,
|
||||||
safeParse,
|
safeParse,
|
||||||
source
|
source
|
||||||
}: {
|
}: {
|
||||||
|
@ -111,6 +112,15 @@ export function createJsonSchema<TData = unknown>(
|
||||||
source?: any
|
source?: any
|
||||||
} = {}
|
} = {}
|
||||||
): AgenticSchema<TData> {
|
): AgenticSchema<TData> {
|
||||||
|
parse ??= (value: unknown) => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
value = JSON.parse(jsonrepair(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use `cfValidateJsonSchema` from `@agentic/json-schema` here.
|
||||||
|
return value as TData
|
||||||
|
}
|
||||||
|
|
||||||
safeParse ??= (value: unknown) => {
|
safeParse ??= (value: unknown) => {
|
||||||
try {
|
try {
|
||||||
const result = parse(value)
|
const result = parse(value)
|
||||||
|
|
|
@ -60,4 +60,38 @@ describe('zodToJsonSchema', () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('handles optional properties in strict mode', () => {
|
||||||
|
const params = zodToJsonSchema(
|
||||||
|
z.object({
|
||||||
|
name: z.string().optional(),
|
||||||
|
age: z.number().optional().default(10)
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
strict: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(params).toEqual({
|
||||||
|
additionalProperties: false,
|
||||||
|
type: 'object',
|
||||||
|
required: ['name', 'age'],
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
anyOf: [
|
||||||
|
{
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'null'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
type: 'number',
|
||||||
|
default: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { z } from 'zod'
|
import type { z } from 'zod'
|
||||||
import { zodToJsonSchema as zodToJsonSchemaImpl } from 'zod-to-json-schema'
|
import { zodToJsonSchema as zodToJsonSchemaImpl } from 'openai-zod-to-json-schema'
|
||||||
|
|
||||||
import type * as types from './types'
|
import type * as types from './types'
|
||||||
import { omit } from './utils'
|
import { omit } from './utils'
|
||||||
|
@ -16,7 +16,7 @@ export function zodToJsonSchema(
|
||||||
return omit(
|
return omit(
|
||||||
zodToJsonSchemaImpl(schema, {
|
zodToJsonSchemaImpl(schema, {
|
||||||
$refStrategy: 'none',
|
$refStrategy: 'none',
|
||||||
target: strict ? 'openAi' : undefined
|
openaiStrictMode: strict
|
||||||
}),
|
}),
|
||||||
'$schema',
|
'$schema',
|
||||||
'default',
|
'default',
|
||||||
|
|
Ładowanie…
Reference in New Issue