Design: Flexible Agent/Provider Plugin System #171

Closed
opened 2026-01-24 10:23:14 +00:00 by jack · 0 comments
Owner

Aktueller Stand

In packages/worker/src/agents/index.ts ist das Agent-System stark hardcoded:

// Hardcoded Type
export type AIProvider = 'anthropic' | 'mistral' | 'gemini' | 'openai' | 'openrouter';

// Hardcoded Switch
switch (provider) {
  case 'anthropic':
    agent = createAnthropicAgent();
    break;
  case 'mistral':
    agent = createMistralAgent();
    break;
  case 'gemini':
  case 'openai':
  case 'openrouter':
    // TODO: Add these providers when needed
    throw new Error(`Provider '${provider}' not yet implemented`);
}

// Hardcoded Fallback
const fallbackOrder: AIProvider[] = ['mistral', 'anthropic'];

Es existiert bereits registerAgent(), aber das System ist nicht wirklich plugin-fähig.

Ziele

  1. Dynamische Provider-Registration ohne Code-Änderungen
  2. Konfigurierbare Fallback-Reihenfolge
  3. Einfache Erweiterbarkeit für neue Provider
  4. Typ-Sicherheit beibehalten

Design-Vorschläge

Option 1: Factory Registry Pattern

interface AgentFactory {
  name: string;
  displayName: string;
  isAvailable: () => boolean;
  create: () => Agent;
  priority?: number; // Für Fallback-Reihenfolge
}

class AgentRegistry {
  private factories = new Map<string, AgentFactory>();
  
  register(factory: AgentFactory): void {
    this.factories.set(factory.name, factory);
  }
  
  getAvailableProviders(): string[] {
    return [...this.factories.entries()]
      .filter(([_, f]) => f.isAvailable())
      .sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0))
      .map(([name]) => name);
  }
  
  createAgent(provider: string): Agent {
    const factory = this.factories.get(provider);
    if (!factory) throw new Error(`Unknown provider: ${provider}`);
    return factory.create();
  }
}

// Registrierung:
registry.register({
  name: 'anthropic',
  displayName: 'Anthropic Claude',
  isAvailable: () => !!process.env.ANTHROPIC_API_KEY,
  create: createAnthropicAgent,
  priority: 10,
});

Option 2: File-basiertes Plugin System

packages/worker/src/agents/
  ├── providers/
  │   ├── anthropic.provider.ts
  │   ├── mistral.provider.ts
  │   ├── openai.provider.ts
  │   └── ... (auto-discovered)
  ├── registry.ts
  └── index.ts

Jeder Provider exportiert eine Standard-Schnittstelle:

// anthropic.provider.ts
export default {
  name: 'anthropic',
  displayName: 'Anthropic Claude',
  models: ['claude-3-haiku', 'claude-3-sonnet', 'claude-3-opus'],
  envKey: 'ANTHROPIC_API_KEY',
  create: (config) => new AnthropicAgent(config),
} satisfies ProviderDefinition;

Auto-Discovery beim Start:

const providers = await glob('providers/*.provider.ts');
for (const file of providers) {
  const def = await import(file);
  registry.register(def.default);
}

Option 3: Settings-basierte Konfiguration

// settings.json
{
  "AI_PROVIDERS": {
    "primary": "anthropic",
    "fallback": ["mistral", "openai"],
    "disabled": ["gemini"]
  },
  "PROVIDER_CONFIG": {
    "anthropic": {
      "model": "claude-3-haiku-20240307",
      "maxTokens": 4096
    },
    "mistral": {
      "model": "mistral-small-latest"
    }
  }
}

Option 4: Kombinierter Ansatz (Empfohlen)

  1. Factory Registry für Code-Struktur
  2. Auto-Discovery für eingebaute Provider
  3. Settings-Konfiguration für Reihenfolge und Parameter
  4. External Plugin API für Community-Provider
// Eingebaute Provider werden auto-discovered
// Externe Provider können per npm installiert werden:
// npm install @claude-mem/provider-ollama

// settings.json
{
  "AI_PROVIDER_ORDER": ["anthropic", "mistral", "ollama"],
  "EXTERNAL_PROVIDERS": ["@claude-mem/provider-ollama"]
}

Zusätzliche Features

  • Model Selection pro Provider: Nicht nur Provider, sondern auch Model konfigurierbar
  • Provider-spezifische Settings: Temperature, MaxTokens, etc.
  • Health Checks: Provider-Verfügbarkeit periodisch prüfen
  • Cost Tracking: Token-Usage pro Provider tracken
  • Rate Limiting: Provider-spezifische Rate Limits

Betroffene Dateien

  • packages/worker/src/agents/index.ts
  • packages/worker/src/agents/types.ts
  • packages/shared/src/settings.ts
  • Neue Provider-Dateien

