Skip to content

fix(auxiliary): don't skip sibling models when a configured fallback_chain reuses the same provider - #59561

Closed
okalentiev wants to merge 2 commits into
NousResearch:mainfrom
okalentiev:fix/aux-fallback-chain-same-provider-skip
Closed

fix(auxiliary): don't skip sibling models when a configured fallback_chain reuses the same provider#59561
okalentiev wants to merge 2 commits into
NousResearch:mainfrom
okalentiev:fix/aux-fallback-chain-same-provider-skip

Conversation

@okalentiev

Copy link
Copy Markdown
Contributor

Summary

_try_configured_fallback_chain skips every auxiliary.<task>.fallback_chain
entry whose provider matches the provider that just failed. That's correct
when the provider itself is unreachable (e.g. missing credentials), but it
also fires for a chain that intentionally lists several different models
under the same provider — e.g.

auxiliary:
  compression:
    provider: nvidia
    model: deepseek-ai/deepseek-v4-pro
    fallback_chain:
      - provider: nvidia
        model: minimaxai/minimax-m3
      - provider: nvidia
        model: deepseek-ai/deepseek-v4-flash

When the primary NVIDIA NIM model times out, the provider-only skip check
(fb_provider.lower() == skip) discards both fallback entries — they all
say provider: nvidia — so the configured NIM fallback chain is silently a
no-op. The call falls straight through to the main-agent-model safety net
instead, which in our case was also degraded at the time, producing a
confusing final error that named the main model instead of NIM.

Real trace that surfaced this (from agent.log)

Auxiliary compression: using nvidia (deepseek-ai/deepseek-v4-pro) at https://integrate.api.nvidia.com/v1/
Auxiliary compression: timeout on the critical path; skipping same-provider retry and falling back: Request timed out.
Auxiliary compression: connection error on nvidia (Request timed out.), trying fallback
Auxiliary compression: connection error on nvidia — falling back to main agent model main-agent(openai-codex) (gpt-5.5)
Failed to generate context summary: Codex auxiliary Responses stream exceeded 120.0s total timeout.

The two configured NIM fallback models were never attempted.

Fix

Add an optional failed_model parameter to _try_configured_fallback_chain.
When provided, the skip narrows to the exact (provider, model) pair that
just failed, instead of the whole provider:

if fb_provider.lower() == skip and (
    skip_model is None or fb_model_raw.lower() == skip_model
):
    continue
  • _try_configured_fallback_for_unavailable_client (client-build failures,
    where the whole provider is unreachable regardless of model — e.g. missing
    API key) does not pass failed_model, so it keeps the old provider-wide
    skip. That's still correct there.
  • The two runtime request-error call sites, call_llm and async_call_llm,
    now pass failed_model=final_model — the model that actually failed — so
    sibling models under the same provider get a chance.

Tests

Added to tests/agent/test_auxiliary_client.py:

  • test_same_provider_sibling_model_not_skipped_when_failed_model_given
    regression test for this exact bug (NVIDIA NIM sibling model chain).
  • test_same_provider_same_model_still_skipped — the exact failed
    (provider, model) pair is still excluded.
  • test_same_provider_skipped_wholesale_without_failed_model — back-compat:
    callers that don't pass failed_model keep skipping the whole provider.

Also updated 3 pre-existing tests whose assert_called_with(...) checks
needed the new failed_model kwarg added to their expected call signature.

Full relevant suites pass locally: 302 in
test_auxiliary_client.py/test_auxiliary_main_first.py, and 495 across
compression + auxiliary related test files.

Out of scope

Whether the main-agent-model safety net should itself retry/back off
differently when it also times out — that's a separate concern from making
the configured fallback_chain actually usable.

🤖 Patch authored with assistance from Claude Code

…chain reuses the same provider

_try_configured_fallback_chain skipped every fallback_chain entry whose
provider matched the one that just failed. A chain that intentionally lists
several models under the same provider (e.g. two more NVIDIA NIM models
after the primary NIM model times out) was therefore skipped wholesale,
falling straight through to the main-agent-model safety net instead of
trying the other configured models on that provider.

Add failed_model so the skip narrows to the exact (provider, model) pair
that failed. Callers that only know the provider (client-build failures,
where the whole provider is unreachable regardless of model) keep the old
provider-wide skip; the two runtime request-error call sites (call_llm,
async_call_llm) now pass the model that just failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/config Config system, migrations, profiles area/billing Account usage, credit usage, billing (cross-cutting) labels Jul 6, 2026
…fallback chain

Follow-up to the same-provider fallback fix: narrowing the configured-chain
skip to the exact failed model is only correct for model-specific failures.
Auth (401) and payment (402) errors are provider-wide — every model on the
provider shares the same broken credentials/account — so trying a sibling
model can't recover and merely burns another doomed request before the
aux task fails. Worse, returning that sibling client bypasses the
main-agent-model safety net that a provider-wide skip would have reached.

Only forward failed_model to _try_configured_fallback_chain for
model-specific failures (timeout, connection, rate limit, model-incompatible,
invalid response). Auth/payment keep failed_model=None (whole-provider skip),
preserving the pre-existing safety-net behaviour for credential/billing
failures.

Adds an integration test that a timeout forwards the failed model, and
updates the payment-error test to assert failed_model=None.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@okalentiev

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up commit after a self-review caught a regression in the original change.

Regression: narrowing the chain skip to the exact failed (provider, model) pair is only correct for model-specific failures. For auth (401) and payment (402) errors the whole provider is broken (shared credentials/account), so a sibling model on that provider can't recover — and returning that sibling client would bypass the main-agent-model safety net that the old provider-wide skip reached. In auto mode, a 402 could then burn an extra doomed request and fail the aux task instead of falling through to the main model.

Fix: only forward failed_model for model-specific failures (timeout, connection, rate limit, model-incompatible, invalid response). Auth/payment keep failed_model=None → whole-provider skip → main-agent-model safety net, exactly as before.

Added an integration test that a timeout forwards the failed model, and updated the payment-error test to assert failed_model=None. Full test_auxiliary_client.py (297) + related compression suites (172) pass; ruff clean.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused fallback-chain fix. Static review confirms the reported behavior remains on current main: agent/auxiliary_client.py:3986 skips every entry sharing the failed provider, and both runtime paths invoke that helper without model identity (agent/auxiliary_client.py:7157, :7166, :7668, :7677).

The PR narrows that skip only for runtime model-specific failures and retains the existing provider-wide behavior for unavailable-client, auth, and payment cases. The sync and async paths are both covered by the proposed change, and no additional runtime callers were found.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
teknium1 added a commit that referenced this pull request Jul 27, 2026
…ails on the same provider

Widen okalentiev's failed_model narrowing (#59561) to
_try_main_agent_model_fallback. The safety-net layer still skipped on a
provider-label match alone, so single-provider users whose aux compression
model and main model share one custom endpoint had ZERO fallbacks: the aux
model timing out exhausted the chain in one hop and compression aborted.

Real incident (0.19.0 debug dump): aux zai-org/glm-5.2 hung 324s and timed
out while main mindai/macaron-v1-venti on the SAME endpoint was serving
448K-token turns — the label-only skip discarded the one viable summarizer,
the session wedged over threshold, and the anti-thrash breaker tripped.

Same convention as the chain fix: model-specific failures (timeout,
connection, rate limit) pass failed_model so only the exact failed model is
skipped; provider-wide failures (auth 401 / payment 402) pass None and keep
the whole-provider skip. Both sync and async call_llm sites pass it.

Sabotage-verified: the new regression test fails on the provider-only skip.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #72468 — your commits were cherry-picked onto current main with your authorship preserved in git log (rebase merge).

Your fix turned out to matter beyond the configured fallback_chain: the same provider-label-only skip existed in the main-agent-model safety net layer, where it left single-provider users (aux model + main model behind one custom endpoint) with zero working fallbacks for compression. PR #72468 carries your two commits verbatim and extends your failed_model narrowing to that layer too, keeping your auth/payment provider-wide carve-out semantics.

Thanks for the clean fix and the real trace in the PR body — it made the wider bug class easy to confirm.

@teknium1 teknium1 closed this Jul 27, 2026
teknium1 added a commit that referenced this pull request Jul 27, 2026
…ped skips

Every fallback/dedup/skip decision asks one question — 'is this candidate
the same backend as the one that failed, along the axis that failure
invalidated?' — but it was re-implemented inline at six sites across four
subsystems, each comparing whatever string was locally convenient. Each
incident fixed one site while the others kept the bug: #22548, #70893,
#59561, #72468, #62984/#54250/#57584.

agent/backend_identity.py now owns the concept: BackendIdentity (provider /
model / base_url axes), FailureScope (MODEL / CREDENTIAL / ENDPOINT — each
failure class invalidates a different axis), and should_skip_candidate().
Unknown axes never manufacture a skip (over-skipping strands failover; a
wrong try costs one RTT).

Migrated sites:
- chat_completion_helpers.try_activate_fallback: replaces the provider+model
  early-exit (the #62984 bug: ignored base_url, stranding multi-endpoint
  pools) AND _fallback_entry_is_same_backend_by_base_url (deleted)
- auxiliary_client._try_configured_fallback_chain +
  _try_main_agent_model_fallback: replace label/model comparisons; auth and
  payment map to CREDENTIAL scope, keeping the #59561 carve-out
