How Pi Web Combines Model Configurations and Authentication Status: A Technical Deep Dive

Pi Web merges model settings and authentication credentials by storing both in a centralized models.json file and exposing unified API endpoints that resolve provider credentials at runtime.

In the agegr/pi-web repository, the architecture unifies provider-specific model lists with their corresponding authentication state. This integration allows the UI to display a coherent view of which models are available and whether valid credentials exist to access them.

Centralized Configuration in models.json

The system persists both model definitions and provider credentials in a single JSON file located at ~/.pi/agent/models.json. This co-location ensures that authentication parameters travel with their associated model configurations.

REST API for Configuration Management

The file app/api/models-config/route.ts implements the HTTP interface for this storage. A GET request invokes readModelsJson() (lines 30-32) to return the raw configuration, while a PUT request uses writeModelsJson() (lines 34-38) to persist updates. After any write operation, the endpoint calls invalidateModelsCache() (line 38) to clear stale cached data.

Runtime Authentication Resolution

When the application needs to verify or discover authentication details, it resolves credentials dynamically rather than relying solely on static file contents.

Provider-Specific Discovery Auth

For model discovery operations, app/api/models-config/discover/route.ts imports resolveModelDiscoveryAuth() from lib/model-discovery-auth.ts (line 53). This utility creates a temporary configuration containing only the target provider (lines 27-35), initializes a ModelRuntime, and extracts authentication via modelRuntime.getAuth(model). The function returns an object containing apiKey and additional headers (lines 45-49), enabling secure API calls without exposing full configuration files.

Global Auth Status Aggregation

To present authentication status across all providers, app/api/auth/all-providers/route.ts enumerates known providers (lines 8-10) and queries modelRuntime.getProviderAuthStatus(provider.id) for each (line 26). The endpoint filters out OAuth-only providers and custom providers whose credentials originate from models.json (lines 25-28). Each result includes a configured boolean and a source field indicating "env" or "config_file", allowing the UI to distinguish between environment variables and file-based credentials (lines 31-36).

Merging Configuration with Auth Status in the UI

The frontend constructs a unified view by combining the static configuration from models.json with the runtime auth status. First, it fetches the stored configuration via GET /api/models-config, then retrieves live auth states via GET /api/auth/all-providers. The client merges these datasets to render provider cards that show both available models and authentication health.

import { get } from "@/lib/agent-client";

// Fetch stored model configuration
const config = await get("/api/models-config");

// Fetch authentication status for each provider
const { providers } = await get("/api/auth/all-providers");

// Merge for UI rendering
const merged = providers.map(p => ({
  id: p.id,
  name: p.displayName,
  configured: p.configured,
  source: p.source,
  models: config.providers?.[p.id]?.models ?? [],
}));

Cache Coordination and Data Consistency

To prevent stale data, the system implements an invalidation strategy in lib/models-cache.ts. Any mutation of models.json—whether through the PUT endpoint, login/logout flows, or API key updates—triggers invalidateModelsCache() (line 34). This clears the in-memory cache used by loadModelsWithCache() (lines 45-80), ensuring subsequent reads reload the updated file and reflect current authentication status.

Practical Implementation Examples

Updating Model Configuration

To add a custom provider with models and credentials, submit a PUT request to the configuration endpoint:

await fetch("/api/models-config", {
  method: "PUT",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    providers: {
      mycustom: {
        apiKey: "sk-xxxx",
        models: [{ id: "my-model-1" }],
      },
    },
  }),
});

Triggering Model Discovery with Auth Resolution

To discover available models for a specific provider while automatically resolving authentication:

await fetch("/api/models-config/discover", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    provider: "openai",
    providerConfig: { apiKey: "sk-xxxx" },
  }),
});

Summary

  • Pi Web stores provider configurations and API keys together in ~/.pi/agent/models.json, managed via app/api/models-config/route.ts.
  • Runtime authentication resolution occurs through resolveModelDiscoveryAuth() in lib/model-discovery-auth.ts, which creates temporary runtimes to extract credentials.
  • The app/api/auth/all-providers/route.ts endpoint aggregates auth status across all providers, returning configured and source metadata.
  • Cache consistency is maintained via invalidateModelsCache() in lib/models-cache.ts, triggered after any configuration mutation.
  • The UI merges static configuration data with runtime auth status to present a unified provider health dashboard.

Frequently Asked Questions

How does Pi Web store authentication credentials?

Authentication credentials are stored alongside model definitions in the models.json file within the agent's data directory at ~/.pi/agent. This file contains both the list of available models and per-provider API keys.

What happens when I update the models configuration?

When you submit a PUT request to /api/models-config, the system writes to models.json and immediately calls invalidateModelsCache() (as implemented in lib/models-cache.ts line 34). This clears the in-memory cache, ensuring that subsequent reads reflect the updated configuration and authentication status.

How does the UI know if a provider is properly authenticated?

The frontend queries GET /api/auth/all-providers, which calls modelRuntime.getProviderAuthStatus() for each provider. The endpoint returns a configured boolean and a source field indicating whether credentials come from "env" variables or "config_file", allowing the interface to display real-time authentication health.

Can Pi Web discover models without manual configuration?

Yes. The /api/models-config/discover endpoint accepts a provider name and temporary configuration, then uses resolveModelDiscoveryAuth() to instantiate a runtime and extract authentication headers automatically. This enables model discovery without permanently storing credentials in models.json.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →