kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
8aca815ccf
commit
6a985e5ccb
|
@ -1,10 +1,10 @@
|
|||
import type { ContentfulStatusCode } from 'hono/utils/http-status'
|
||||
import { Validator } from '@agentic/json-schema'
|
||||
import { HttpError } from '@agentic/platform-core'
|
||||
import { assert, HttpError } from '@agentic/platform-core'
|
||||
import plur from 'plur'
|
||||
|
||||
/**
|
||||
* Validates `data` against the provided JSON schema object.
|
||||
* Validates `data` against the provided JSON schema.
|
||||
*
|
||||
* This method uses a fork of `@cfworker/json-schema`. It does not use `ajv`
|
||||
* because `ajv` is not supported on CF workers due to its dynamic code
|
||||
|
@ -14,9 +14,7 @@ import plur from 'plur'
|
|||
* not running on CF workers, consider using `validateJsonSchemaObject` from
|
||||
* `@agentic/platform-openapi-utils`.
|
||||
*/
|
||||
export function cfValidateJsonSchemaObject<
|
||||
T extends Record<string, any> = Record<string, any>
|
||||
>({
|
||||
export function cfValidateJsonSchema<T = unknown>({
|
||||
schema,
|
||||
data,
|
||||
coerce = false,
|
||||
|
@ -25,16 +23,29 @@ export function cfValidateJsonSchemaObject<
|
|||
errorStatusCode = 400
|
||||
}: {
|
||||
schema: any
|
||||
data: Record<string, unknown>
|
||||
data: unknown
|
||||
coerce?: boolean
|
||||
strictAdditionalProperties?: boolean
|
||||
errorMessage?: string
|
||||
errorStatusCode?: ContentfulStatusCode
|
||||
}): T {
|
||||
// Special-case check for required fields to give better error messages.
|
||||
if (schema.required && Array.isArray(schema.required)) {
|
||||
assert(schema, 400, '`schema` is required')
|
||||
const isSchemaObject =
|
||||
typeof schema === 'object' &&
|
||||
!Array.isArray(schema) &&
|
||||
schema.type === 'object'
|
||||
const isDataObject = typeof data === 'object' && !Array.isArray(data)
|
||||
if (isSchemaObject && !isDataObject) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: `${errorMessage ? errorMessage + ': ' : ''}Data must be an object according to its schema.`
|
||||
})
|
||||
}
|
||||
|
||||
// Special-case check for required fields to give better error messages
|
||||
if (isSchemaObject && Array.isArray(schema.required)) {
|
||||
const missingRequiredFields: string[] = schema.required.filter(
|
||||
(field: string) => (data as T)[field] === undefined
|
||||
(field: string) => (data as Record<string, unknown>)[field] === undefined
|
||||
)
|
||||
|
||||
if (missingRequiredFields.length > 0) {
|
||||
|
@ -48,11 +59,12 @@ export function cfValidateJsonSchemaObject<
|
|||
// Special-case check for additional top-level fields to give better error
|
||||
// messages.
|
||||
if (
|
||||
isSchemaObject &&
|
||||
schema.properties &&
|
||||
(schema.additionalProperties === false ||
|
||||
(schema.additionalProperties === undefined && strictAdditionalProperties))
|
||||
) {
|
||||
const extraProperties = Object.keys(data).filter(
|
||||
const extraProperties = Object.keys(data as Record<string, unknown>).filter(
|
||||
(key) => !schema.properties[key]
|
||||
)
|
||||
|
|
@ -2,7 +2,7 @@ import type { AdminDeployment, Tool } from '@agentic/platform-types'
|
|||
import { assert } from '@agentic/platform-core'
|
||||
|
||||
import type { GatewayHonoContext, McpToolCallResponse } from './types'
|
||||
import { cfValidateJsonSchemaObject } from './cf-validate-json-schema-object'
|
||||
import { cfValidateJsonSchema } from './cf-validate-json-schema'
|
||||
|
||||
export async function createHttpResponseFromMcpToolCallResponse(
|
||||
_ctx: GatewayHonoContext,
|
||||
|
@ -35,7 +35,7 @@ export async function createHttpResponseFromMcpToolCallResponse(
|
|||
)
|
||||
|
||||
// Validate tool response against the tool's output schema.
|
||||
const toolCallResponseContent = cfValidateJsonSchemaObject({
|
||||
const toolCallResponseContent = cfValidateJsonSchema({
|
||||
schema: tool.outputSchema,
|
||||
data: toolCallResponse.structuredContent as Record<string, unknown>,
|
||||
coerce: false,
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { AdminDeployment, Tool } from '@agentic/platform-types'
|
|||
import { assert } from '@agentic/platform-core'
|
||||
|
||||
import type { GatewayHonoContext } from './types'
|
||||
import { cfValidateJsonSchemaObject } from './cf-validate-json-schema-object'
|
||||
import { cfValidateJsonSchema } from './cf-validate-json-schema'
|
||||
|
||||
export async function getToolArgsFromRequest(
|
||||
ctx: GatewayHonoContext,
|
||||
|
@ -48,7 +48,7 @@ export async function getToolArgsFromRequest(
|
|||
}
|
||||
|
||||
// Validate incoming request params against the tool's input schema.
|
||||
const incomingRequestArgs = cfValidateJsonSchemaObject({
|
||||
const incomingRequestArgs = cfValidateJsonSchema<Record<string, any>>({
|
||||
schema: tool.inputSchema,
|
||||
data: incomingRequestArgsRaw,
|
||||
errorMessage: `Invalid request parameters for tool "${tool.name}"`,
|
||||
|
|
|
@ -22,6 +22,18 @@ server.addTool({
|
|||
}
|
||||
})
|
||||
|
||||
server.addTool({
|
||||
name: 'add2',
|
||||
description: 'TODO',
|
||||
parameters: z.object({
|
||||
a: z.number(),
|
||||
b: z.number()
|
||||
}),
|
||||
execute: async (args) => {
|
||||
return String(args.a + args.b)
|
||||
}
|
||||
})
|
||||
|
||||
await server.start({
|
||||
transportType: 'httpStream',
|
||||
httpStream: {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { hashObject, HttpError } from '@agentic/platform-core'
|
||||
import { assert, hashObject, HttpError } from '@agentic/platform-core'
|
||||
import { betterAjvErrors } from '@apideck/better-ajv-errors'
|
||||
import Ajv, { type ValidateFunction } from 'ajv'
|
||||
import addFormats from 'ajv-formats'
|
||||
|
@ -19,7 +19,7 @@ const globalAjv = new Ajv({
|
|||
addFormats(globalAjv)
|
||||
|
||||
/**
|
||||
* Validates `data` against the provided JSON schema object.
|
||||
* Validates `data` against the provided JSON schema.
|
||||
*
|
||||
* This method uses `ajv` and is therefore not compatible with CF workers due
|
||||
* to its use of code generation and evaluation.
|
||||
|
@ -29,9 +29,7 @@ addFormats(globalAjv)
|
|||
*
|
||||
* @see https://github.com/ajv-validator/ajv/issues/2318
|
||||
*/
|
||||
export function validateJsonSchemaObject<
|
||||
T extends Record<string, unknown> = Record<string, unknown>
|
||||
>({
|
||||
export function validateJsonSchema<T = unknown>({
|
||||
schema,
|
||||
data,
|
||||
ajv = globalAjv,
|
||||
|
@ -42,10 +40,23 @@ export function validateJsonSchemaObject<
|
|||
ajv?: Ajv
|
||||
errorMessage?: string
|
||||
}): T {
|
||||
assert(schema, 400, '`schema` is required')
|
||||
const isSchemaObject =
|
||||
typeof schema === 'object' &&
|
||||
!Array.isArray(schema) &&
|
||||
schema.type === 'object'
|
||||
const isDataObject = typeof data === 'object' && !Array.isArray(data)
|
||||
if (isSchemaObject && !isDataObject) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: `${errorMessage ? errorMessage + ': ' : ''}Data must be an object according to its schema.`
|
||||
})
|
||||
}
|
||||
|
||||
// Special-case check for required fields to give better error messages
|
||||
if (Array.isArray(schema.required)) {
|
||||
if (isSchemaObject && Array.isArray(schema.required)) {
|
||||
const missingRequiredFields: string[] = schema.required.filter(
|
||||
(field: string) => (data as T)[field] === undefined
|
||||
(field: string) => (data as Record<string, unknown>)[field] === undefined
|
||||
)
|
||||
|
||||
if (missingRequiredFields.length > 0) {
|
||||
|
|
Ładowanie…
Reference in New Issue