Adapters.toOpenAI
Java · package io.github.muthuishere:toolnexus · SPEC §4 · Adapters.java
public static List<Map<String, Object>> toOpenAI(List<Tool> tools)Turns a List<Tool> into the tools array an OpenAI-shaped chat completion expects. This is the
bridge between “toolnexus knows about these tools” and “the model can call them”.
When to use it
Section titled “When to use it”When you are driving the LLM call yourself and need schema to put in the request body. Every OpenAI-compatible endpoint takes this shape — OpenAI, OpenRouter, Groq, Together, a local Ollama, or your own gateway.
Why this and not the client
Section titled “Why this and not the client”tk.toOpenAI() on a Toolkit is the same function applied to that
toolkit’s tools — use it when you have a toolkit, and the static method when you have a bare list.
Examples
Section titled “Examples”1. One tool to OpenAI schema
Section titled “1. One tool to OpenAI schema”import io.github.muthuishere.toolnexus.*;import java.util.List;import java.util.Map;
public class Example { public static void main(String[] args) { Tool weather = NativeTool.of( "get_weather", "Current weather for a city", Map.of("type", "object", "properties", Map.of("city", Map.of("type", "string")), "required", List.of("city")), (Map<String, Object> a) -> "sunny in " + a.get("city") );
List<Map<String, Object>> schema = Adapters.toOpenAI(List.of(weather));
if (schema.size() != 1) throw new AssertionError("expected 1 entry"); if (!schema.get(0).get("type").equals("function")) throw new AssertionError("type");
@SuppressWarnings("unchecked") Map<String, Object> fn = (Map<String, Object>) schema.get(0).get("function"); if (!fn.get("name").equals("get_weather")) throw new AssertionError("name"); if (!fn.get("description").equals("Current weather for a city")) throw new AssertionError("description");
System.out.println("ok: " + fn.get("name")); }}Note the nesting: OpenAI wraps each tool in {"type":"function","function":{...}}. The
inputSchema() on a Tool becomes function.parameters — the key is renamed.
2. Feeding it straight into a request body
Section titled “2. Feeding it straight into a request body”The output is plain Maps and Lists, so any JSON library serializes it without help.
import io.github.muthuishere.toolnexus.*;import java.util.ArrayList;import java.util.List;import java.util.Map;
public class Example { static Tool mk(String name, String desc) { return NativeTool.of(name, desc, Map.of("type", "object", "properties", Map.of()), (Map<String, Object> a) -> name); }
public static void main(String[] args) { List<Tool> tools = List.of(mk("search", "Search the docs"), mk("ping", "Health check"));
Map<String, Object> body = Map.of( "model", "gpt-4o-mini", "messages", List.of(Map.of("role", "user", "content", "search for adapters")), "tools", Adapters.toOpenAI(tools) );
@SuppressWarnings("unchecked") List<Map<String, Object>> entries = (List<Map<String, Object>>) body.get("tools"); if (entries.size() != 2) throw new AssertionError("expected 2 tools");
// Order is preserved. List<String> names = new ArrayList<>(); for (Map<String, Object> e : entries) { @SuppressWarnings("unchecked") Map<String, Object> fn = (Map<String, Object>) e.get("function"); names.add((String) fn.get("name")); } if (!names.equals(List.of("search", "ping"))) throw new AssertionError("order: " + names);
System.out.println("ok: " + String.join(", ", names)); }}3. Round-tripping a call back to the tool
Section titled “3. Round-tripping a call back to the tool”Schema out, tool call in. The name() the model returns is the same name() you look up.
import io.github.muthuishere.toolnexus.*;import java.util.List;import java.util.Map;
public class Example { public static void main(String[] args) { Tool weather = NativeTool.of( "get_weather", "Current weather for a city", Map.of("type", "object", "properties", Map.of("city", Map.of("type", "string")), "required", List.of("city")), (Map<String, Object> a) -> "sunny in " + a.get("city") ); List<Tool> tools = List.of(weather);
// What a model would send back. OpenAI encodes arguments as a JSON STRING; // parse it with your JSON library before calling execute. String calledName = "get_weather"; Map<String, Object> parsedArgs = Map.of("city", "Chennai");
Tool called = tools.stream() .filter(t -> t.name().equals(calledName)) .findFirst() .orElseThrow(() -> new AssertionError("the advertised name should resolve back"));
ToolResult res = called.execute(parsedArgs, new ToolContext()); if (res.isError() || !res.output().equals("sunny in Chennai")) { throw new AssertionError(res.output()); }
// An empty tool list is valid — it just means "no tools this turn". if (!Adapters.toOpenAI(List.of()).isEmpty()) throw new AssertionError("expected empty");
System.out.println("ok: " + calledName + " -> " + res.output()); }}| Path | From | Notes |
|---|---|---|
[].type |
— | Always the literal "function". |
[].function.name |
Tool.name() |
What the model calls back with. |
[].function.description |
Tool.description() |
|
[].function.parameters |
Tool.inputSchema() |
Renamed — inputSchema → parameters. |
See also
Section titled “See also”Adapters.toAnthropic·Adapters.toGeminiToolkit.create—tk.toOpenAI()is this, applied to the toolkitLlmClient.create— calls the adapter for you