Images and speech
Three built-in toolkits in tnsai-tools let an agent generate images, speak text and transcribe audio. Each toolkit exposes one tool per provider, so the model can pick a provider at call time.
| Toolkit | BuiltInTool | Tools | Direction |
|---|---|---|---|
ImageGenTools | IMAGE_GEN_TOOLS | dalle3_generate, flux_generate, stability_generate | Text to image |
TextToSpeechTools | TEXT_TO_SPEECH_TOOLS | elevenlabs_tts, cartesia_tts, deepgram_tts | Text to speech |
SpeechToTextTools | SPEECH_TO_TEXT_TOOLS | deepgram_transcribe, assemblyai_transcribe, replicate_whisper | Audio file to text |
MEDIA_TOOLS adds the OpenAI pair: openai_tts and whisper_transcribe. Register it next to the others when you want OpenAI and another provider in the same agent.
Register the toolkits
Pass the toolkits to builtInTools(...). AgentBuilder.build() requires principal and authorityScope, and liabilitySink is optional.
package com.example.tnsai.docs;
import com.tnsai.accountability.AuthorityScope;
import com.tnsai.accountability.LiabilitySink;
import com.tnsai.agents.Agent;
import com.tnsai.agents.AgentBuilder;
import com.tnsai.enums.BuiltInTool;
import com.tnsai.identity.AgentPrincipal;
import com.tnsai.llm.providers.OpenAIClient;
import com.tnsai.roles.Role;
public final class ToolsMultimodalBuilderExample {
private ToolsMultimodalBuilderExample() {}
public static Agent build(
Role myRole,
AgentPrincipal principal,
LiabilitySink sink,
AuthorityScope scope
) {
return AgentBuilder.create()
.llm(new OpenAIClient("gpt-4o"))
.role(myRole)
.builtInTools(
BuiltInTool.IMAGE_GEN_TOOLS,
BuiltInTool.TEXT_TO_SPEECH_TOOLS,
BuiltInTool.SPEECH_TO_TEXT_TOOLS
)
.principal(principal)
.liabilitySink(sink)
.authorityScope(scope)
.build();
}
}The agent then calls the tools from a chat turn:
Agent artist = ToolsMultimodalBuilderExample.build(myRole, principal, sink, scope);
String reply = artist.chat("Draw a watercolor painting of a giraffe on Mars");Every tool returns a JSON string. Each tool checks its arguments before the HTTP call, so a bad value fails with IllegalArgumentException naming the allowed values.
Images: IMAGE_GEN_TOOLS
| Tool | Provider | Key | Returns |
|---|---|---|---|
dalle3_generate | OpenAI DALL-E 3 | OPENAI_API_KEY | provider, model (dall-e-3), urls, revised_prompt when the model rewrote the prompt |
flux_generate | FLUX on Replicate | REPLICATE_API_TOKEN | provider, model (flux-<model>), urls |
stability_generate | Stability AI Stable Image | STABILITY_API_KEY | provider, model, urls, finish_reason when present |
| Tool | Parameters | Defaults |
|---|---|---|
dalle3_generate | size: 1024x1024, 1792x1024, 1024x1792. quality: standard, hd. n: must be 1. | 1024x1024, standard, 1 |
flux_generate | model: schnell, dev, pro. aspectRatio, such as 1:1 or 16:9. outputFormat: webp, jpg, png. | schnell, 1:1, webp |
stability_generate | model: core, sd3, ultra. aspectRatio, such as 1:1 or 16:9. | core, 1:1 |
DALL-E and FLUX return provider-hosted URLs. DALL-E URLs expire about an hour after generation, so download the image if you need to keep it. Stability returns the image itself, and urls holds it as a data:image/png;base64,… URI.
Speech: TEXT_TO_SPEECH_TOOLS
| Tool | Provider | Key | Models or voices | Default |
|---|---|---|---|---|
elevenlabs_tts | ElevenLabs | ELEVENLABS_API_KEY | eleven_multilingual_v2, eleven_monolingual_v1, eleven_turbo_v2_5, eleven_flash_v2_5 | eleven_multilingual_v2, voice 21m00Tcm4TlvDq8ikWAM |
cartesia_tts | Cartesia | CARTESIA_API_KEY | sonic-2, sonic-english, sonic-multilingual | sonic-2, voice a0e99841-438c-4a64-b679-ae501e7d6091 |
deepgram_tts | Deepgram Aura | DEEPGRAM_API_KEY | 12 voices, such as aura-asteria-en and aura-orion-en | aura-asteria-en |
ElevenLabs and Cartesia take a voiceId next to the model. Deepgram picks the voice through model.
All three return the same shape:
{
"provider": "elevenlabs",
"model": "eleven_multilingual_v2",
"audio_uri": "data:audio/mpeg;base64,SUQzBAAAAAAAJ...",
"audio_bytes": 45920
}audio_uri plays directly in an <audio> element. Input is capped at 2000 characters per call.
Transcription: SPEECH_TO_TEXT_TOOLS
Each tool takes audioPath, the absolute path to a local file of at most 50 MB. Supported formats are MP3, WAV, M4A, OGG and FLAC.
| Tool | Provider | Key | Models | Returns |
|---|---|---|---|---|
deepgram_transcribe | Deepgram | DEEPGRAM_API_KEY | nova-2 (default), nova-2-general, nova-2-meeting, nova-2-phonecall, nova-3, enhanced, base | provider, model, text, language, confidence |
assemblyai_transcribe | AssemblyAI | ASSEMBLYAI_API_KEY | universal-2 | provider, model, text, language, audio_duration |
replicate_whisper | Whisper on Replicate | REPLICATE_API_TOKEN | large-v3 (default), large-v2, medium, small | provider, model (whisper-<model>), text, language when present |
deepgram_transcribe takes a language code, default en. assemblyai_transcribe takes an optional languageCode.
assemblyai_transcribe uploads the file, submits a job and polls it. Polling starts at two seconds, backs off to ten, and gives up after 300 seconds.
The OpenAI whisper_transcribe in MEDIA_TOOLS has its own 25 MB cap, and openai_tts caps input at 4096 characters.
API keys
| Variable | Used by |
|---|---|
OPENAI_API_KEY | dalle3_generate, whisper_transcribe, openai_tts |
REPLICATE_API_TOKEN | flux_generate, replicate_whisper |
STABILITY_API_KEY | stability_generate |
ELEVENLABS_API_KEY | elevenlabs_tts |
CARTESIA_API_KEY | cartesia_tts |
DEEPGRAM_API_KEY | deepgram_tts, deepgram_transcribe |
ASSEMBLYAI_API_KEY | assemblyai_transcribe |
A tool reads its key from the environment when it is called, not when the agent is built. You can register a toolkit without its keys. A call without the key throws IllegalStateException, and the message names the missing variable.
Related
- Catalog: every built-in toolkit.
- Audio:
WhisperClientfor transcription outside an agent. - Custom tools: write your own
@Toolmethods.