Skip to content

feat(web): update providers on all connected machines (upstream) - #992

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-10-03-update-all-providers
Oct 3, 2026
Merged

rynfar merged 2 commits into
pylonfrom
upstream/2026-10-03-update-all-providers

Conversation

@rynfar

@rynfar rynfar commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Pylon could update providers one instance at a time in Settings, or one local environment at a time from the launch popover (Windows + WSL). There was no single action covering every connected machine, including SSH, relay and tunnel environments. Upstream #14678 added a compact global "Update all" button. The maintainer chose to extend Pylon's grouped UI instead (decision brief in #981).

Source

Upstream Title Outcome
0a04cc50def48121b9ece038c7df8b7fa789074b (#14678) feat(web): update providers on every machine with one click Adapted. Pylon's grouped interaction is used instead of upstream's header button and tooltip. Upstream's ProviderUpdateRun formatter is adopted and changed to report interruptions. Upstream's ProviderUpdatesAction.tsx is not ported; ProviderUpdateAllEnvironmentsAction replaces it.

What changed

  • Settings → Providers → Provider updates → "Update all connected environments" (web and desktop). This is a section at the top of the page, separate from the device tabs. It shows how many provider updates exist across how many connected environments and says that environments other than the selected one are included. It is hidden in scoped provider-setup links and when nothing can be updated.
  • Review before dispatch. A dialog lists:
    • Will update: each machine with its providers and target versions.
    • Needs a manual update: manual-only providers, drivers whose instances report different update commands, and Prime Agent.
    • Not included: environments that are not connected, are still loading provider status, are still checking permissions, or where this session is read-only.
  • Dispatch. Confirming sends one environment-addressed serverEnvironment.updateProvider per candidate instance. Sends run concurrently across environments; within an environment they go through the existing serial config lane. A synchronous ref guard stops a double click. The commands, scopes and server paths are the existing ones.
  • Outcomes. The dialog switches to per-environment rows that show status and offer Retry. They reuse EnvironmentUpdateRow and the logic extracted into useEnvironmentProviderUpdates, keeping its request-version fencing, 6-minute transport-hang expiry and terminal-only result persistence. One toast summarizes the run with a line per problem, labelled by machine and provider.
  • Refactor. ProviderUpdateEnvironmentRows now uses the extracted hook, so the launch popover behaves as before.
  • Docs. docs/user/updating.md has a new "Update providers" section.

Pylon adaptations vs upstream

  • Interrupted commands are reported. Upstream drops them, and drops the whole toast when every command was interrupted. Here an interrupted request gets its own warning line: "The request was interrupted. Check the provider's status or retry." A success whose snapshot is missing the targeted instance, or whose state is not terminal, is reported as unfinished rather than counted as a success. Upstream's "failed" wording is kept when every problem is a real failure (failed/unchanged). Mixed results read "did not finish".
  • Access restrictions. Operate access per environment is resolved exactly as the selected-environment panel resolves it. The desktop primary is granted. A browser primary uses its cookie session (primarySessionStateAtom, now exported). Other environments use the /api/auth/session scopes for their credential (providerOperateAccess.ts). Sessions are read only for connected environments that have outdated providers. Read-only and pending environments are never dispatched. The server's RpcAuthorization (orchestration:operate) remains authoritative.
  • Prime. Prime Agent is excluded from bulk dispatch even if a server reported it as updatable, and is listed as "use Prime maintenance". An unavailable Prime (enabled: false) is ignored. Managed maintenance commands are never sent.
  • Instance identity and installer ownership. Candidates come from the existing canOneClickUpdateProviderCandidate (one representative per driver; all instances must share one update command) using each environment's own instance IDs. Duplicate-target rejection and installer serialization stay with providerMaintenanceRunner and providerMaintenanceCommandCoordinator. There are no backend changes.
  • Scope labelling. Per-instance "Update now" and the launch popover's per-environment rows are unchanged. The new action is labelled "all connected environments" and sits outside the selected-device area.
  • Mobile is unchanged and still updates one environment at a time. This is recorded in the docs.

No contract, wire schema, migration, event or projection changes.

Verification

  • vp test run src/components/ProviderUpdateLaunchNotification.logic.test.ts src/components/ProviderUpdateEnvironmentRows.test.tsx src/components/settings/ProviderUpdateAllEnvironments.test.tsx src/components/settings/ProviderSettingsPanel.logic.test.ts: 4 files, 81 tests passed.
  • vp test run src/components/settings/ProviderSettingsPanel.environment.test.tsx: 20 passed.
  • vp run -F @t3tools/web typecheck: tsc --noEmit ran in apps/web, exit 0.
  • vp lint on the changed files: no new findings. Two existing warnings remain: a ref read during render in the rows component, and an effect setState in ProviderSettingsPanel.
  • vp fmt --check on the changed files: clean.
  • The server is untouched, so there was no server typecheck.

New coverage:

  • Formatter: partial failure; interruption; all-interrupted (warning, not null); missing or non-terminal snapshots; unchanged counted as failed; transport and disconnect errors; empty run.
  • Plan: multiple environments, each keeping its own instance; disconnected, reconnecting, loading, read-only and pending-access environments; no session read when there is nothing to update; manual-only providers; differing instance commands; Prime updatable vs unavailable; a queued update keeps its row.
  • Component: concurrent dispatch with the correct instance per environment; partial failure toast with machine labels; per-row status and a Retry that re-sends only the failed environment; duplicate clicks; interruption and disconnect reporting; no dispatch to read-only, offline or Prime targets.

Not verified

  • No UI run. Browser and computer use were not authorized for this task, so the dialog layout, copy, toast rendering and real multi-environment behavior (local + WSL + SSH/relay/tunnel) have not been seen in the running app. Before/after screenshots are still needed.
  • The new multi-environment session-access atom (providerOperateAccess.ts) has no direct unit test. Its resolution delegates to the existing tested resolvePrimaryOperateAccess / resolveRemoteOperateAccess.
  • If an environment disconnects in the middle of a run, its row leaves the dialog (it is no longer an operable group). Its outcome is still reported in the summary toast.

Review follow-ups (8d00a32b1c)

  • A hung request no longer wedges the bulk run. The per-environment hook resolves at its 6-minute expiry with timed-out runs, which are reported as "No response from the environment".
  • A server "already running" rejection is shown as in progress elsewhere: unfinished in the summary, never a failed row. The reason string is now a shared contract constant (SERVER_PROVIDER_UPDATE_ALREADY_RUNNING_REASON); the server literal is unchanged, so older servers still match.
  • A per-row retry closes the run's summary toast, so the toast never reports a failure that the retry may have fixed.
  • A run that finishes while the dialog is closed resets the dialog, so the next opening shows the review list and confirm button.
  • New hook-level tests cover request-version fencing, duplicate calls, timeout followed by a late result, and already-running handling. New component tests cover the timeout and already-running cases.
  • Verification:
    • Focused web suites: 5 files, 106 tests passed.
    • providerMaintenanceRunner.test.ts: 16 passed.
    • Typechecks for @t3tools/web, t3 and @t3tools/contracts all exit 0.
    • Scoped lint has no new findings; fmt is clean.

Part of upstream cycle #981.

🤖 Generated with Claude Code

Adapts upstream 0a04cc50de (#14678) to Pylon's grouped provider update UI.
Settings > Providers gains an "Update all connected environments" action that
shows the reviewed targets (machine and provider) before anything runs, then
sends environment-addressed serverEnvironment.updateProvider commands
concurrently through the shared per-environment update hook, so each
environment keeps its own outcome row and retry.

Adopts upstream's ProviderUpdateRun aggregate formatter, adapted so
interrupted requests and results without a terminal snapshot are reported
instead of dropped. Read-only, still-checking, loading and disconnected
environments are listed as not included; manual-only providers, differing
instance update commands, and Prime Agent (owned by Prime maintenance) are
listed for manual follow-up. Per-environment launch popover and individual
instance updates are unchanged. Mobile is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.1 KiB 1.1 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.4 KiB 20.4 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 4.9 KiB 4.9 KiB +41 B (+0.8%) 6.8 KiB ✅
Claude Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB +41 B (+3.5%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 20.7 KiB 20.8 KiB +41 B (+0.2%) 29.3 KiB ✅
Claude Live turn messages 1 2 +1 (+100.0%) 8 ✅

Baseline: b4c210e · PR result: 8d00a32 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Review follow-ups for the all-environments provider update action:

- The per-environment update hook now resolves at its 6-minute expiry with
  timed-out runs, so a hung request no longer wedges the bulk run (summary
  toast, running state, and reopen behavior).
- A server "already running" rejection (shared contract reason) is treated
  as in progress elsewhere: unfinished in the summary, not a failed row.
- A per-row retry closes the run's summary toast so it never reports a
  failure the retry fixed.
- A run that finishes while the dialog is closed returns the next opening to
  review instead of a stale progress view.
- Hook-level regression tests for request-version fencing, duplicate calls,
  timeout-then-late-result, and already-running handling.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rynfar
rynfar merged commit 1a69319 into pylon Oct 3, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant