Several features for OpenAPI toolkit and OpenAI Assistants (#3989)

* Allows 'x-strict' attribute in OpenAPI spec tool and other json spec objects, this allows the OpenAI Assistant to have function calls with 'strict' mode. Also allows the OpenAI assistant to call several tools in the same run. And adds a checkbox 'remove Nulls' for the OpenAPI toolkit so that parameters with null values are not passed to the backend api.

* fix lint errors

---------

Co-authored-by: Olivier Schiavo <olivier.schiavo@wengo.com>
This commit is contained in:
owengo
2025-02-28 13:05:57 +01:00
committed by GitHub
parent 289c2591d6
commit e58c8b953d
3 changed files with 312 additions and 51 deletions
@@ -7,6 +7,20 @@ import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackCon
import { availableDependencies, defaultAllowBuiltInDep, prepareSandboxVars } from '../../../src/utils'
import { ICommonObject } from '../../../src/Interface'
const removeNulls = (obj: Record<string, any>) => {
Object.keys(obj).forEach((key) => {
if (obj[key] === null) {
delete obj[key]
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
removeNulls(obj[key])
if (Object.keys(obj[key]).length === 0) {
delete obj[key]
}
}
})
return obj
}
interface HttpRequestObject {
PathParameters?: Record<string, any>
QueryParameters?: Record<string, any>
@@ -104,6 +118,8 @@ export interface DynamicStructuredToolInput<
method: string
headers: ICommonObject
customCode?: string
strict?: boolean
removeNulls?: boolean
}
export class DynamicStructuredTool<
@@ -122,12 +138,15 @@ export class DynamicStructuredTool<
customCode?: string
strict?: boolean
func: DynamicStructuredToolInput['func']
// @ts-ignore
schema: T
private variables: any[]
private flowObj: any
private removeNulls: boolean
constructor(fields: DynamicStructuredToolInput<T>) {
super(fields)
@@ -140,6 +159,8 @@ export class DynamicStructuredTool<
this.method = fields.method
this.headers = fields.headers
this.customCode = fields.customCode
this.strict = fields.strict
this.removeNulls = fields.removeNulls ?? false
}
async call(
@@ -156,7 +177,7 @@ export class DynamicStructuredTool<
try {
parsed = await this.schema.parseAsync(arg)
} catch (e) {
throw new ToolInputParsingException(`Received tool input did not match expected schema`, JSON.stringify(arg))
throw new ToolInputParsingException(`Received tool input did not match expected schema ${e}`, JSON.stringify(arg))
}
const callbackManager_ = await CallbackManager.configure(
config.callbacks,
@@ -203,9 +224,15 @@ export class DynamicStructuredTool<
fs: undefined,
process: undefined
}
if (typeof arg === 'object' && Object.keys(arg).length) {
for (const item in arg) {
sandbox[`$${item}`] = arg[item]
let processedArg = { ...arg }
if (this.removeNulls && typeof processedArg === 'object' && processedArg !== null) {
processedArg = removeNulls(processedArg)
}
if (typeof processedArg === 'object' && Object.keys(processedArg).length) {
for (const item in processedArg) {
sandbox[`$${item}`] = processedArg[item]
}
}
@@ -262,4 +289,8 @@ export class DynamicStructuredTool<
setFlowObject(flow: any) {
this.flowObj = flow
}
isStrict(): boolean {
return this.strict === true
}
}