Skip to content

feat(ai): refresh provider model catalogs on demand - #938

Open
dviejokfs wants to merge 1 commit into
mainfrom
fix/refresh-workspace-provider-models
Open

feat(ai): refresh provider model catalogs on demand#938
dviejokfs wants to merge 1 commit into
mainfrom
fix/refresh-workspace-provider-models

Conversation

@dviejokfs

@dviejokfs dviejokfs commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an explicit, permission-checked provider model refresh endpoint instead of launching provider CLIs during catalog reads
  • resolve Claude's account-aware catalog from Claude Code's native initialize response inside the authenticated user's persistent workspace
  • automatically create or wake the global user workspace when model discovery needs compute; a user-owned workspace without recoverable compute is now surfaced as an error
  • remove fabricated Claude model identifiers and share the same parsing rules used by temps-agent-runtime
  • cache authoritative catalogs with TTL, cooldown, per-principal single-flight refreshes, cancellation-safe cleanup, and credential-change invalidation
  • safely fence stale provider process trees before reusing a recovered workspace, while preserving its persistent files
  • discover and import an authenticated local Claude credential with one click for easier onboarding
  • expose provider-specific refresh progress and persistent actionable failures in the UI

Why

Provider model lists are account-aware and can change independently of Temps. Claude Code exposes the usable catalog only after its authenticated CLI initializes, so a static host-side list cannot be authoritative. Previously, Temps advertised invented identifiers such as claude-sonnet-5; those values could be rejected by the installed harness.

The refresh flow now asks the real CLI in the user's workspace. For a global user-owned chat, Temps creates or wakes that user's persistent workspace automatically. It does not require the user to manually start a sandbox, and it does not treat an unavailable sandbox as a successful empty workspace.

Behavior

  • cached catalog reads remain side-effect free
  • an explicit or first-use refresh creates/wakes global-user-{principal} through the normal workspace and sandbox services
  • successful discovery leaves the persistent workspace available for the following chat turn
  • timeout/cancellation pauses a newly started workspace through SandboxService, preserving its volume and synchronizing registry/database state
  • recovered workspaces are reused only after a fail-closed process-tree fence confirms stale Claude/Codex/OpenCode processes are gone
  • unavailable compute returns sanitized RFC 7807 guidance; raw provider, credential, and Docker errors are not exposed

Evidence

Backend

cargo test --lib -p temps-sandbox -p temps-ai-agent-cli -p temps-ai-chat -p temps-agents
cargo test --lib -p temps-ai-gateway
cargo check --lib -p temps-sandbox -p temps-ai-agent-cli -p temps-ai-chat -p temps-ai-gateway -p temps-agents
cargo clippy --lib -p temps-sandbox -p temps-ai-agent-cli -p temps-ai-chat -p temps-ai-gateway -p temps-agents -- -D warnings
combined targeted suites: 1030 passed, 1 ignored, 0 failed
temps-ai-gateway: 225 passed, 0 failed
cargo check: passed
clippy: 0 errors

The real process regression also verified that a TERM-resistant parent and child are escalated and removed:

cargo test --lib -p temps-agents strict_fence_kills -- --nocapture
1 passed, 0 failed

Frontend

bun test src/components/ai/DebugChatPanel.test.ts src/components/ai/chat-runtime-options.test.ts
bunx tsc --noEmit
58 passed, 0 failed
typecheck passed

Browser

agent-browser exercised the generated client against the exact branch server in isolated dev slot 33:

  • selecting the global user workspace immediately changed its status to Sandbox starting / recovering
  • the UI automatically issued the provider model refresh request
  • the local Docker daemon could not allocate another isolated network because its predefined address pools are exhausted, so the UI rendered the sanitized persistent-workspace error and did not display fabricated models
  • no shared Docker network was deleted or modified to manufacture a happy-path result

Repository gates

git diff --check
python3 scripts/source_attribution.py check
clean
Attribution check passed for 3764 source files.

Security

  • refresh requires the provider's runtime permission; workspace-backed discovery additionally requires SandboxesWrite and SandboxesExec
  • host credential discovery/import remains restricted to administrators/settings mutation permissions
  • reusable credentials remain encrypted and reach the provider only through the existing short-lived relay
  • credential files are opened without following symlinks, validated from the opened handle, and size-bounded before parsing
  • model caches and single-flight locks are principal-scoped; credential invalidation waits for in-flight discovery
  • the recovered-workspace fence freezes roots and descendants, terminates them, escalates survivors, and verifies absence before clearing the recovery marker
  • cancellation or any provider error leaves the recovery marker set, so an unfenced workspace cannot be reused
  • backend errors and logs expose classifications only, not raw provider output, tokens, or infrastructure details

