fix(mlx): self-heal the UseMlx active-provider terminal client - #106
Merged
Conversation
…t-probe caps) Move the MLX self-heal into MlxProviderFactory so the UseMlx active-provider terminal client starts the mlx_lm runtime and advertises the verified tool-calling capability. CreateAsync now awaits EnsureRunningAsync before snapshotting capabilities (so the tool-calling probe has set ToolCallingVerified first) and returns the decorator stack wrapped outermost in EnsureRunningChatClient. CreateFactory() passes the extension; both factory ctors take it. Reworked factory tests drive SupportsToolCalling through the attach-first probe seam and cover the start path + wrapper identity. Tasks: 1.1, 1.2, 1.3, 3.1, 3.2, 3.3 Change: mlx-active-provider-self-heal Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reduce the keyed daemon helper MlxClient(key) to resolve the keyed MlxProviderExtension, build the ProviderConfig (BaseUrl null → factory falls back to the runtime-state URL seeded by EnsureRunningAsync), and return the factory's CreateAsync result verbatim. Drops the helper's duplicate up-front EnsureRunningAsync call and its own outer EnsureRunningChatClient wrap — both now supplied solely by the factory (Block 1), so the returned chain has exactly one self-heal wrapper and construction probes exactly once. Keyed port routing (firstline :8800 / escalation :8810) and the warm/stop seams are unchanged. Adds a regression test asserting the single wrapper and a single EnsureRunningAsync invocation. Tasks: 2.1, 2.2, 3.4, 4.1, 4.2 Change: mlx-active-provider-self-heal Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User confirmed a live sandbox-code .UseMlx(port 8666) turn: the model responded, created and ran a C hello-world, and prompted for tool permissions — verifying both runtime self-heal and tool-calling. All 12 tasks complete. Tasks: 4.3 Change: mlx-active-provider-self-heal Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Why
The
UseMlxactive-provider composition verb (shipped in #104) registered MLX as the active provider, but the terminalIChatClientit produced never started themlx_lmruntime. A standalone.UseMlx(model, port)agent threwConnection refused (127.0.0.1:8666)on its first turn, and — because the tool-calling probe never ran — reportedSupportsToolCalling == falseeven if a server were started by hand. The self-heal wrapper (EnsureRunningChatClient) existed but was wired only into the keyed daemon helperMlxClient(key), not the factory that builds the active-provider client.What changed
Block 1 — factory owns the self-heal (
55bd912)MlxProviderFactoryctor(s) gain anMlxProviderExtensionparameter;MlxProviderExtension.CreateFactory()passesthis.CreateAsyncis now genuinely async: itawaitsEnsureRunningAsyncfirst (so the tool-calling probe setsToolCallingVerifiedbeforeGetCapabilities()snapshots capabilities), then returns theChatClient → MlxMaxTokensDefaulter → CapabilitiesDecoratorstack wrapped outermost inEnsureRunningChatClient.Block 2 — single-source the keyed path (
af5bca4)MlxClientExtensions.MlxClient(key)reduced to resolve the keyed extension, build theProviderConfig, and return the factory's now-self-healing client — dropping its duplicate up-frontEnsureRunningAsynccall and its own outer wrapper. Exactly one wrapper, one probe. Keyed ports (firstline :8800 / escalation :8810) and the warm/stop seams (EscalationWarmingService,AddMlxFirstline/AddMlxEscalation,MlxRuntimeKeys) are unchanged.Scope
providers/Dmon.Providers.Mlx/+ its tests only. No core, ADR, or contract changes — ADR-027 (terminal-client selection) and ADR-034 (MLX runtime lifecycle) are honoured; this restores the intended self-heal. Clean-break internal ctor signature change (no published consumers).Verification
make build— 0 warnings (TreatWarningsAsErrors).env -u MEKO_API_KEY make test— full suite green;Dmon.Providers.Mlx.Tests88/88 (new coverage:CreateAsyncinvokesEnsureRunningAsync+ returns anEnsureRunningChatClient-wrapped client; advertisesSupportsToolCalling == truepost-probe; keyedMlxClient(key)returns a single-sourced self-healing client —ensureRunningCalls == 1).openspec validate mlx-active-provider-self-heal --strict— valid.sandbox-codeand ran a.UseMlx(port 8666)turn — the model responded, created and ran a C hello-world, and prompted for tool permissions. Confirms both runtime self-heal (noConnection refused) and tool-calling.Change:
mlx-active-provider-self-heal🤖 Generated with Claude Code