Files
tutti/docs/architecture/agent-provider-cli-updates.md
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

141 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agent Provider CLI Updates
Status: current implemented architecture
## Purpose
Provider CLI update discovery and execution are daemon-owned product behavior.
They are intentionally separate from local provider readiness and from the
existing install workflow:
- readiness answers whether the current local CLI, adapter, and auth state can
launch;
- update discovery checks a trusted remote package source for a newer release;
- install supplies a missing runtime or repairs the minimum supported runtime;
- update is an explicit user action that moves an already installed,
source-owned runtime to a discovered newer version.
## Ownership
`packages/agent/daemon/providerregistry` owns the provider-neutral update
descriptor: capability, source, execution strategy, package, binary, optional
dependency policy, and stable unsupported reason. The registry validates that a
supported update uses the same managed npm package and binary as the provider's
installer. Shared logic never selects an update strategy by provider id.
`services/tuttid/service/agentstatus` owns local source recognition, cached npm
metadata discovery, version comparison, the explicit update action, and the
mandatory post-update probe. `services/tuttid/api` only projects those domain
results through the OpenAPI contract.
## Read And Refresh Contract
`GET /v1/agent-providers/status` remains local by default:
- no flag: local readiness only; update capability and current version are
projected without remote discovery;
- `refresh=true`: bypass only the local readiness cache;
- `includeUpdates=true`: opt into cached remote update discovery;
- `includeUpdates=true&refreshUpdates=true`: bypass only the update-metadata
cache;
- `refreshUpdates=true` without `includeUpdates=true`: no remote discovery.
`includeNetwork` remains an independent opt-in for network diagnostics. Neither
update flag enables it.
Update discovery uses a six-hour daemon cache, including failed outcomes. A
registry timeout, invalid response, or unavailable mirror sets a non-fatal
`reasonCode` on the provider's update status; it does not fail or replace local
readiness.
## Automatic Discovery Scheduler
The daemon owns a separate background scheduler for update discovery. It starts
only after the daemon has published its listener metadata and is ready for
clients. In production, the first check is delayed by 90 seconds (within the
60–120 second startup window), followed by a six-hour interval. These durations
are injectable in scheduler tests.
The device-global `agentCliUpdateCheckEnabled` desktop preference controls the
scheduler and defaults to `true`. A persisted `false` value starts the scheduler
without a timer or remote request. Preference changes cancel an active check or
reschedule the next check from the startup delay. Failed discovery is non-fatal
and retries with bounded exponential backoff beginning at five minutes and
capped at one hour; a successful check restores the six-hour interval. Daemon
shutdown cancels any in-flight discovery and waits for the scheduler to exit.
Scheduled work calls the dedicated managed-provider discovery path directly. It
does not call the ordinary provider readiness/status endpoint, set
`includeNetwork`, request `refresh=true` or `refreshUpdates=true`, run an update
action, or install a package. The same descriptor and local-source gates apply:
only an installed CLI proven to belong to a supported managed npm package may
reach a remote npm registry. Unsupported, missing, and unmanaged runtimes are
local-only decisions.
The update status exposes:
- `capability` and `unsupportedReason`;
- `source`;
- `currentVersion` and `latestVersion`;
- nullable `updateAvailable` (`null` means unchecked, failed, or not safely
comparable);
- `lastCheckedAt` and non-fatal `reasonCode`.
## Safe Source Gate
A provider descriptor declaring managed npm support is necessary but not
sufficient. For an installed CLI, tuttid must also prove that the resolved
launcher belongs to the descriptor's npm package by locating and validating its
package manifest and npm prefix. A standalone binary, package-manager install,
official-script install, or otherwise unknown origin is reported as
`unsupported` with `unmanaged_install_source`; tuttid does not install a second
copy and call it an update.
Current support matrix:
| Provider | Descriptor source | Runtime ownership requirement | Update capability |
| ------------------------------------- | ------------------------------------- | -------------------------------------------- | ----------------- |
| Codex | npm (`@openai/codex`) | resolved CLI must belong to that npm package | supported |
| Tutti Agent | managed npm (`@tutti-os/tutti-agent`) | resolved CLI must belong to that npm package | supported |
| Claude Code, Cursor, OpenCode, Hermes | official script | not safely attributable to managed npm | unsupported |
| OpenClaw | shell command / unknown source | not safely attributable to managed npm | unsupported |
| Nexight | provider unavailable | no supported update source | unsupported |
## Explicit Update Action
`POST /v1/agent-providers/{provider}/actions/update/run` is distinct from
`install`. The action:
1. verifies the descriptor capability and the installed runtime's managed npm
ownership;
2. refreshes update metadata and selects the exact discovered version;
3. runs the controlled managed npm executor against the owning prefix;
4. invalidates readiness and update caches;
5. performs a fresh provider probe before reporting completion.
An npm exit failure or failed post-update probe returns a failed action result.
It never reports success solely from the package manager exit code.
## Desktop Interaction And State Projection
The Agents settings table is a compact discovery surface. It may show the
current/latest version summary and open the provider's environment panel, but it
does not execute updates inline. The environment panel owns update discovery,
the explicit Update action, progress/log presentation, post-update detection,
and re-login alongside the other provider setup operations. Keeping the command
in that panel prevents table rows from changing height and gives all environment
remediation one interaction owner.
`IAgentProviderStatusService` is the renderer module seam for this workflow. It
owns request/action orchestration and exposes separate operation signals:
- `isLoading` describes ordinary provider-status query activity;
- `isCheckingUpdates()` describes the complete lifetime of update discovery;
- `isActionPending(provider, "update")` describes the complete update mutation,
including the refresh and post-action status projection.
UI must not infer update-operation state from `isLoading`: install/update status
polling legitimately toggles query loading between requests. Manual Check for
updates remains disabled while either update discovery or any update action is
pending, while unrelated environment detection does not lock that control.