Review

  • backend/security lifecycle review: approved, no remaining findings
  • frontend state/accessibility review: approved, no remaining findings
  • dedicated security review: approved, no remaining findings

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

📓 Changelog preview

This is what your commits will add to the generated CHANGELOG.md at release time (via git-cliff). Do not edit CHANGELOG.md by hand — it is generated from your Conventional Commit messages.

## [Unreleased]

### Added

- **ai:** Refresh provider model catalogs on demand

@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds permission-checked, principal-aware provider-model refreshes backed by persistent user workspaces, with cache invalidation, lifecycle fencing, local credential import, and frontend progress/error handling. The current-head target-specific import guard aligns the macOS-only import with all of its uses.

  • Replaces fabricated Claude identifiers with account-aware catalogs parsed from Claude Code initialization.
  • Adds principal-scoped model caching, cooldown, and single-flight refresh coordination.
  • Adds explicit refresh and local-credential import APIs with generated frontend bindings.
  • Updates model selectors and provider settings UI to surface refresh progress and actionable failures.
  • Guards the macOS-only Duration import to keep Linux all-features Clippy clean.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
crates/temps-ai-agent-cli/src/service.rs Principal-scoped workspace model snapshots, cooldown state, and single-flight locks resolve the previously reported cross-user cache reuse.
web/src/pages/agent-sandbox/AgentSandboxProviderDetail.tsx Provider refresh now uses the generated React Query mutation and derives button loading state from isPending.
crates/temps-agents/src/services/provider_credential_service.rs Local credential discovery is bounded and platform-aware; the current-head macOS cfg consistently guards the Duration import and all uses.
crates/temps-agents/src/handlers/ai_providers.rs Adds typed, permission-checked refresh and credential-import endpoints with audit logging and sanitized refresh failures.
crates/temps-ai/src/service.rs Adds provider capability snapshots, refresh policies, caching, invalidation, and refresh coordination used by host and workspace discovery.
web/src/lib/ai-provider-catalog-query.ts Centralizes the generated provider-catalog query options and shared cache identity used across refreshed model consumers.

Sequence Diagram

sequenceDiagram
    participant UI as Provider UI
    participant API as Refresh API
    participant Cache as Principal Cache
    participant WS as User Workspace
    participant CLI as Provider CLI
    UI->>API: Refresh provider models
    API->>API: Check runtime and sandbox permissions
    API->>Cache: Lookup principal-scoped refresh state
    alt Reusable cached catalog
        Cache-->>API: Cached capabilities
    else Discovery required
        API->>WS: Create or wake persistent workspace
        WS->>CLI: Initialize metadata-only discovery
        CLI-->>WS: Account-aware model catalog
        WS-->>Cache: Store catalog for principal
        Cache-->>API: Refreshed capabilities
    end
    API-->>UI: Typed catalog response
    UI->>UI: Update query cache and refresh status
Loading

Reviews (6): Last reviewed commit: "feat(ai): refresh provider model catalog..." | Re-trigger Greptile

Comment thread crates/temps-ai-agent-cli/src/service.rs Outdated
Comment thread web/src/pages/agent-sandbox/AgentSandboxProviderDetail.tsx Outdated
@dviejokfs
dviejokfs force-pushed the fix/refresh-workspace-provider-models branch from 1efcc7a to 684f849 Compare September 8, 2026 12:34
@dviejokfs

Copy link
Copy Markdown
Contributor Author

@greptile-apps please re-review the current head. All previous findings have been addressed with regression coverage.

@dviejokfs
dviejokfs force-pushed the fix/refresh-workspace-provider-models branch 3 times, most recently from 52292c4 to 937ad03 Compare September 8, 2026 18:53
@dviejokfs

Copy link
Copy Markdown
Contributor Author

@greptile-apps please re-review the current head. The model refresh now creates/wakes the principal-owned persistent global workspace, uses the provider-native Claude initialize catalog, and fail-closes recovered workspace reuse behind a verified process-tree fence. All prior backend, frontend, lifecycle, and security findings have been addressed.

Discover provider capabilities explicitly instead of spawning CLIs during catalog reads. Cache authoritative results, preserve stale selections safely, and refresh workspace-capable providers through isolated credential relays.

Signed-off-by: David Viejo <dviejo@kfs.es>
@dviejokfs
dviejokfs force-pushed the fix/refresh-workspace-provider-models branch from 937ad03 to 11c19bd Compare September 8, 2026 19:02
@dviejokfs

Copy link
Copy Markdown
Contributor Author

@greptile-apps please re-review current head 11c19bd. The only delta after your prior 5/5 is a target-specific cfg on the macOS-only Duration import, fixing the Linux all-features Clippy job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant