✨ (openai) Add tools and functions support (#1167)
Closes #863 Got helped from #1162 for the implementation. Closing it in favor of this PR. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced `CodeEditor` with additional properties for better form control and validation. - Introduced tools and functions in OpenAI integrations documentation for custom JavaScript execution. - Added capability to define and use custom JavaScript functions with the OpenAI assistant. - Expanded layout metadata options to include various input types and languages. - **Improvements** - Updated the OpenAI actions to support new function execution features. - **Documentation** - Added new sections for tools and functions in the OpenAI integrations guide. - **Refactor** - Refactored components and actions to integrate new features and improve existing functionalities. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@ -24,6 +24,24 @@ export const askAssistant = createAction({
|
||||
label: 'Message',
|
||||
inputType: 'textarea',
|
||||
}),
|
||||
functions: option
|
||||
.array(
|
||||
option.object({
|
||||
name: option.string.layout({
|
||||
fetcher: 'fetchAssistantFunctions',
|
||||
label: 'Name',
|
||||
}),
|
||||
code: option.string.layout({
|
||||
inputType: 'code',
|
||||
label: 'Code',
|
||||
lang: 'javascript',
|
||||
moreInfoTooltip:
|
||||
'A javascript code snippet that can use the defined parameters. It should return a value.',
|
||||
withVariableButton: false,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.layout({ accordion: 'Functions', itemLabel: 'function' }),
|
||||
responseMapping: option
|
||||
.saveResponseArray(['Message', 'Thread ID'] as const)
|
||||
.layout({
|
||||
@ -64,6 +82,40 @@ export const askAssistant = createAction({
|
||||
},
|
||||
dependencies: ['baseUrl', 'apiVersion'],
|
||||
},
|
||||
{
|
||||
id: 'fetchAssistantFunctions',
|
||||
fetch: async ({ options, credentials }) => {
|
||||
if (!options.assistantId) return []
|
||||
const config = {
|
||||
apiKey: credentials.apiKey,
|
||||
baseURL: options.baseUrl,
|
||||
defaultHeaders: {
|
||||
'api-key': credentials.apiKey,
|
||||
},
|
||||
defaultQuery: options.apiVersion
|
||||
? {
|
||||
'api-version': options.apiVersion,
|
||||
}
|
||||
: undefined,
|
||||
} satisfies ClientOptions
|
||||
|
||||
const openai = new OpenAI(config)
|
||||
|
||||
const response = await openai.beta.assistants.retrieve(
|
||||
options.assistantId
|
||||
)
|
||||
|
||||
return response.tools
|
||||
.filter((tool) => tool.type === 'function')
|
||||
.map((tool) =>
|
||||
tool.type === 'function' && tool.function.name
|
||||
? tool.function.name
|
||||
: undefined
|
||||
)
|
||||
.filter(isDefined)
|
||||
},
|
||||
dependencies: ['baseUrl', 'apiVersion', 'assistantId'],
|
||||
},
|
||||
],
|
||||
getSetVariableIds: ({ responseMapping }) =>
|
||||
responseMapping?.map((r) => r.variableId).filter(isDefined) ?? [],
|
||||
@ -77,6 +129,7 @@ export const askAssistant = createAction({
|
||||
message,
|
||||
responseMapping,
|
||||
threadId,
|
||||
functions,
|
||||
},
|
||||
variables,
|
||||
logs,
|
||||
@ -139,6 +192,45 @@ export const askAssistant = createAction({
|
||||
) {
|
||||
throw new Error(run.status)
|
||||
}
|
||||
if (run.status === 'requires_action') {
|
||||
if (run.required_action?.type === 'submit_tool_outputs') {
|
||||
const tool_outputs = (
|
||||
await Promise.all(
|
||||
run.required_action.submit_tool_outputs.tool_calls.map(
|
||||
async (toolCall) => {
|
||||
const parameters = JSON.parse(toolCall.function.arguments)
|
||||
|
||||
const functionToExecute = functions?.find(
|
||||
(f) => f.name === toolCall.function.name
|
||||
)
|
||||
if (!functionToExecute) return
|
||||
|
||||
const name = toolCall.function.name
|
||||
if (!name) return
|
||||
const func = AsyncFunction(
|
||||
...Object.keys(parameters),
|
||||
functionToExecute.code
|
||||
)
|
||||
const output = await func(...Object.values(parameters))
|
||||
|
||||
return {
|
||||
tool_call_id: toolCall.id,
|
||||
output,
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
).filter(isDefined)
|
||||
|
||||
run = await openai.beta.threads.runs.submitToolOutputs(
|
||||
currentThreadId,
|
||||
run.id,
|
||||
{ tool_outputs }
|
||||
)
|
||||
|
||||
await waitForRun(run)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await waitForRun(run)
|
||||
@ -170,3 +262,5 @@ export const askAssistant = createAction({
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
|
||||
|
||||
Reference in New Issue
Block a user