fix: auto-resolve two bug reports — plugin reattach isolation (#496) + routed-model usage attribution (#495) - #511
Draft
TYRMars wants to merge 2 commits into
Draft
fix: auto-resolve two bug reports — plugin reattach isolation (#496) + routed-model usage attribution (#495)#511TYRMars wants to merge 2 commits into
TYRMars wants to merge 2 commits into
Conversation
`PluginManager.#reattachOne` iterated a plugin's skills with no per-skill
error guard, and the MCP-server loop ran after it. One unreadable or
unparseable SKILL.md threw, aborting the rest of that plugin's reattach —
including every MCP server it declared — and `reattachInstalled`'s bare
`.catch(() => {})` swallowed the rejection, so an entire MCP integration
plus all sibling skills vanished silently on restart while
`GET /v1/plugins` kept reporting the plugin as fully installed.
- Wrap each skill's load/parse/insert in a per-skill try/catch that
records the failure and continues, matching `SkillCatalog.scanRoot`
and the MCP loop below it.
- Record (rather than silently swallow) per-MCP add failures too.
- Add `degraded` / `last_error` fields to the ledger entry, set at
reattach time (and cleared on a clean reattach), surfaced through
`list()` / `get()` so `GET /v1/plugins` no longer reports a
half-attached plugin as healthy.
- `reattachInstalled` now records whole-plugin failures (e.g. a corrupt
plugin.json) on the entry instead of dropping them on the floor.
Adds regression tests: one bad SKILL.md no longer takes down sibling
skills or the MCP server, the plugin is marked degraded, and a
subsequent clean reattach clears the marker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pdj9CWcTPhxPMi559vJpDz
…uting one (#495) Under JARVIS_ROUTER_ENABLED, RoutingProvider rewrites ChatRequest.model before delegating, but the agent loop stamped every `usage` event with the static `config.model`. So all token usage from routed turns was attributed to the pre-routing model, and the web UsagePanel priced it from a table keyed by that wrong name — under-reporting cost by up to two orders of magnitude with no anomaly visible (the expensive tier showed zero usage, and the "unknown model → partial estimate" safety valve never fired because the stale name is a valid known one). Propagate the effective model back through the provider seam: - Add an optional `model` to the `usage` LlmChunk variant and to ChatResponse (absent for plain providers). - RoutingProvider tags the streamed usage chunk and the blocking response with the resolved tier target — using `?? existing` so a downstream that reports its own model is respected. - agent.ts prefers `chunk.model ?? this.config.model`, so non-routing providers are unchanged while routed usage is attributed correctly. Adds regression tests: streamed + blocking routed usage carries the tier target model, and a downstream-set model is not overwritten. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pdj9CWcTPhxPMi559vJpDz
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.
Auto-resolves two independent bug reports, one commit each.
#496 — plugin reattach: one bad
SKILL.mdsilently kills a plugin's MCP servers + sibling skillsPluginManager.#reattachOneiterated a plugin's skills with no per-skill error guard, and the MCP-server loop ran after it. On server restart, one unreadable/unparseableSKILL.mdthrew and aborted the rest of that plugin's reattach — silently killing every MCP server it declared plus all sibling skills — whilereattachInstalled's bare.catch(() => {})swallowed the error andGET /v1/pluginskept reporting the plugin as fully installed (that data comes from the ledger, not live state).Fix (
packages/plugin/src/manager.ts):try/catcharound each skill's load/parse/insert, so one bad file can't take down siblings or MCP servers (matchesSkillCatalog.scanRootand the MCP loop's existing best-effort pattern).degraded/last_errorfields on the ledger entry, set at reattach time and cleared on a clean reattach, surfaced throughlist()/get()soGET /v1/pluginsstops reporting a half-attached plugin as healthy.reattachInstalledrecords whole-plugin failures (e.g. corruptplugin.json) on the entry.InstalledPlugintype gains the two optional fields.Tests: a corrupted installed
SKILL.mdis skipped while its sibling skill and the MCP server still come up and the entry is markeddegraded; a subsequent clean reattach clears the marker.#495 — routed usage priced against the wrong model under
JARVIS_ROUTER_ENABLEDThe agent loop stamped every
usageevent with the staticconfig.model, not the model the request actually ran on. With routing enabled,RoutingProviderrewrites the model before delegating, so all token usage from routed turns was attributed to the pre-routing model and the web UsagePanel priced it from a table keyed by that wrong name — under-reporting cost by up to two orders of magnitude, invisibly (the expensive tier showed zero usage; the "unknown model → partial estimate" safety valve never fired because the stale name is a valid known one).Fix (
packages/core,packages/router):modeladded to theusageLlmChunkvariant and toChatResponse(absent for plain providers).RoutingProvidertags the streamed usage chunk and the blocking response with the resolved tier target, using?? existingso a downstream that reports its own model wins.agent.tspreferschunk.model ?? this.config.model— non-routing providers unchanged, routed usage attributed correctly.Tests: streamed + blocking routed usage carries the tier-target model; a downstream-set model is not overwritten.
Verification
pnpm --filter @jarvis/plugin test→ 30/30;@jarvis/router→ 27/27;@jarvis/core→ 30/30. Lint clean on all changed files.pty.node/ an unbuilt UI dist, and a latentassert.oktype-narrowing error inrouter.test.ts's chain-reconciliation test (present onmain, identical before/after this change).🤖 Generated with Claude Code
https://claude.ai/code/session_01Pdj9CWcTPhxPMi559vJpDz