Priorität

Mittel - Verbessert Erweiterbarkeit und Developer Experience erheblich

## Aktueller Stand In `packages/worker/src/agents/index.ts` ist das Agent-System stark hardcoded: ```typescript // Hardcoded Type export type AIProvider = 'anthropic' | 'mistral' | 'gemini' | 'openai' | 'openrouter'; // Hardcoded Switch switch (provider) { case 'anthropic': agent = createAnthropicAgent(); break; case 'mistral': agent = createMistralAgent(); break; case 'gemini': case 'openai': case 'openrouter': // TODO: Add these providers when needed throw new Error(`Provider '${provider}' not yet implemented`); } // Hardcoded Fallback const fallbackOrder: AIProvider[] = ['mistral', 'anthropic']; ``` Es existiert bereits `registerAgent()`, aber das System ist nicht wirklich plugin-fähig. ## Ziele 1. **Dynamische Provider-Registration** ohne Code-Änderungen 2. **Konfigurierbare Fallback-Reihenfolge** 3. **Einfache Erweiterbarkeit** für neue Provider 4. **Typ-Sicherheit** beibehalten ## Design-Vorschläge ### Option 1: Factory Registry Pattern ```typescript interface AgentFactory { name: string; displayName: string; isAvailable: () => boolean; create: () => Agent; priority?: number; // Für Fallback-Reihenfolge } class AgentRegistry { private factories = new Map<string, AgentFactory>(); register(factory: AgentFactory): void { this.factories.set(factory.name, factory); } getAvailableProviders(): string[] { return [...this.factories.entries()] .filter(([_, f]) => f.isAvailable()) .sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0)) .map(([name]) => name); } createAgent(provider: string): Agent { const factory = this.factories.get(provider); if (!factory) throw new Error(`Unknown provider: ${provider}`); return factory.create(); } } // Registrierung: registry.register({ name: 'anthropic', displayName: 'Anthropic Claude', isAvailable: () => !!process.env.ANTHROPIC_API_KEY, create: createAnthropicAgent, priority: 10, }); ``` ### Option 2: File-basiertes Plugin System ``` packages/worker/src/agents/ ├── providers/ │ ├── anthropic.provider.ts │ ├── mistral.provider.ts │ ├── openai.provider.ts │ └── ... (auto-discovered) ├── registry.ts └── index.ts ``` Jeder Provider exportiert eine Standard-Schnittstelle: ```typescript // anthropic.provider.ts export default { name: 'anthropic', displayName: 'Anthropic Claude', models: ['claude-3-haiku', 'claude-3-sonnet', 'claude-3-opus'], envKey: 'ANTHROPIC_API_KEY', create: (config) => new AnthropicAgent(config), } satisfies ProviderDefinition; ``` Auto-Discovery beim Start: ```typescript const providers = await glob('providers/*.provider.ts'); for (const file of providers) { const def = await import(file); registry.register(def.default); } ``` ### Option 3: Settings-basierte Konfiguration ```json // settings.json { "AI_PROVIDERS": { "primary": "anthropic", "fallback": ["mistral", "openai"], "disabled": ["gemini"] }, "PROVIDER_CONFIG": { "anthropic": { "model": "claude-3-haiku-20240307", "maxTokens": 4096 }, "mistral": { "model": "mistral-small-latest" } } } ``` ### Option 4: Kombinierter Ansatz (Empfohlen) 1. **Factory Registry** für Code-Struktur 2. **Auto-Discovery** für eingebaute Provider 3. **Settings-Konfiguration** für Reihenfolge und Parameter 4. **External Plugin API** für Community-Provider ```typescript // Eingebaute Provider werden auto-discovered // Externe Provider können per npm installiert werden: // npm install @claude-mem/provider-ollama // settings.json { "AI_PROVIDER_ORDER": ["anthropic", "mistral", "ollama"], "EXTERNAL_PROVIDERS": ["@claude-mem/provider-ollama"] } ``` ## Zusätzliche Features - **Model Selection pro Provider**: Nicht nur Provider, sondern auch Model konfigurierbar - **Provider-spezifische Settings**: Temperature, MaxTokens, etc. - **Health Checks**: Provider-Verfügbarkeit periodisch prüfen - **Cost Tracking**: Token-Usage pro Provider tracken - **Rate Limiting**: Provider-spezifische Rate Limits ## Betroffene Dateien - `packages/worker/src/agents/index.ts` - `packages/worker/src/agents/types.ts` - `packages/shared/src/settings.ts` - Neue Provider-Dateien ## Priorität Mittel - Verbessert Erweiterbarkeit und Developer Experience erheblich
jack closed this issue 2026-01-24 19:20:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
customable/claude-mem#171
No description provided.