Commit Graph

46210 Commits

Author SHA1 Message Date
ethernet
65cfee332a fix(tui): follow a chat into the worktree its agent settled in
An agent told to make a worktree and work in it left the chat on the checkout it
started in — the sidebar kept the chat in the primary branch lane while every
later command ran in the worktree.

`_reconcile_session_cwd_from_terminal` refused whenever `explicit_cwd` was set,
but `session.create` sets that for ANY session whose cwd exists on disk, and the
desktop always sends a workspace. The guard that was meant to protect a
deliberately chosen workspace (#72776) therefore disabled the follow for the
whole desktop surface.

Key the pin on `cwd_pinned`, set only by the two moves the user drives:
`session.cwd.set` (the composer's folder picker) and `session.workspace.move`
(move-to-project). A cwd a chat merely STARTED in is not a pin, so the agent's
own worktree settle re-anchors the chat and the desktop moves it to that lane.
2026-09-29 16:29:04 -04:00
fangliquanflq
ff3d829ad7 fix(tui_gateway): enrich persisted session git metadata 2026-09-29 16:29:04 -04:00
Austin Pickett
e1d7beb2af test(desktop): drag-to-new-session on a main lane switches only to a branch git lists 2026-09-29 16:29:04 -04:00
Austin Pickett
3da330fe23 fix(desktop): git-enrich lazily created session rows; never switch to a fallback lane label
Desktop session rows are created on the first submit (_ensure_session_db_row),
after _hydrate_session_cwd has already run against a missing row, so no git
probe was ever claimed and git_branch/git_repo_root stayed NULL. The sidebar
then labelled the lane with the DEFAULT_BRANCH_LABEL "main" fallback, and "+"
ran `git switch main`, which fails on a master-trunk repo.

- _ensure_session_db_row schedules the generation-scoped git probe once per
  live session when the row has a cwd but lacks git metadata.
- "+" on a main-checkout lane switches only when git lists the label as a
  branch (laneSwitchTarget); otherwise the session opens on the current checkout.

Fixes #108694
Fixes #108784
2026-09-29 16:29:04 -04:00
kshitijk4poor
fddab1ae8a fix(desktop): reap timed git trees on in-app relaunch too
app.exit() does not fire will-quit, and every in-app relaunch (About's
Restart, the bundle-swap relaunch, the GPU/no-sandbox relaunches) exits
through exitAfterBackendShutdown. Kill the timed git trees there as well,
or a probe in flight at relaunch still ends up under PID 1.
2026-09-30 01:56:00 +05:30
kshitijk4poor
a691b964c9 fix(desktop): keep the bundle-skew warning working on treeless checkouts
With lazy fetch off, the path-limited rev-list walk fails on a tree:0
checkout as soon as an update moves more than one commit: it needs the
tree of every intermediate commit, and only the checked-out endpoints are
local. The probe then reported "not stale" exactly when the renderer is
most likely behind, on the install shape `hermes update` produces.

When the walk cannot run, compare the stamp and HEAD endpoints over the
runtime paths. Ancestry is already proven, so a differing diff means the
renderer predates runtime changes. The diff reads only the two endpoint
trees, offline. Measured on a real tree:0 clone of this repo: 45 ms, no
new packs. If the stamp's tree is missing too, git exits 128 and the probe
stays quiet as before.

Proposed by @Froraut on #123039, with field data.

Co-authored-by: Froraut <79215537+Froraut@users.noreply.github.com>
2026-09-30 01:56:00 +05:30
kshitijk4poor
4daeec7f2c fix(desktop): kill timed git commands at app quit, and skip taskkill on an exited root
Timed execGit commands lead their own POSIX process group, so nothing
reached a probe still running when the app quit: the 5 s timer died with
the process and the group was left orphaned under PID 1 (#125243's
"survives restart"). execGit now tracks timed children, and will-quit
kills each tree (group SIGKILL on POSIX, taskkill /T /F on Windows).

On Windows a root that already exited has no tree left for taskkill /T to
walk and its pid may be reused, so the timeout path skips taskkill there.
The error/close handlers no longer repeat finish()'s clearTimeout.

Quit-time cleanup was first proposed in #125861.

Co-authored-by: chelsealong <chelsealong@126.com>
2026-09-30 01:56:00 +05:30
kshitijk4poor
3a21c2a75a refactor(desktop): delete main.ts runGit now that the skew probe uses execGit
The bundle-skew probe was runGit's only caller. With the probe on execGit
(timeout, process-tree reap, GIT_NO_LAZY_FETCH), runGit is dead: an untimed,
untracked spawn nothing should reach for again.

Its spawn-failure path goes with it. describeGitSpawnFailure and the
GIT_UNUSABLE marker had exactly one producer, runGit, and the only runGit
caller swallowed every error, so the hermes:updates:check handler's
git-unusable branch could not fire; nothing in the renderer reads it.
2026-09-30 01:56:00 +05:30
Matt Healey
2d71786e8c test(desktop): pin that the bundle-skew probe never lazy-fetches on a treeless clone
A real `--filter=tree:0` clone over file:// runs the probe and asserts the
pack directory is unchanged. Without GIT_NO_LAZY_FETCH the same probe writes a
new promisor pack (4 more files under objects/pack).

Cherry-picked from the test half of #123039 (fc5ea944bd); the env change it
carried is already in the previous commit.
2026-09-30 01:56:00 +05:30
择梦舟
c42db5415f fix(desktop): bound bundle skew checks and reap timed-out git trees
Coalesce concurrent version polls, cache results briefly, and skip checks
while an updater owns the local runtime. Use the existing execGit runner
with a 5-second timeout and no lazy fetch; reap its process group or Windows
process tree so Python-hosted git and promisor children cannot accumulate.

Add concurrency/backoff coverage and a live descendant-process regression.
Related to NousResearch/hermes-agent#125932.

(cherry picked from commit 633d7de6cd68164d2293c47f8e37170debabeaed)
2026-09-30 01:56:00 +05:30
kshitijk4poor
a66f681696 chore: map dreamfarer-space and mheals for the bundle-skew salvage 2026-09-30 01:56:00 +05:30
Brooklyn Nicholson
12c3d5c968 fix(tui-gateway): keep replay seq monotonic across ring eviction
FIFO session eviction in tui_gateway/event_replay.py deleted the session's
_replay_next_seq, so a session revisited after eviction restarted at seq 1,
under every client watermark, and session.events.since returned nothing new.
Keep the seq counter for the process epoch and raise _replay_evicted_through
to the last stamped seq, so an old watermark gets truncated: true instead of
an empty, complete-looking reply.

The client half (acting on truncated: true) is
https://github.com/NousResearch/hermes-agent/pull/126988.
2026-09-29 15:22:03 -05:00
Cestercian
2ecc90df3a fix(desktop): declare lucide-react dependency for onboarding setup card
Onboarding setup.tsx imports Puzzle from lucide-react; the package was
missing from apps/desktop/package.json, breaking from-source desktop builds.
2026-09-29 15:13:58 -05:00
ethernet
ec5f44138a Merge pull request #128348 from NousResearch/fix/release-claim-copy
Release cut output shows its CI run link and leads with the next action
2026-09-29 16:06:18 -04:00
teknium1
7968c72a3c chore: map andreausderhood contributor email 2026-09-29 12:55:46 -07:00
teknium1
2995676293 fix(model-picker): stop the 50-model cap cutting the Nous and OpenRouter free tier
Both rows are already curated lists (Nous = curated manifest + the Portal's
recommendations, OpenRouter = curated ∩ live ∩ tools), and the free tier
sits last by design. The gateway /model picker and the TUI/Desktop payload
ask for max_models=50, so the tail was sliced off: on main the Nous row had
58 entries (8 Portal-recommended free models hidden, space-bunny-alpha
among them) and OpenRouter had 54-55 (the whole free block hidden). Adding a
catalog entry alone only swapped which free model fell off the end.

- nous and openrouter join _UNCAPPED_PICKER_PROVIDERS; list_picker_providers
  caps its OpenRouter override through the same _cap_models.
- _cap_models honours max_models=0 for uncapped rows too (slug-only
  callers asked for no models and got a full uncapped catalog).
- The platform text fallback slices its own 5-model preview instead of
  relying on the listing cap, so uncapped rows do not dump into chat.
2026-09-29 12:55:46 -07:00
andreausderhood
652ce40e5b feat(models): add stealth/space-bunny-alpha to the OpenRouter curated list
Space Bunny Alpha is a live $0 stealth SKU on OpenRouter (tool support, 1M
context, image/video input) that the picker never offered: the OpenRouter row
is the curated manifest intersected with the live catalog, and the id was not
in the curated list, so the live entry was filtered out.

- models_catalog_static.py: id + "free, stealth model" description, and
  membership in _OPENROUTER_ONLY (stealth SKU without the :free suffix, not
  carried by Nous Portal)
- website/static/api/model-catalog.json: regenerated
  (scripts/build_model_catalog.py, 63 -> 64 OpenRouter entries)

Fixes #122075
2026-09-29 12:55:46 -07:00
Brooklyn Nicholson
018d982bd9 fix(agent): a home working dir is a fallback, not a project
The packaged Desktop with no default project dir resolves its spawn cwd (and
TERMINAL_CWD) to $HOME, and SubdirectoryHintTracker's containment check is
then vacuously true for the whole home subtree: any AGENTS.md, CLAUDE.md or
.cursorrules under ~ is injected into tool results on first touch. The
tracker now treats a home (or container-home) working dir as a fallback, not
a project — hint discovery stays off until the session adopts a real
workspace, and _register_session_cwd re-anchors it there (same hook that
already updates agent.session_cwd). AIAgent init also prefers the session's
own cwd over the launch TERMINAL_CWD, so an agent built for a workspace
session scopes hints to it from the start. .archive joins the excluded dir
names (retired skills trees hold stale AGENTS.md copies).

Rebases the home guard from #77145 (idea + guard direction) onto the current
class shape; covers the install-tree shape #75922 targeted via the shared
home guard.

Fixes #76902
Ref: https://github.com/NousResearch/hermes-agent/issues/75839

Co-authored-by: Sahil-SS9 <218421507+Sahil-SS9@users.noreply.github.com>
2026-09-29 14:53:00 -05:00
Brooklyn Nicholson
d9a97ae517 test(tui_gateway): assert the raw row sequence, not just the count, after the restart retire 2026-09-29 14:47:27 -05:00
Yuan Li
878347b84f test(tui_gateway): restart between two queued drains retires only the never-run prompt (#125577)
Two prompts accepted busy, the first drains, then the backend dies before
the second drains: the reopen retires the second's still-marked row while
the drained turn's healed row stays active. The never-run prompt's copies
survive inactive (durable history is never deleted).
2026-09-29 14:47:27 -05:00
Yuan Li
ead1a7dc78 fix(tui_gateway): retire a never-drained busy-queue accept row on cold reopen (#125577)
A prompt accepted while the session's agent is busy writes its user row at
accept time; only the in-memory queue drain ever retires that row. A backend
restart discards the queue with nothing left to run, so the row stayed active
and the next resume's alternation repair glued the never-run prompt into the
previous turn's user message.

Mark the accept-time row (display_metadata._queued_prompt) and deactivate
still-marked rows in reopen_session — the drain's replacement row is
unmarked, so still-marked after a restart is exactly never-drained. A
dispatched-then-interrupted turn's row is never marked (its in-process
discard is #123532's contract). Rows are deactivated, never deleted.
2026-09-29 14:47:27 -05:00
ethernet
1927d39446 Merge pull request #128307 from kshitijk4poor/feat/openai-ultrafast
feat(fast): /fast ultrafast for GPT-6 Astra, priced at the served tier (6x)
2026-09-29 15:45:46 -04:00
ethernet
8ad4dc8d67 Merge pull request #128248 from kshitijk4poor/feat/gpt-6-1-sol
feat(models): add gpt-6.1-sol; reasoning-off omits 'none', which 6.1 Sol 400s on
2026-09-29 15:43:44 -04:00
Brooklyn Nicholson
cf9dbe5952 fix(cli): degrade gracefully when prompt_toolkit.patch_stdout is missing
The top-level import was unguarded (its neighbours already had try/except
patterns), so a partial prompt_toolkit install — e.g. a stale venv with the
package present but a submodule broken — crashed every import of cli,
including tui_gateway.slash_worker, which every gateway session spawns.
The only use site is a 'with patch_stdout():' block, so fall back to
contextlib.nullcontext, mirroring agent/display.py's guarded
patch_stdout StdoutProxy import.

Fixes #96075
2026-09-29 14:40:47 -05:00
ethernet
e336fbcf79 fix: release cut output waits for its CI run and leads with the next action
The cut printed before GitHub listed the dispatched run, so it almost always
said "the run is not listed yet". It now polls up to 30s for the run, and when
none lists it links the stable-release workflow page. The copy is shorter:
Release CI, the skipped-tests warning (bold on a tty), the draft link, and the
publish command on its own line.
2026-09-29 15:12:04 -04:00
Jeffrey Quesnelle
dccb84b924 Merge pull request #115343 from marcusds/chore/relay-0.9
chore(relay): upgrade to 0.9.3
2026-09-29 15:05:57 -04:00
ethernet
6a8ef0c061 Merge pull request #128334 from NousResearch/fix/release-tag-record-signature
A signed release tag no longer fails stable admission and reconciliation
2026-09-29 15:00:57 -04:00
Jeffrey Quesnelle
02c389b364 Merge pull request #128244 from NousResearch/sid/clarify-hydration-tests-questions-shape
test(desktop): clarify hydration tests send the questions shape
2026-09-29 14:57:26 -04:00
ethernet8023
792ba0a264 fix(release): read a tag's record, not its signature
git keeps an annotated tag's signature inside the message body, so
`git tag -l --format=%(contents)` returns the JSON record followed by an
armored block, and `json.loads` of the whole message raises "Extra data: line 2
column 1" at the armor's first byte. Claim tags, final receipts and build
receipts are created on a host whose git signs tags, so stable admission
(`python -m scripts.releases.stable admit`), ordered reconciliation
(`python -m scripts.releases.sequencer`) and tagless build receipts each
refused to read their own tag.

Add `versioning.tag_record()` as the one reader of a tag's record — the text
before the armor, unchanged for an unsigned tag or a detached signature — and
route every `%(contents)` read through it in stable.py, sequencer.py and
commit_build.py. commit_build imports it inside the function so its module
surface stays stdlib-only for the isolated checkout-admission step.

The reads inside the release tests use the same reader, and the one fixture
that creates a plain final tag says so explicitly, so the release suite passes
on a host whose git signs tags by default.
2026-09-29 14:55:15 -04:00
alt-glitch
3b9c31c685 test(desktop): clarify hydration tests send the questions shape
Four tests added after the clarify contract change still sent a top-level
choices/question request. The clarify handler reads only questions, so it
stored no card and the tests failed on main.
2026-09-30 00:01:41 +05:30
kshitijk4poor
ab66fb8996 feat(models): list gpt-6.1-sol on Nous Portal (now served by /v1/models) 2026-09-29 23:55:18 +05:30
kshitijk4poor
bdde674296 feat(fast): /fast ultrafast for GPT-6 Astra, priced at the served tier
OpenAI's Ultrafast service tier (service_tier="ultrafast") is broadly
available for GPT-6 Astra in the API and Codex (Pro 500 / Enterprise),
billed at 6x Standard. GPT-6.1 Sol Ultrafast is announced as coming soon.

- One tier table: agent.fast_mode.parse_service_tier / STATIC_TIERS now
  back the CLI, gateway and TUI config loaders (three hand-copied parsers).
- resolve_fast_mode_overrides(tier="ultrafast") sends the tier only for
  Ultrafast models on api.openai.com / chatgpt.com; anything else gets
  nothing rather than a silent swap to another paid tier.
- /fast ultrafast on CLI, gateway (typed + picker when supported) and TUI;
  static-tier attach sites pass the tier through.
- Pricing: the response's SERVED service_tier is folded into usage (Codex
  stream assembler keeps it); served ultrafast prices from a published
  6x row (272K whole-request tier included). A request asking for
  Ultrafast but served at default bills at Standard.
- i18n: 4 new keys in all 17 locales; option lists mention ultrafast.
2026-09-29 23:54:34 +05:30
unsupportedpastels
99721dca80 fix(checkpoints): refuse an empty restore selection and delete read-only test repos
- A selection that resolves to no entries (e.g. ":(exclude)*") is refused
  before the pre-rollback snapshot. Checkout with an empty pathspec file
  switches the store's HEAD instead of restoring nothing.
- Remove the nested repository with utils.rmtree_readonly so the
  deleted-repo test runs on Git for Windows (read-only loose objects).
2026-09-29 14:12:41 -04:00
unsupportedpastels
01d5909fbc fix(checkpoints): restore exactly the inspected selection and keep nested-repo labels in listings
- Check out the entries resolved during inspection as literal paths,
  instead of re-evaluating the pathspec after the pre-rollback snapshot
  restages the index (attribute pathspecs could select an uncaptured
  gitlink the inspection never saw).
- Put a multiline reason on one line before appending the nested-repo
  note; listings read %s, which stops at the first blank line.
- Gate host-specific test rows with platforms() and decode raw-byte
  filenames inside the test, so the file collects on Windows, passes on
  macOS and is selected by the OS lanes.
2026-09-29 14:12:41 -04:00
unsupportedpastels
9ec9028e50 fix(checkpoints): label checkpoints that did not capture a nested repo
A nested repository is stored as a gitlink, so its files are not in the
checkpoint. Say so when the checkpoint is taken: its message gains
"[nested git repos not captured: <paths>]", which every /rollback listing
(CLI, gateway, TUI, Desktop) already shows. The gitlink parse is shared
with the rollback guard.

rollback.list sent the TUI an always-empty message (it read a "message"
key the manager calls "reason"), so TUI and Desktop listings never showed
what a checkpoint was; map it from reason.

Co-authored-by: FroRaut <79215537+Froraut@users.noreply.github.com>
2026-09-29 14:12:41 -04:00
unsupportedpastels
b846c17fe0 test(checkpoints): cover a gitlink below an ordinary directory
A one-component gitlink cannot catch separator or component-splitting
mistakes in the scoped restore guard. Pin refusal for the exact gitlink,
its ancestors and descendants in every spelling (including Windows
separators on Windows), and unrelated recovery beside it.

Co-authored-by: FroRaut <79215537+Froraut@users.noreply.github.com>
2026-09-29 14:12:41 -04:00
unsupportedpastels
713d09970f fix(checkpoints): select nested repo guard scope by recorded path, not symlink target
The scoped restore guard resolved the requested path through the live
filesystem, so a captured file later replaced by a symlink into a nested
repository was refused even though the checkpoint holds its bytes.
Normalize the selection lexically; resolved-path confinement stays in
_validate_file_path. A recorded gitlink replaced by an unrelated symlink
is still refused.
2026-09-29 14:12:41 -04:00
unsupportedpastels
e700e5ffdb fix(checkpoints): honor Git pathspecs in nested repository guard
Resolve selective restores against a disposable index before any checkpoint mutation, preserving unrelated-file recovery and refusing uncaptured gitlinks. Keep NUL-delimited filenames lossless, including surrogateescaped POSIX bytes. Add real-Git regression coverage and document the capture limitation.

Fixes #127073
Salvages #127077

Co-authored-by: Yuan Li <dskwelmcy@163.com>
2026-09-29 14:12:41 -04:00
Yuan Li
19714b1d93 fix(checkpoints): scope nested repo restore refusal
(cherry picked from commit e590192111781391ab3dc2255222aea6627992aa)
2026-09-29 14:12:41 -04:00
Yuan Li
45daba473f test(checkpoints): cover nested repository rollback refusal
(cherry picked from commit a28a71652eb6736b7402dbb5f6e288da4b10772d)
2026-09-29 14:12:41 -04:00
Yuan Li
be6c55685b fix(checkpoints): refuse rollback of uncaptured nested repos
(cherry picked from commit 574816570f0c72fef12b836ea09e5c8233049ca6)
2026-09-29 14:12:41 -04:00
kshitijk4poor
bf87ae620e feat(models): add gpt-6.1-sol (OpenRouter + direct OpenAI API)
OpenAI released GPT-6.1 Sol on 2026-09-29. It is live on OpenRouter
(openai/gpt-6.1-sol, -pro) and the direct API; not yet on Nous Portal
or on Codex OAuth for our test account.

- Catalog: OPENROUTER_MODELS + openai-api picker; kept off the nous
  list via _OPENROUTER_ONLY until the Portal serves it. Manifest regenerated.
- Context: 1.05M direct API, 272K Codex fallback; 272K compaction
  auto-raise on the Codex route.
- Pricing: $2/$10, cached input $0.10 (5%, not 6 Sol's 10%), cache write
  $2.50, 2x/1.5x above 272K; -pro aliased to the base row.
- Reasoning: none/minimal return 400 on 6.1 Sol (unlike 6 Sol), so it uses
  Astra's low..max ladder without Astra's account gating. OpenRouter's
  catalog wrongly lists 'none' for it, so the OpenRouter profile omits a
  disable when the OpenAI ladder has no 'none'.
2026-09-29 23:25:26 +05:30
finn763
ebf1be6527 fix(desktop): keep a settled unpersisted live-tail reply across a stale refresh graft
Post-turn rehydrates can race the gateway commit: the refreshed page shares the anchor but ends before the just-settled reply. preserveLocalPendingTurnMessages only protected stream-id rows, so a reply that settled onto a non-stream id (interim id, appended assistant-<ts> bubble) was dropped after it already painted. Extend the #70209 only-copy rule to the single newest settled, non-interim, unpersisted assistant row when the refreshed page carries no identical text.

That row is skipped when the refreshed page brings its own assistant row for the same reply ordinal: a rotated or compacted page supersedes it, so keeping the cached copy would render the pre-compression answer next to its replacement.

Closes #121613
2026-09-29 12:32:11 -05:00
Brooklyn Nicholson
4bc847741d fix(desktop): keep a pending streamed reply over a divergent same-turn store partial
Fixes #80151
2026-09-29 12:30:35 -05:00
Siddharth Balyan
45079e6330 fix(security): the first tirith scan no longer waits on its download (#128150)
* fix(security): the first tirith scan no longer waits on its download

A process that never ran the CLI startup install (desktop serve, the
gateway, a newly routed profile) claimed the install on its first scan and
ran pm.ensure("tirith") inline. The first terminal call then waited on the
PM worker, the runtime toolchain and the tirith download before it ran.

The cold scan now starts the same background install as startup and scans
with the default path, so the call fails open at once like any scan during
a startup download.

* fix(security): a scan during the tirith download never trips the breaker

The previous commit let a cold scan run while the background install was
still downloading. That scan spawned the bare default "tirith", got
FileNotFoundError and counted it as a crash. Three terminal calls during
the download opened the circuit breaker, and every scan then returned
allow unscanned for 300 s, even after the download finished. With
tirith_fail_open: false the first three commands were blocked and the
breaker then let commands run unscanned.

A scan that finds the default binary missing while this home's install
thread is alive no longer spawns or counts a crash. Fail-open allows the
command at once ("tirith installing"). Fail-closed waits for the install,
as the inline install did before, and then scans with the real binary.
So only the fail-open case skips the scan during a download; the earlier
commit's "fails open at once" holds only for fail_open.

The PM consumer test now joins the background install before it reads
the recorded download requests.
2026-09-29 17:29:05 +00:00
David Metcalfe
d939624916 fix(desktop): remove 9px override from pane tab label, inherit parent size
The layout-tree renderer (63a9bde77) introduced PaneTabLabel with a
text-[9px] override that contradicts the parent PaneTab's baseline of
text-[0.6875rem] (11px). The old ChatHeader/TitleMenuTrigger used 0.75rem
(12px), making 9px a clear regression.

Drop the explicit size class from the label span so it inherits 0.6875rem
from the parent — consistent typographic hierarchy, still a meaningful
improvement over 9px.
2026-09-29 12:27:20 -05:00
Brooklyn Nicholson
6ae7b79b51 fix(tools): word the read_preview hint so the Windows footgun lint doesn't read it as open() 2026-09-29 12:25:29 -05:00
Brooklyn Nicholson
0242946697 fix(tools): split the merged preview/terminal bridge timeout errors into the two cases they conflate
An empty bridge answer produced one string that blamed a closed tab
('The action timed out, or no GUI window answered. Open a page with
open_preview first.') even when the pane was open on an app older than
this backend — two cases with different remedies. drive_preview /
annotate_preview now lead with 'no preview tab is open' and name the
older-app possibility; read_preview / read_terminal name both the
nothing-open and bridge-timeout cases and the update-the-app remedy.

Refs #94272
Refs #95104
Refs #119333

Co-authored-by: lesseradmin <veeman961@gmail.com>
2026-09-29 12:25:29 -05:00
Brooklyn Nicholson
d3d47ce98a fix(tui-gateway): probe the preview.act bridge so an absent renderer fails fast
drive_preview / annotate_preview blocked the full 45s deadline on every
call when nothing could answer preview.act — an app build older than the
tools (the renderer ships in the desktop bundle, the backend offers the
tool), or a session no attached window hosts — and the tool then blamed a
closed tab. Port PR 94300's fail-fast ladder onto the JSON-RPC
server-requests path, mirroring _tour_request: first action per session
gets a 10s probe deadline; unanswered → bridge marked unavailable for
that session with an actionable update-the-app error, and later actions
short-circuit instead of stacking waits. Unlike tour support, a preview
pane can open later in the session, so an unanswered probe only condemns
the bridge for a cooldown window, with a single in-flight reprobe per
session; concurrent callers fail fast. Once answered, the full deadline
is back and a transient miss never disables the bridge. A window-owned
request that every window declines settles as a non-empty answer
(main e33f1a0faf): the refusal passes through unchanged.

Fixes #94272

Co-authored-by: lesseradmin <veeman961@gmail.com>
2026-09-29 12:25:29 -05:00
ethernet
36699ac97a Merge pull request #128156 from NousResearch/fix/desktop-flavored-icons-clean-checkout
Desktop release builds stop leaving their flavored icon render in the checkout
2026-09-29 13:08:09 -04:00