Completed
on 7 Jan 2026, 11:30 pm

Output

🤖 Provider Interface & Multi-Provider Routing

gvShell's abstraction layer for AI model access

📝 Provider Interface

type Provider interface {
    // Name returns the provider identifier (e.g., "claude", "gpt")
    Name() string

    // Send sends a prompt and returns the response
    Send(ctx context.Context, prompt string) (Response, error)

    // Stream sends a prompt and streams the response
    Stream(ctx context.Context, prompt string) (<-chan StreamEvent, error)
}

📦 Response & StreamEvent Types

type Response struct {
    Content    string  // AI response text
    Model      string  // Model used (e.g., "claude-sonnet-4")
    TokensIn   int     // Input tokens consumed
    TokensOut  int     // Output tokens generated
    DurationMs int64   // Request duration
}

type StreamEvent struct {
    Type    string  // "text", "done", "error"
    Content string  // Chunk content
    Error   error   // Error if Type=="error"
}

🗂️ Provider Types

Type Description Providers
TypeAPI Direct HTTP API calls (stateless, function calling only) claude, openai, gemini, ollama
TypeCLI Spawn subprocess (full tool access, persistent context) claude-cli, codex

🚦 @Provider Routing

Users can target specific providers with prefix syntax:

// Format: @provider prompt or @provider:prompt

"@claude explain quantum computing"     // → Claude API
"@gpt4 write a haiku about code"       // → OpenAI (via alias)
"@ollama:summarize this file"          // → Local Ollama
"@cc fix this bug"                     // → Claude CLI (alias)
"what is 2+2?"                         // → Default provider

📚 Standard Providers

Name Type Aliases Env Var
claude API anthropic, sonnet, opus, haiku ANTHROPIC_API_KEY
claude-cli CLI claudecli, cc ANTHROPIC_API_KEY
openai API gpt, gpt4, gpt4o, chatgpt, o1, o3 OPENAI_API_KEY
codex CLI codex-cli, codexcli OPENAI_API_KEY
gemini API google, flash, pro GOOGLE_API_KEY
ollama API local, llama, mistral (none - local)

🔄 Registry Flow

┌───────────────┐
 User Prompt     "@claude hello"
└───────┬───────┘
        │
        ▼
┌─────────────────────────┐
 ParseProviderPrefix()     Extract @provider prefix
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
 Registry.Get(name)        Resolve alias → factory()
└────────────┬────────────┘
             │
             ▼
┌─────────────────────────┐
 Provider.Stream(prompt)   Send to AI model
└────────────┬────────────┘
             │
             ▼
┌───────────────┐
 StreamEvents    text → text → done
└───────────────┘

⚡ Key Registry Methods

// Registration
registry.Register(info, factory)    // Add provider
registry.Unregister(name)           // Remove provider

// Lookup
registry.Get(name)                  // Get by name/alias
registry.GetDefault()               // Get default provider
registry.GetWithFallback()          // Try fallback chain

// Routing
registry.RoutePrompt(prompt)        // Parse @prefix, return provider
registry.SendWithRouting(ctx, p)    // Route + send (sync)
registry.StreamWithRouting(ctx, p)  // Route + stream

// Configuration
registry.SetDefault(name)           // Set default provider
registry.SetFallbackChain(names)    // Set fallback order
registry.ListByType(TypeCLI)        // Filter by type

💡 Design Highlights

  • Factory pattern - Providers created on-demand via ProviderFactory
  • Thread-safe - sync.RWMutex protects all registry operations
  • Alias resolution - Case-insensitive, supports multiple aliases per provider
  • Fallback chains - Automatic failover when primary provider unavailable
  • CLI vs API split - CLI providers have full tool access, API providers are stateless

What's Next?

Choose an action:

Quick Actions

Original Request

No layout configured

Details

Type General
Status Completed
Scope vibetools
Tags gvshellprovidersarchitectureapi
Created 7 Jan 2026, 11:29 pm
Updated 7 Jan 2026, 11:30 pm
Timing
⏱️ 86.4s
0 tools
TTFE 0% Thinking 100% Tools 0%
Created By claude

Raw Data

{
  "id": "f6537bc6-0eea-480f-b746-9e735c598693",
  "type": "general",
  "status": "completed",
  "title": "Provider Interface & Multi-Provider Routing",
  "description": "Technical deep-dive into gvShell's Provider interface and Registry system",
  "context": {
    "output": "<div style=\"background:#1e1e1e;color:#e0e0e0;padding:20px;border-radius:8px;font-family:'Consolas','Monaco',monospace;\">\n<h2 style=\"font-family:sans-serif;color:#fff;margin:0 0 8px 0;\">🤖 Provider Interface & Multi-Provider Routing</h2>\n<p style=\"color:#9ca3af;margin:0 0 20px 0;\">gvShell's abstraction layer for AI model access</p>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#3b82f6;margin:0 0 12px 0;font-family:sans-serif;\">📝 Provider Interface</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#c678dd;\">type</span> <span style=\"color:#e5c07b;\">Provider</span> <span style=\"color:#c678dd;\">interface</span> {\n    <span style=\"color:#7f848e;\">// Name returns the provider identifier (e.g., \"claude\", \"gpt\")</span>\n    <span style=\"color:#61afef;\">Name</span>() <span style=\"color:#98c379;\">string</span>\n\n    <span style=\"color:#7f848e;\">// Send sends a prompt and returns the response</span>\n    <span style=\"color:#61afef;\">Send</span>(ctx <span style=\"color:#e5c07b;\">context.Context</span>, prompt <span style=\"color:#98c379;\">string</span>) (<span style=\"color:#e5c07b;\">Response</span>, <span style=\"color:#98c379;\">error</span>)\n\n    <span style=\"color:#7f848e;\">// Stream sends a prompt and streams the response</span>\n    <span style=\"color:#61afef;\">Stream</span>(ctx <span style=\"color:#e5c07b;\">context.Context</span>, prompt <span style=\"color:#98c379;\">string</span>) (<span style=\"color:#c678dd;\">&lt;-chan</span> <span style=\"color:#e5c07b;\">StreamEvent</span>, <span style=\"color:#98c379;\">error</span>)\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#22c55e;margin:0 0 12px 0;font-family:sans-serif;\">📦 Response & StreamEvent Types</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#c678dd;\">type</span> <span style=\"color:#e5c07b;\">Response</span> <span style=\"color:#c678dd;\">struct</span> {\n    Content    <span style=\"color:#98c379;\">string</span>  <span style=\"color:#7f848e;\">// AI response text</span>\n    Model      <span style=\"color:#98c379;\">string</span>  <span style=\"color:#7f848e;\">// Model used (e.g., \"claude-sonnet-4\")</span>\n    TokensIn   <span style=\"color:#98c379;\">int</span>     <span style=\"color:#7f848e;\">// Input tokens consumed</span>\n    TokensOut  <span style=\"color:#98c379;\">int</span>     <span style=\"color:#7f848e;\">// Output tokens generated</span>\n    DurationMs <span style=\"color:#98c379;\">int64</span>   <span style=\"color:#7f848e;\">// Request duration</span>\n}\n\n<span style=\"color:#c678dd;\">type</span> <span style=\"color:#e5c07b;\">StreamEvent</span> <span style=\"color:#c678dd;\">struct</span> {\n    Type    <span style=\"color:#98c379;\">string</span>  <span style=\"color:#7f848e;\">// \"text\", \"done\", \"error\"</span>\n    Content <span style=\"color:#98c379;\">string</span>  <span style=\"color:#7f848e;\">// Chunk content</span>\n    Error   <span style=\"color:#98c379;\">error</span>   <span style=\"color:#7f848e;\">// Error if Type==\"error\"</span>\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#8b5cf6;margin:0 0 12px 0;font-family:sans-serif;\">🗂️ Provider Types</h3>\n<table style=\"width:100%;border-collapse:collapse;font-size:0.9rem;\">\n<tr style=\"background:#1e1e1e;\">\n  <th style=\"text-align:left;padding:10px;color:#8b5cf6;border-bottom:1px solid #444;\">Type</th>\n  <th style=\"text-align:left;padding:10px;color:#8b5cf6;border-bottom:1px solid #444;\">Description</th>\n  <th style=\"text-align:left;padding:10px;color:#8b5cf6;border-bottom:1px solid #444;\">Providers</th>\n</tr>\n<tr style=\"background:#252525;\">\n  <td style=\"padding:10px;\"><code style=\"color:#3b82f6;\">TypeAPI</code></td>\n  <td style=\"padding:10px;color:#9ca3af;\">Direct HTTP API calls (stateless, function calling only)</td>\n  <td style=\"padding:10px;\">claude, openai, gemini, ollama</td>\n</tr>\n<tr style=\"background:#1e1e1e;\">\n  <td style=\"padding:10px;\"><code style=\"color:#22c55e;\">TypeCLI</code></td>\n  <td style=\"padding:10px;color:#9ca3af;\">Spawn subprocess (full tool access, persistent context)</td>\n  <td style=\"padding:10px;\">claude-cli, codex</td>\n</tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#f59e0b;margin:0 0 12px 0;font-family:sans-serif;\">🚦 @Provider Routing</h3>\n<p style=\"color:#9ca3af;margin:0 0 12px 0;font-family:sans-serif;\">Users can target specific providers with prefix syntax:</p>\n<pre style=\"margin:0;line-height:1.8;overflow-x:auto;\"><span style=\"color:#7f848e;\">// Format: @provider prompt or @provider:prompt</span>\n\n<span style=\"color:#98c379;\">\"@claude explain quantum computing\"</span>     <span style=\"color:#7f848e;\">// → Claude API</span>\n<span style=\"color:#98c379;\">\"@gpt4 write a haiku about code\"</span>       <span style=\"color:#7f848e;\">// → OpenAI (via alias)</span>\n<span style=\"color:#98c379;\">\"@ollama:summarize this file\"</span>          <span style=\"color:#7f848e;\">// → Local Ollama</span>\n<span style=\"color:#98c379;\">\"@cc fix this bug\"</span>                     <span style=\"color:#7f848e;\">// → Claude CLI (alias)</span>\n<span style=\"color:#98c379;\">\"what is 2+2?\"</span>                         <span style=\"color:#7f848e;\">// → Default provider</span></pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#ef4444;margin:0 0 12px 0;font-family:sans-serif;\">📚 Standard Providers</h3>\n<table style=\"width:100%;border-collapse:collapse;font-size:0.85rem;\">\n<tr style=\"background:#1e1e1e;\">\n  <th style=\"text-align:left;padding:8px;color:#ef4444;border-bottom:1px solid #444;\">Name</th>\n  <th style=\"text-align:left;padding:8px;color:#ef4444;border-bottom:1px solid #444;\">Type</th>\n  <th style=\"text-align:left;padding:8px;color:#ef4444;border-bottom:1px solid #444;\">Aliases</th>\n  <th style=\"text-align:left;padding:8px;color:#ef4444;border-bottom:1px solid #444;\">Env Var</th>\n</tr>\n<tr style=\"background:#252525;\">\n  <td style=\"padding:8px;\"><code style=\"color:#8b5cf6;\">claude</code></td>\n  <td style=\"padding:8px;\">API</td>\n  <td style=\"padding:8px;color:#7f848e;\">anthropic, sonnet, opus, haiku</td>\n  <td style=\"padding:8px;\"><code style=\"color:#e5c07b;\">ANTHROPIC_API_KEY</code></td>\n</tr>\n<tr style=\"background:#1e1e1e;\">\n  <td style=\"padding:8px;\"><code style=\"color:#22c55e;\">claude-cli</code></td>\n  <td style=\"padding:8px;\">CLI</td>\n  <td style=\"padding:8px;color:#7f848e;\">claudecli, cc</td>\n  <td style=\"padding:8px;\"><code style=\"color:#e5c07b;\">ANTHROPIC_API_KEY</code></td>\n</tr>\n<tr style=\"background:#252525;\">\n  <td style=\"padding:8px;\"><code style=\"color:#8b5cf6;\">openai</code></td>\n  <td style=\"padding:8px;\">API</td>\n  <td style=\"padding:8px;color:#7f848e;\">gpt, gpt4, gpt4o, chatgpt, o1, o3</td>\n  <td style=\"padding:8px;\"><code style=\"color:#e5c07b;\">OPENAI_API_KEY</code></td>\n</tr>\n<tr style=\"background:#1e1e1e;\">\n  <td style=\"padding:8px;\"><code style=\"color:#22c55e;\">codex</code></td>\n  <td style=\"padding:8px;\">CLI</td>\n  <td style=\"padding:8px;color:#7f848e;\">codex-cli, codexcli</td>\n  <td style=\"padding:8px;\"><code style=\"color:#e5c07b;\">OPENAI_API_KEY</code></td>\n</tr>\n<tr style=\"background:#252525;\">\n  <td style=\"padding:8px;\"><code style=\"color:#8b5cf6;\">gemini</code></td>\n  <td style=\"padding:8px;\">API</td>\n  <td style=\"padding:8px;color:#7f848e;\">google, flash, pro</td>\n  <td style=\"padding:8px;\"><code style=\"color:#e5c07b;\">GOOGLE_API_KEY</code></td>\n</tr>\n<tr style=\"background:#1e1e1e;\">\n  <td style=\"padding:8px;\"><code style=\"color:#8b5cf6;\">ollama</code></td>\n  <td style=\"padding:8px;\">API</td>\n  <td style=\"padding:8px;color:#7f848e;\">local, llama, mistral</td>\n  <td style=\"padding:8px;color:#7f848e;\">(none - local)</td>\n</tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#06b6d4;margin:0 0 12px 0;font-family:sans-serif;\">🔄 Registry Flow</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;color:#e0e0e0;\">\n<span style=\"color:#3b82f6;\">┌───────────────┐</span>\n<span style=\"color:#3b82f6;\">│</span> User Prompt   <span style=\"color:#3b82f6;\">│</span>  <span style=\"color:#98c379;\">\"@claude hello\"</span>\n<span style=\"color:#3b82f6;\">└───────┬───────┘</span>\n        │\n        ▼\n<span style=\"color:#8b5cf6;\">┌─────────────────────────┐</span>\n<span style=\"color:#8b5cf6;\">│</span> ParseProviderPrefix()   <span style=\"color:#8b5cf6;\">│</span>  Extract <span style=\"color:#e5c07b;\">@provider</span> prefix\n<span style=\"color:#8b5cf6;\">└────────────┬────────────┘</span>\n             │\n             ▼\n<span style=\"color:#22c55e;\">┌─────────────────────────┐</span>\n<span style=\"color:#22c55e;\">│</span> Registry.Get(name)      <span style=\"color:#22c55e;\">│</span>  Resolve alias → factory()\n<span style=\"color:#22c55e;\">└────────────┬────────────┘</span>\n             │\n             ▼\n<span style=\"color:#f59e0b;\">┌─────────────────────────┐</span>\n<span style=\"color:#f59e0b;\">│</span> Provider.Stream(prompt) <span style=\"color:#f59e0b;\">│</span>  Send to AI model\n<span style=\"color:#f59e0b;\">└────────────┬────────────┘</span>\n             │\n             ▼\n<span style=\"color:#ef4444;\">┌───────────────┐</span>\n<span style=\"color:#ef4444;\">│</span> StreamEvents  <span style=\"color:#ef4444;\">│</span>  text → text → done\n<span style=\"color:#ef4444;\">└───────────────┘</span>\n</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:8px;margin-bottom:20px;\">\n<h3 style=\"color:#ec4899;margin:0 0 12px 0;font-family:sans-serif;\">⚡ Key Registry Methods</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#7f848e;\">// Registration</span>\nregistry.<span style=\"color:#61afef;\">Register</span>(info, factory)    <span style=\"color:#7f848e;\">// Add provider</span>\nregistry.<span style=\"color:#61afef;\">Unregister</span>(name)           <span style=\"color:#7f848e;\">// Remove provider</span>\n\n<span style=\"color:#7f848e;\">// Lookup</span>\nregistry.<span style=\"color:#61afef;\">Get</span>(name)                  <span style=\"color:#7f848e;\">// Get by name/alias</span>\nregistry.<span style=\"color:#61afef;\">GetDefault</span>()               <span style=\"color:#7f848e;\">// Get default provider</span>\nregistry.<span style=\"color:#61afef;\">GetWithFallback</span>()          <span style=\"color:#7f848e;\">// Try fallback chain</span>\n\n<span style=\"color:#7f848e;\">// Routing</span>\nregistry.<span style=\"color:#61afef;\">RoutePrompt</span>(prompt)        <span style=\"color:#7f848e;\">// Parse @prefix, return provider</span>\nregistry.<span style=\"color:#61afef;\">SendWithRouting</span>(ctx, p)    <span style=\"color:#7f848e;\">// Route + send (sync)</span>\nregistry.<span style=\"color:#61afef;\">StreamWithRouting</span>(ctx, p)  <span style=\"color:#7f848e;\">// Route + stream</span>\n\n<span style=\"color:#7f848e;\">// Configuration</span>\nregistry.<span style=\"color:#61afef;\">SetDefault</span>(name)           <span style=\"color:#7f848e;\">// Set default provider</span>\nregistry.<span style=\"color:#61afef;\">SetFallbackChain</span>(names)    <span style=\"color:#7f848e;\">// Set fallback order</span>\nregistry.<span style=\"color:#61afef;\">ListByType</span>(TypeCLI)        <span style=\"color:#7f848e;\">// Filter by type</span></pre>\n</div>\n\n<div style=\"background:#1e3a5f;border:2px solid #3b82f6;padding:16px;border-radius:8px;font-family:sans-serif;\">\n<h4 style=\"color:#3b82f6;margin:0 0 8px 0;\">💡 Design Highlights</h4>\n<ul style=\"color:#e0e0e0;margin:0;padding-left:20px;line-height:1.8;\">\n<li><strong>Factory pattern</strong> - Providers created on-demand via <code>ProviderFactory</code></li>\n<li><strong>Thread-safe</strong> - <code>sync.RWMutex</code> protects all registry operations</li>\n<li><strong>Alias resolution</strong> - Case-insensitive, supports multiple aliases per provider</li>\n<li><strong>Fallback chains</strong> - Automatic failover when primary provider unavailable</li>\n<li><strong>CLI vs API split</strong> - CLI providers have full tool access, API providers are stateless</li>\n</ul>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-top:24px;font-family:sans-serif;\">\n<h4 style=\"margin:0 0 8px 0;color:#fff;\">What's Next?</h4>\n<p style=\"color:#9ca3af;margin:0;\">Choose an action:</p>\n</div>\n</div>",
    "choices": [
      {
        "label": "Claude Provider",
        "value": "Show the Claude provider implementation details",
        "primary": true
      },
      {
        "label": "CLI vs API Deep Dive",
        "value": "Explain the differences between CLI and API providers in detail"
      },
      {
        "label": "Fallback Chains",
        "value": "Show how provider fallback chains work with examples"
      }
    ],
    "requestedAt": "2026-01-07T10:45:00Z",
    "requestId": "dd378b67-4cfc-47ae-a01f-b0fe70795adf",
    "turnTiming": {
      "totalMs": 86419,
      "ttfeMs": 48,
      "thinkingMs": 86371,
      "toolExecutionMs": 0,
      "toolCallCount": 0,
      "thinkingPct": 100,
      "toolsPct": 0,
      "ttfePct": 0
    }
  },
  "createdBy": "claude",
  "createdAt": "2026-01-07T13:29:57.590Z",
  "updatedAt": "2026-01-07T13:30:04.786Z",
  "requestId": "dd378b67-4cfc-47ae-a01f-b0fe70795adf",
  "scope": "vibetools",
  "tags": [
    "gvshell",
    "providers",
    "architecture",
    "api"
  ],
  "targetUser": "claude"
}
DashboardReportsKontasksFlowsDecisionsSessionsTelemetryLogs + Go