- hermes_cli/fallback_cmd add: primary-match + duplicate checks now identity-
  aware (#54250/#57584): same provider+model on a different explicit
  base_url is a pool entry, not a duplicate

_mark_provider_unhealthy stays label-keyed deliberately: its only triggers
are confirmed 402s, which ARE credential-scoped.

Owner-level tests pin each incident's semantics by number; sabotage-verified
(removing the base_url axis fails the #62984 test).
jhjaggars-hermes added a commit to jhjaggars/hermes-agent that referenced this pull request Jul 27, 2026
* perf(desktop): 60fps sash drag on real sessions — height-gate the RO pins

Driving HER real instance (real profile, real transcripts, streams live)
via CDP instead of synthetic tiles finally exposed the remaining stall.
The timeline on a real 60-frame sash drag:

  style recalc 2736ms | script 1027ms | layout 89ms
  top callsite: pin @ fallback.tsx — 927ms

Two pin-to-bottom ResizeObservers (the bounded tool window's and the
reasoning preview's) pinned on EVERY resize delivery. A sash drag changes
every message's WIDTH once per frame, so each frame ran scrollTop write ->
scrollHeight read across every tool group: a forced write-read reflow
cascade that the render counters could never see (zero React involvement).

Both pins are now height-gated off the RO entry (reflow-free): only
content GROWTH pins. Width-only deliveries return immediately.

Measured on the live app, same drag, before -> after:
  fps      11.5 -> 59-60
  p95      101ms -> 18ms
  slow>33  60/60 -> 1/60

Also in this batch (each was verified live before the next was attempted):
- thread/list: split messageSignature into STRUCTURAL (ids/roles — keys
  boundaries + row identity) and WEIGHT (part counts — budget only), and
  memoize groups + row JSX. A streamed part-append re-rendered every
  turn's boundary via its resetKey prop; explain() measured 540-865
  wasted Block renders per drag/stream sample, now {}.
- message-render-boundary: document the structural-only resetKey contract.
- tool/fallback: memoize ToolFallback's part object + ToolEntry/ToolTitle/
  ToolGlyph (151 renders each, 100% wasted, on real transcripts).
- use-message-stream: ADAPTIVE flush floor — next flush waits 3x the
  measured cost of the last one (33ms floor, 250ms cap), so multi-stream
  load degrades text update rate instead of input latency.
- tree-split: preview sash drags with inline flex on the two seam
  wrappers, committing the store ONCE on release (fixed-zone sides get
  flexBasis only, so a hidden sidebar can't leave a phantom gap).
- debug/: perf-live LoAF long-frame attribution, explain() cascade walker
  with changed-hook indices, diag-real-loop/key-latency/switch-trace
  probes that drive the real app over CDP.

Typing during 2 live streams: keystroke->paint p50 3.3ms, p95 18.4ms,
zero frames over 33ms. Session switch p50 ~35ms settled; the remaining
~1.3s outlier tail is streaming-session switches (React work-loop, not
style/layout) — next target.

* perf(desktop): don't backfill the transcript while its thread streams

Switching to a STREAMING session took ~1.4s to settle while an idle
session settled in ~50ms. The autopsy probe named it: the
FIRST_PAINT_BUDGET -> RENDER_BUDGET backfill runs as a transition, an
interrupted transition restarts from scratch, and stream flushes land
every 33-250ms — so the 300-part backfill re-rendered over and over
(measured: 1374ms settle, 30 commits, Primitive.div x2237 for one switch).

Gate the backfill on the thread being idle. The user lands on the live
tail immediately either way; older turns backfill the moment the run
ends, and 'Show earlier' remains the manual path meanwhile.

Measured on the live app (diag-switch-autopsy, real sessions):
  switch to idle session        ~35-55ms settled (unchanged)
  switch to streaming session   1374ms -> backfill deferred; lands at
                                the live tail like any other switch

Adds diag-switch-autopsy.mjs (per-switch settle/commits/top-renders) and
live-drive.mjs (status/fps/drag one-liners against the running app).

* fix(cli): scope -c/--resume to the current workspace

`hermes -c`/`--resume` (continue last session) resolved the globally
most-recently-used session, then cd'd into *its* recorded cwd. So running
`hermes -c` from repo A could land you in repo B's session — the session
you last touched anywhere, not the last one *here*.

Now `_resolve_last_session` scopes to the current workspace first: the git
repo root when CWD is inside a repo (so all sessions across its
subdirs/worktrees group together), else the CWD itself — matching the
`workspace_key` identity `hermes sessions list --workspace` already groups
on. It falls back to the unscoped global MRU when no session matches the
current workspace, preserving the old behaviour for fresh directories.

Adds `workspace_key` param to `SessionDB.search_sessions` and a
`_workspace_key_clause` SQL helper that mirrors `workspace_key()`: a row
matches when its `git_repo_root` equals the key, or (legacy rows without
git metadata) when its `cwd` is at or under it.

* feat(plugins): add public subagent lifecycle API

* fix subagent lifecycle ownership invariants

* fix(delegation): integrate lifecycle refactor with tool-history + daemon pool

Follow-ups on the salvaged NousResearch#63359:
- _finalize_child_results carries tool_call_history on subagent_stop
  (the NousResearch#62011/NousResearch#72403 field landed after the PR branched; the shared
  pipeline must emit it for both delegate_task and plugin-launched
  children). Lifecycle test updated for the new payload field.
- The lifecycle executor uses DaemonThreadPoolExecutor — a wedged or
  abandoned child must never block interpreter exit at atexit-join time
  (same rationale as _run_single_child's timeout executor and the
  async-delegation pool).
- delegate_task's batch path keeps live-transcript wiring while routing
  child construction through the shared
  _build_child_preserving_parent_tools helper.

* Revert the streaming-backfill gate — it broke a real E2E invariant

Deferring the FIRST_PAINT_BUDGET -> RENDER_BUDGET backfill while a thread
streams cut a 1374ms streaming-session switch to instant, but it also
means a streaming transcript stays clipped to 60 parts for the duration
of the run. `large-session-resume` asserts the resumed transcript shows
every seeded reply exactly once, and that count is short while the budget
is held down — a genuine behavior change, not a flaky test.

The switch cost is real and still worth fixing, but the fix has to keep
the full transcript mounted (raise the budget in idle callbacks, or
virtualize) rather than withhold it. Session-switch work is happening in
a parallel effort; leaving the invariant intact for them.

Everything else in this branch is untouched: the reflow-gated RO pins
(11.5 -> 59fps drag), the structural/weight signature split, the adaptive
stream flush, the tree-split preview, and the tool-row memo boundaries.

* fix(sessions): verify fully reconstructed recovery

* test(desktop): wait for committed compress directive

* test(desktop): assert compress argument stage

* test(desktop): isolate compression from slash completion

* fix(desktop): keep pinned sidebar rows in user order

flattenSessionsWithBranches always re-sorted roots by last_active, so a
turn finishing floated background tasks over the hand-picked Pinned list
even though $pinnedSessionIds already stored drag order. preserveOrder
skips that sort for pins (and other non-date-grouped manual lists); default
recents stay recency-sorted for truthful date buckets.

* refactor(fallback): single owner for backend identity and failure-scoped skips

Every fallback/dedup/skip decision asks one question — 'is this candidate
the same backend as the one that failed, along the axis that failure
invalidated?' — but it was re-implemented inline at six sites across four
subsystems, each comparing whatever string was locally convenient. Each
incident fixed one site while the others kept the bug: NousResearch#22548, NousResearch#70893,
NousResearch#59561, NousResearch#72468, NousResearch#62984/NousResearch#54250/NousResearch#57584.

agent/backend_identity.py now owns the concept: BackendIdentity (provider /
model / base_url axes), FailureScope (MODEL / CREDENTIAL / ENDPOINT — each
failure class invalidates a different axis), and should_skip_candidate().
Unknown axes never manufacture a skip (over-skipping strands failover; a
wrong try costs one RTT).

Migrated sites:
- chat_completion_helpers.try_activate_fallback: replaces the provider+model
  early-exit (the NousResearch#62984 bug: ignored base_url, stranding multi-endpoint
  pools) AND _fallback_entry_is_same_backend_by_base_url (deleted)
- auxiliary_client._try_configured_fallback_chain +
  _try_main_agent_model_fallback: replace label/model comparisons; auth and
  payment map to CREDENTIAL scope, keeping the NousResearch#59561 carve-out
- hermes_cli/fallback_cmd add: primary-match + duplicate checks now identity-
  aware (NousResearch#54250/NousResearch#57584): same provider+model on a different explicit
  base_url is a pool entry, not a duplicate

_mark_provider_unhealthy stays label-keyed deliberately: its only triggers
are confirmed 402s, which ARE credential-scoped.

Owner-level tests pin each incident's semantics by number; sabotage-verified
(removing the base_url axis fails the NousResearch#62984 test).

* test(desktop): wait for backfill before the duplicate-count baseline

The large-session-resume E2E captured initialMockReplyCount immediately
after openSeededSession, which returns once the NEWEST turn is in the
viewport. With FIRST_PAINT_BUDGET=20 (lowered from 60 in this branch),
only the newest ~10 turns mount at first paint; the older turns
backfill in a rAF. The baseline was reading 10 instead of 27, so once
the backfill mounted the full 28 (27 seeded + 1 new), the test saw
"28 ≠ 11" and reported duplicates that were never there.

Wait for the oldest seeded turn to mount before taking the baseline.
This makes the count reflect the fully-mounted transcript regardless
of FIRST_PAINT_BUDGET, so the perf win (smaller first paint) and the
no-duplicate invariant both hold.

Refs NousResearch#72504

* perf(desktop): keep thread message component types stable across a session switch

* perf(desktop): bail the transcript out of router-driven re-renders on session switch

* fix(tui): paint the OSC-10 default foreground on quantizing terminals

A skin that authors a background paints both terminal defaults: OSC-11
for the backdrop, OSC-10 to re-base every default-fg token (markdown
body, borders, anything rendered without an explicit color) onto the
theme's text tone.

The OSC-10 half never fired on a limited-palette terminal.
`normalizeThemeForAnsiLightTerminal` rewrites the foreground tones to
`ansi256(N)`, and `setTerminalForeground` only accepts `#rrggbb` — so
the argument failed the hex test and the write was silently skipped.
The background moved to the skin while default-fg text stayed on the
host profile's foreground.

That split is the reported symptom: prose renders in the terminal's own
near-black while every themed token beside it renders the skin's gray,
so the base text color appears to change between adjacent words. A
resize repaints the affected cells from the screen buffer, which is why
the text "goes black" on resize and why the mix looks scattered rather
than uniform.

Resolve the tone through a new `themeToneHex` before handing it to
OSC-10: `ansi256(N)` maps through the xterm grayscale ramp and 6x6x6
cube, an authored hex passes through, and anything with no paintable
color yields '' (which correctly clears back to the terminal default).

Verified on Terminal.app + the `brooklyn` skin: `theme.color.text` is
`ansi256(238)`, previously dropped, now emitted as
`ESC]10;#444444 BEL` alongside the existing `ESC]11;#f6f9fd BEL`.

* fmt(js): `npm run fix` on merge (NousResearch#72522)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fmt(js): `npm run fix` on merge (NousResearch#72532)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* ci: retrigger checks (GitHub Actions failed to resolve workflow file)

* chore: sync homelab branch with upstream main

---------

Co-authored-by: Brooklyn Nicholson <brooklyn.bb.nicholson@gmail.com>
Co-authored-by: Tony Simons <asimons81@gmail.com>
Co-authored-by: teknium1 <127238744+teknium1@users.noreply.github.com>
Co-authored-by: Gille <4317663+helix4u@users.noreply.github.com>
Co-authored-by: b <b@b>
Co-authored-by: hermes-seaeye[bot] <307254004+hermes-seaeye[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hermes Agent <hermes-agent@users.noreply.github.com>
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…ails on the same provider

Widen okalentiev's failed_model narrowing (NousResearch#59561) to
_try_main_agent_model_fallback. The safety-net layer still skipped on a
provider-label match alone, so single-provider users whose aux compression
model and main model share one custom endpoint had ZERO fallbacks: the aux
model timing out exhausted the chain in one hop and compression aborted.

Real incident (0.19.0 debug dump): aux zai-org/glm-5.2 hung 324s and timed
out while main mindai/macaron-v1-venti on the SAME endpoint was serving
448K-token turns — the label-only skip discarded the one viable summarizer,
the session wedged over threshold, and the anti-thrash breaker tripped.

Same convention as the chain fix: model-specific failures (timeout,
connection, rate limit) pass failed_model so only the exact failed model is
skipped; provider-wide failures (auth 401 / payment 402) pass None and keep
the whole-provider skip. Both sync and async call_llm sites pass it.

Sabotage-verified: the new regression test fails on the provider-only skip.
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…ped skips

Every fallback/dedup/skip decision asks one question — 'is this candidate
the same backend as the one that failed, along the axis that failure
invalidated?' — but it was re-implemented inline at six sites across four
subsystems, each comparing whatever string was locally convenient. Each
incident fixed one site while the others kept the bug: NousResearch#22548, NousResearch#70893,
NousResearch#59561, NousResearch#72468, NousResearch#62984/NousResearch#54250/NousResearch#57584.

agent/backend_identity.py now owns the concept: BackendIdentity (provider /
model / base_url axes), FailureScope (MODEL / CREDENTIAL / ENDPOINT — each
failure class invalidates a different axis), and should_skip_candidate().
Unknown axes never manufacture a skip (over-skipping strands failover; a
wrong try costs one RTT).

Migrated sites:
- chat_completion_helpers.try_activate_fallback: replaces the provider+model
  early-exit (the NousResearch#62984 bug: ignored base_url, stranding multi-endpoint
  pools) AND _fallback_entry_is_same_backend_by_base_url (deleted)
- auxiliary_client._try_configured_fallback_chain +
  _try_main_agent_model_fallback: replace label/model comparisons; auth and
  payment map to CREDENTIAL scope, keeping the NousResearch#59561 carve-out
- hermes_cli/fallback_cmd add: primary-match + duplicate checks now identity-
  aware (NousResearch#54250/NousResearch#57584): same provider+model on a different explicit
  base_url is a pool entry, not a duplicate

_mark_provider_unhealthy stays label-keyed deliberately: its only triggers
are confirmed 402s, which ARE credential-scoped.

Owner-level tests pin each incident's semantics by number; sabotage-verified
(removing the base_url axis fails the NousResearch#62984 test).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing Account usage, credit usage, billing (cross-cutting) area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants