Tool Calling & Programmatic Prompts
Tools let the LLM call methods in your application during a conversation — query a database, look up an order, send an email, or any other action you want the assistant to be able to perform. Vaadin supports two ways to expose tools: registered tool objects (covered on this page) and framework-agnostic Controllers.
Tool Calling
Register objects with vendor-specific @Tool annotations that the LLM can invoke:
Source code
Java
public class WeatherTools {
@Tool("Get current weather for a city")
public String getWeather(String city) {
return weatherService.getCurrentWeather(city);
}
}
var orchestrator = AIOrchestrator
.builder(provider, systemPrompt)
.withMessageList(messageList)
.withInput(messageInput)
.withTools(new WeatherTools())
.build();For Spring AI, use @org.springframework.ai.tool.annotation.Tool. For LangChain4j, use @dev.langchain4j.agent.tool.Tool.
|
Note
|
Tool Threading
With a streaming provider or background execution, tool methods are invoked off the request thread, where UI.getCurrent() and other Vaadin thread locals are not available. Wrap component access in ui.access(), or capture the needed state before the turn starts.
|
|
Tip
|
Framework-Agnostic Tools via Controllers
For a reusable set of tools that does not depend on a specific LLM framework’s annotations, or when a lifecycle hook is needed after each LLM request cycle, implement AIController instead. GridAIController and ChartAIController are built-in examples. Controllers and tool objects can be combined on the same orchestrator.
|
|
Note
|
Tool Errors
Tool objects registered via withTools() are executed by the vendor framework, whose own error handling decides what the LLM sees when a tool throws — by default, both LangChain4j and Spring AI relay the raw message of any exception. To control what the LLM learns about failures, define the tool through a controller instead and throw a ToolException for messages the LLM is meant to see; see Tool Error Handling.
|
Programmatic Prompts
Send prompts without a Message Input component using prompt(). This is useful for triggering AI interaction from button clicks or other events:
Programmatic prompts go through the same pipeline as chat submits: a configured request interceptor can change or reject them before anything is sent.
|
Note
|
One Request at a Time
The orchestrator processes one prompt at a time. If prompt() is called while a previous request is still streaming, the new call is logged as a warning and silently dropped. Wait for the current response to complete before sending another prompt.
|
|
Important
|
UI Context Required
prompt() requires an active UI context. If called from a background thread or outside a Vaadin request, it throws an IllegalStateException. Always call prompt() from within a UI event handler or wrap the call in ui.access().
|