Adding custom tools to assistants
OpenAI, Ollama and Anthropic chats have, when instructed how, the capability to request function calls to be performed. Assistants mirror that capability.
To use it, we first need to define the function.
tool := GtLlmFunctionTool new name: 'lookupDocumentationPage'; parameters: {'pageName'}; description: 'Looks up a documentation page by name and returns its content in Markdown format. `pageName` may be a substring. If multiple pages are found, only the first one will be returned.'; block: [ :aFunctionCall | (LeDatabase gtBook asyncPagesForWord: aFunctionCall anyArgument) toArray wait ifEmpty: [ 'No page found' ] ifNotEmpty: [ :pages | pages first asMarkdownPage ] ]
We can then add it to the assistant’s provider. Please note that due to a technical limitation, tools and structured outputs do not play well together with Ollama assistants [1], and Anthropic does not formally support structured outputs [2]. Otherwise, both providers are equivalent.
assistant := GtLlmAssistant new description: 'You are an assistant that answers questions about Glamorous Toolkit (also: GToolkit or GT) by referring to the GToolkit book through tool search.'; providerStencil: [ :anInstructionFormat | GtOpenAIAssistantProvider withApiKeyFromFile format: anInstructionFormat asJsonSchema; assistantMessageClass: GtOpenAIActionMessage; userMessageClass: GtOpenAIActionMessage; addTool: tool; instructions: anInstructionFormat asInstructionPiece instructionString ]. assistant
Finally, we can use the chat as before.
chat := assistant createChat. chat sendChatRequest: 'Tell me about gt4llm.'
[1] This is because OpenAI uses a signal to interrupt the conversation to request a tool call and then resumes answering the question. In Ollama, the tool call is embedded in the answer, thus it’s an in-band communication channel.
[2] It is however usually able to adhere to the format even when not forced to.