Repository navigation
Conversation
LlamaBackend.withTextHistory() now declares tools through preface.tools, returns the runtime's parsed tool_calls from create, and replays assistant calls and tool results in the 0.19.0 Message shape native LiteRT-LM sends. A load-time probe reports supportsToolCalling only when the runtime reads preface.tools; ToolChoice.required, parallelToolCalls and tool-result content throw LlamaUnsupportedException, and automatic tool loops stay refused (#919). Fixes #1790 Refs #1874
…n the session budget A runtime tool call that followed streamed text was lost, because the engine parsed the whole reply as one JSON envelope. The Web backend now reports runtime calls through an internal BackendRuntimeToolCalls seam keyed on the generateChat stream; the parser appends them after any calls parsed from text, so preamble text stays content as on native. The Web session budget now renders tool declarations and assistant tool calls, and the load probe for preface.tools runs only when text history is supported.
This was referenced Nov 10, 2026
leehack
added a commit
that referenced
this pull request
Nov 10, 2026
leehack
added a commit
that referenced
this pull request
Nov 10, 2026
Owner
Author
|
Landed on main via batch integration PR #1895 (rebase merge, main |
12 of 13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LlamaBackend.withTextHistory()/LiteRtLmBackend.withTextHistory()on@litert-lm/[email protected].ToolDefinitions go topreface.tools; the runtime's parsedtool_callscome back fromChatSession.create/LlamaEngine.createastoolCalls, carried structurally (an internalBackendRuntimeToolCallsseam) so text the model streams before or after a call stays the reply's content, as on native; assistant calls andLlamaToolResultContentresults are replayed in the 0.19.0Messageshape native LiteRT-LM sends (calls intool_calls, results astool_responseparts), in order. A final tool-result message is sent as the request'sMessageobject.supportsToolCallingonly whencreateConversationreadspreface.tools; otherwise tools and tool history throwLlamaUnsupportedExceptionnaming the capability and@litert-lm/[email protected].ToolChoice.required,parallelToolCalls, tool-resultcontentand media throw;ToolChoice.nonedeclares no tools (as native). Automatic loops stay refused (Report LiteRT-LM Web token-limit truncation to the tool loop #919).litert-lm-web-tool-callinggives real-model evidence.Fixes #1790
Refs #1874
Production-readiness scope
create, run them, add tool results and continue the conversation on LiteRT-LM Web.withTextHistory()on runtimes that pass thepreface.toolsprobe (@litert-lm/[email protected]). Checked in headless Chrome 157 with Qwen3 0.6B (WASM CPU) and Gemma 4 E2B-web.litertlm(WebGPU, GPU_ARTISAN).LlamaBackend()/LiteRtLmBackend()constructors (reportsupportsToolCalling: false, unchanged); runtimes that ignorepreface.tools(typedLlamaUnsupportedException);sendWithTools/completeWithTools(unchanged typed refusal, no termination cause);ToolChoice.required,parallelToolCalls, tool-resultcontent, media (typed refusal before inference).Completeness checklist
PR type guidance
LlamaBackend.withTextHistory,LiteRtLmBackend,LlamaEngineCapabilities.supportsToolCalling/supportsMultiTurnChat), README, support matrix, tool-calling and backend-selection guides, chat app README, three skills, changelogs, capability coverage; happy and negative paths tested.Test Plan
dart run tool/prepare_workspace.dartdart format --output=none --set-exit-if-changed .dart analyzedart test -p vm -j 1 --exclude-tags local-only— CI. Locally:test/unit/core/+test/unit/backends/(all pass),test/unit/tooling/(all pass exceptwindows_registry_qualification_test.dart, which needspwsh, not installed here).dart test -p chrome --exclude-tags local-only— full run, 4676 pass locally at 7d4630f.coverage-lib— CI onmain: the VM-measured changes (chat_completion_stream_parser.dartruntime-call merge,engine.darthook,backend.dartregistry) are covered by the new parser tests and the Chrome engine-path tests; the backend itself is browser-only.litert-lm-web-tool-callingandlitert-lm-web-text-history(Qwen3 CPU, Gemma 4 WebGPU), chat appflutter test test test_vmplus the Chrome subset,validation_coverage_test.dart.Matrix Evidence
static-format-analyzelitert-lm-web-tool-callingtool_calls, result used, no-tools control, text before a call, cancel/reuse, resetc5f39b41…(613722264 B), WASM CPUget_weather {city: Paris}intool_calls; adapter same call, answer "violet hail … -7°C" from the tool result; no tools: no call. Preamble case: the model streamed "One moment, checking." then the call; adapter returned that text as content plus theget_weathercalllitert-lm-web-tool-calling3a08e8d9…(2008432640 B), WebGPU (GPU_ARTISAN)<|tool_call>that the runtime does not parse and the adapter leaves as textlitert-lm-web-text-historydocs-sitehigh-risk-exact-head-independent-qastructured-output-adversarialChatCompletionStreamParserMutation checks, all killed:
manual tool callinggroup (first round, 7): probe ignores consumption,reasoning_contentdropped,ToolChoice.nonedeclaring tools,parallelToolCallsaccepted, tool-resultcontentaccepted (SPI test), tools gate skipped, tool message sent as a string.legacy-probes-tools); chat-scope metadata unchanged;WebAutoBackenddrops calls; engine ignores the reporter.SUITES['tool-calling']mapped to the text-history file;--suiteignored. Failing-first: 5 of the 6 original tests fail againstorigin/main's backend (the rejection test passes there by design, since main rejects all tools).Review Notes
High-risk regression review
origin/main@litert-lm/[email protected]reference plus adapterSeams for #919 (lane 2)
generateChatreturns the_generateWithHistorystream itself (noasync*wrapper), so aBackendGenerationLimitReporting.generationLimitOf(stream)keyed on that stream sees the tool-calling path too. Runtime tool calls use the same pattern:BackendRuntimeToolCalls.runtimeToolCallsOf(stream), registered viaregisterRuntimeToolCallReporterand resolved withruntimeToolCallReporterOf(backend).WebAutoBackendforwardsruntimeToolCallsOfto its delegate; itsgenerationLimitOfstill delegates viadelegate is BackendGenerationLimitReporting, so lane 2 may need a registry lookup (generationLimitReporterOf) there.generationLimitUnsupportedReasonis unchanged; clearing it is what lets the core tool loop run.unreportedTruncationin_updateToolTemplateSupport) keys onkIsWeb && runtime == liteRtLm; relax it when Report LiteRT-LM Web token-limit truncation to the tool loop #919 lands.generate()behavior is unchanged (it only passesprompt.toJSto the shared run).