denisovav/flutter_edge_ai/flutter-edge-ai-function-calling
- community
Checking that the SKILL.md file is still in the repository.
Use when adding function calling (tool calling) to a flutter_edge_ai chat — letting an on-device model call the app's own Dart functions, declaring Tool objects, handling FunctionCallResponse or ParallelFunctionCallResponse, returning results with Message.toolResponse, or running the built-in tool loop generateChatResponseWithTools. Also use when the model describes an action in prose instead of calling the tool, raw tool-call markers appear in the reply text, or a switch over ModelResponse fai…
Install
npx vskill@latest install denisovav/flutter_edge_ai/flutter-edge-ai-function-callingSKILL.md
Function calling with flutter_edge_ai
Packages, engine and model install are in the flutter-edge-ai-inference skill. This one starts from a loaded InferenceModel.
Rules
createChatneedstoolsandsupportsFunctionCalls: true. Without the flag no call is parsed and only a debug warning is logged — and on.litertlmwith Gemma 4 or FunctionGemma the declarations still reach the SDK, so the model answers with raw tool-call JSON inside the text stream.- Pass
modelTypeon web and on ONNX.createChaton native.litertlm, on MediaPipe Android and iOS, and on built-in AI uses the installed model's type when it is left out; the web engines and ONNX fall back toModelType.gemmaIt, and another model's calls then arrive as raw text.openChatalways falls back — pass it there on every platform. Onflutter_edge_ai_llama(GGUF) llamadart reads the calls through the file's own chat template:modelType, whichcreateChatandopenChatboth take from the install, only picks sampling defaults, and the tools are on unlesssupportsFunctionCalls: false. - Switch over all four
ModelResponsesubtypes. It is sealed — a switch that leaves outThinkingResponsedoes not compile. - Return tool results as data, errors included. Never throw from a tool.
- Prefer
generateChatResponseWithToolsto a hand-written loop. - Use a model that can call tools (https://flutteredge.ai/docs/models):
Gemma 4, FunctionGemma, Phi-4 Mini, Qwen 2.5, Qwen3, DeepSeek R1, Gemma 3n E4B .litertlm, or the OS built-in model. Gemma 3 1B, Gemma 3 270M, SmolLM, SmolLM3, LFM2.5, Phi-4 Mini Reasoning and the vision models (FastVLM, Qwen2-VL, SmolVLM2, LLaVA-OneVision) cannot — they describe the action in prose instead. A GGUF model through flutter_edge_ai_llama can call tools when its chat template supports them.
Declare a tool
parameters is a JSON Schema object. The model matches the user's intent against description, so write it as an action and describe every parameter.
Open the chat
The built-in loop
It calls the handler for each tool call, feeds the result back, and continues until the model answers in text or maxToolTurns is reached.
Gemma 4 often writes a sentence, then calls a tool. The sentence streams as TextResponse, so the snippet clears the buffer when a call arrives, as flutter_edge_ai_agent does; the chat's history keeps only the call (its tool_calls objects), not the sentence. Without supportsFunctionCalls: true, or with toolChoice: ToolChoice.none, the call's JSON stays in the text instead.
onToolCall receives a FunctionCallResponse with name and args, and returns the map the model reads back. args keeps the JSON types the model wrote — numbers, booleans, null, nested maps and lists, not only strings — so read a number as num. Its id is null on the .litertlm, MediaPipe, ONNX and built-in AI engines; flutter_edge_ai_llama gives every call one, and genai callIds and Genkit refs carry theirs. The stream carries TextResponse and ThinkingResponse. Reaching maxToolTurns ends the stream without an error — onMaxToolTurns is the only signal. An exception from onToolCall is answered to the model as {"error": …}, and a result jsonEncode cannot write (a DateTime, say) as {"status": "ran", …}, because the tool did run — do not run it again. The turn's other calls are answered as not run, and the error is rethrown on the stream. When an answer cannot be fed (a session closed by a barge-in), that failure is printed and the tool's own error is still the one rethrown; recreate the chat, or clearHistory(replayHistory:), before the next turn.
Handling calls yourself
Calls in a history
A chat records each call as Message.toolCall(calls:) (flutter_edge_ai 2.4.0): toolCalls holds the structured FunctionCallResponses with their ids, and text is what text engines replay — for a .litertlm call, its tool_calls objects without the text written before them. To restore a conversation, keep both, and pair each result with its call through toolCallId:
Message.toolCall with calls alone writes text as {"tool_calls":[{"id","name","arguments"}]}. Only flutter_edge_ai_llama reads toolCallId — pass it there when two calls share a name and their results go back out of order; the other engines pair a result with its call by toolName, in order.
Errors are results
The model can recover from an error it can read. An exception thrown out of a tool ends the turn instead.
Traps
Model answers in prose
- Symptom: "I would change the colour to red" instead of a call.
- Fix: check
supportsFunctionCalls: true, passmodelTypeon web and ONNX, then check the model is tool-capable.
Raw markers in the text
- Symptom:
<|tool_call>or<tool_call|>appears inTextResponsetokens. - Fix:
modelTypedoes not match the installed model — or the call was cut off or malformed. A raw Gemma 4 call runs with its typed arguments or not at all (flutter_edge_ai2.4.1): if one call of the turn does not parse in full — cut off bymaxOutputTokens, say — none of that turn's calls runs and the text stays as it came. RaisemaxOutputTokens.
Model calls the same tool again instead of answering the result
- Symptom: FunctionGemma on
.litertlmrepeats the call it just made afterMessage.toolResponse. - Fix: upgrade
flutter_edge_aiandflutter_edge_ai_litertlmtogether. The
current renamed packages include both halves. For the legacy package names, the minimum fixed pair was flutter_gemma 1.8.4 with flutter_gemma_litertlm 1.7.1; older pairs send the result as an ordinary user message.
Nothing after the tool result
- Symptom: the call arrives, the result goes back, and the stream ends with no text.
- Fix: nothing to fix on FunctionGemma — it is an action model and ending the turn at the call is what it was trained for. Render the tool's own result, and use Gemma 4 when the model should talk about what came back.
Web
Function calling works on the .litertlm web engine. Pass modelType. On web createSession and createChat hold one slot: a second createChat while the first is open hands back the open session, history and all. Close the chat before creating the next, or use openChat for conversations that run side by side.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingpackages/flutter_edge_ai/skills/flutter-edge-ai-function-calling/SKILL.md
Popularity
- Repository stars
- 649
- Repository forks
- 175
- 7-day trend score
- 5
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/denisovav/flutter_edge_ai/flutter-edge-ai-function-calling)