How to encode Tool.Output (aka PromptRepresentable)?

Hey,

I've been trying to write an AI agent for OpenAI's GPT-5, but using the @Generable Tool types from the FoundationModels framework, which is super awesome btw!

I'm having trouble implementing the tool calling, though. When I receive a tool call from the OpenAI api, I do the following:

  1. Find the tool in my [any Tool] array via the tool name I get from the model
if let tool = tools.first(where: { $0.name == functionCall.name }) {
  // ...
}
  1. Parse the arguments of the tool call via GeneratedContent(json:)
let generatedContent = try GeneratedContent(json: functionCall.arguments)

  1. Pass the tool and arguments to a function that calls tool.call(arguments: arguments) and returns the tool's output type
private func execute<T: Tool>(_ tool: T, with generatedContent: GeneratedContent) async throws -> T.Output {
  let arguments = try T.Arguments.init(generatedContent)
  return try await tool.call(arguments: arguments)
}

Up to this point, everything is working as expected. However, the tool's output type is any PromptRepresentable and I have no idea how to turn that into something that I can encode and send back to the model. I assumed there might be a way to turn it into a GeneratedContent but there is no fitting initializer.

Am I missing something or is this not supported? Without a way to return the output to an external provider, it wouldn't really be possible to use FoundationModels Tool type I think. That would be unfortunate because it's implemented so elegantly.

Thanks!

Answered by Frameworks Engineer in 852752022

You could make your tool definition return a concrete type, e.g. String, or GeneratedContent. Then, add a generic constraint to your execute method on the T type.

private func execute<T: Tool>(_ tool: T, with generatedContent: GeneratedContent) async throws -> GeneratedContent where T.Output == GeneratedContent
Accepted Answer

You could make your tool definition return a concrete type, e.g. String, or GeneratedContent. Then, add a generic constraint to your execute method on the T type.

private func execute<T: Tool>(_ tool: T, with generatedContent: GeneratedContent) async throws -> GeneratedContent where T.Output == GeneratedContent

Thanks! That seems to do the trick 😃

To do this, I replaced all any Tool occurrences with this new protocol:

protocol MyAgentTool: Tool where Output: ConvertibleToGeneratedContent {}
How to encode Tool.Output (aka PromptRepresentable)?
 
 
Q