Scope check
Due diligence
What problem does this solve?
Currently RubyLLM only supports server-side execution of tools. However client-side tools can significantly enrich a chat experience: fetching page content, requesting the user's location, displaying custom components to gather input beyond just free-form text, etc.
Vercel's ai-sdk has first-class support for client-side tool calls:
https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-tool-usage
Proposed solution
- Support a
client_side macro on Tool subclasses, e.g.:
class RequestLocation < RubyLLM::Tool
description "Get the user's current geographic location"
client_side
end
-
Server calls execute normally, but client calls are skipped and a Tool::Pause is returned containing the client tool calls that the caller will need to handle. (I prefer to skip :on_tool_call for client tools but would defer to you on it)
-
After executing client tools, the caller resumes the conversation with existing APIs: chat.add_message(role: :tool, content: "...", tool_call_id: "call_1") and chat.continue.
I will be happy to open a PR for this change.
Why this belongs in RubyLLM
This can't be accomplished today without misusing halt and then correctly identifying and deleting the halted tool call result.
Scope check
Due diligence
What problem does this solve?
Currently RubyLLM only supports server-side execution of tools. However client-side tools can significantly enrich a chat experience: fetching page content, requesting the user's location, displaying custom components to gather input beyond just free-form text, etc.
Vercel's
ai-sdkhas first-class support for client-side tool calls:https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-tool-usage
Proposed solution
client_sidemacro onToolsubclasses, e.g.:Server calls execute normally, but client calls are skipped and a
Tool::Pauseis returned containing the client tool calls that the caller will need to handle. (I prefer to skip:on_tool_callfor client tools but would defer to you on it)After executing client tools, the caller resumes the conversation with existing APIs:
chat.add_message(role: :tool, content: "...", tool_call_id: "call_1")andchat.continue.I will be happy to open a PR for this change.
Why this belongs in RubyLLM
This can't be accomplished today without misusing
haltand then correctly identifying and deleting the halted tool call result.