Repository navigation
ed-acp: on-device inference with Provider::Local - #20
Conversation
A third provider beside Onde Cloud and OpenAI API compatible endpoints: <PREFIX>_PROVIDER=local runs the agent's turns on the device with onde, offline and without a key. Behind an optional `local` feature, so cloud-only agents don't build mistral.rs; without it the provider can still be chosen and every turn says how to enable it. - LlmClient::complete converts the turn loop's OpenAI message and tool JSON to onde ChatTurns and ToolDefinitions and runs onde's stateless ChatEngine::complete, so sessions keep working as they do on the cloud: persisted, loaded and replayed with their tool calls. The reasoning and text of a turn are reported once the turn ends, since onde doesn't stream tool-aware turns yet. - One engine per process, loaded with the session's model on first use (downloaded the first time, with a thought saying so). Models come from onde's tool-calling catalogue, which models() lists. Default: Qwen3 4B Instruct 2507, or Qwen3 1.7B on iOS and Android. - No key is needed, so AUTH_REQUIRED doesn't apply and check_auth passes. A stored ONDE_API_KEY is not read as this provider's key. - --setup offers "On-device" when the feature is compiled in. Needs onde 1.4 (ChatEngine::complete). Until it is published the workspace patches onde to a sibling checkout. Checked end to end through LlmClient::complete with Qwen3 4B Instruct 2507: the model called the offered tool, then answered from its result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
This change introduces on-device inference as a new provider (Provider::Local) to ed-acp, allowing agents to run turns locally using onde, without requiring an API key or network access. The feature is optional and gated behind the local feature flag, so cloud-only builds do not include onde dependencies. The CLI setup flow is updated to offer the local provider when available, and the LlmClient logic is extended to route completions and model listings to the local engine when selected. The local.rs module handles conversion between OpenAI-style messages/tools and onde's formats, manages model loading, and provides test coverage for conversion logic and catalog correctness. If the feature is disabled, attempts to use the local provider return a clear error. The change is blocked on onde 1.4.0 being released, as noted in Cargo.toml and the comments. Previous review threads appear addressed, with new tests and feature gating in place.
Automated review by siGit Code Review · commit 15620a5 · see the review dashboard
1.3.2 ships ChatEngine::complete, so the path override to a sibling onde checkout is no longer needed. It also broke CI, where ../onde does not exist. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
This change introduces a new on-device inference provider (Provider::Local) to ed-acp, allowing agents to run turns locally using onde's engine when built with the local feature. The provider is integrated into the setup flow, configuration, and model listing. The implementation ensures that only one model is loaded at a time per process, and the provider is selectable even when the feature is disabled, with clear error messaging. The code includes conversion between OpenAI-style messages/tools and onde's internal types, and is covered by targeted tests. The onde dependency is bumped to 1.3.2 to support the required API. Previous findings about engine locking have been addressed as intentional and documented.
Automated review by siGit Code Review · commit 48cb619 · see the review dashboard
Adds a third provider next to Onde Cloud and OpenAI API compatible endpoints.
<PREFIX>_PROVIDER=localruns the agent's turns on the device with onde, offline and without a key.It sits behind an optional
localfeature, so cloud-only agents don't build mistral.rs. Without the feature the provider can still be chosen, and every turn says how to enable it.LlmClient::completeconverts the turn loop's OpenAI message and tool JSON to ondeChatTurns andToolDefinitions, then runs onde's statelessChatEngine::complete(Add ChatEngine::complete for caller-owned conversations onde#20). Sessions therefore keep working as they do on the cloud: persisted, loaded and replayed with their tool calls. A turn's reasoning and text arrive when the turn ends, since onde doesn't stream tool-aware turns yet.models()lists. The default is Qwen3 4B Instruct 2507, or Qwen3 1.7B on iOS and Android.AUTH_REQUIREDdoesn't apply andcheck_authpasses. A storedONDE_API_KEYisn't read as this provider's key.--setupoffers "On-device" when the feature is compiled in.Blocked on onde 1.4.0. The workspace patches
ondeto a sibling checkout for now, so CI can't build this PR. Once onde 1.4.0 is on crates.io, the patch goes away and the workspace requiresonde = "1.4".The design is in smbcloudXYZ/splitfire
.agents/specs/splitfire-ai-agent/on-device-inference.md.Tested
cargo test -p ed-acp: 35 tests, including the new ones for the message and tool conversion, the default model being in the catalog, and the local config needing no key.local, and on the whole workspace.LlmClient::completewith Qwen3 4B Instruct 2507: the model called the offered tool (theory_chord {"symbol":"F#m7b5"}), then answered "F#, A, C, and E" from its result. Usage was reported (160 prompt and 26 completion tokens).