Files
ocp/backends/base.mjs
T
taodengandClaude Opus 4.6 1f1b3871da feat: Phase 1 — modular backend architecture (v4.0-alpha)
Internal refactor: extract BackendAdapter, ModelRegistry, AgentRouter,
SessionManager, and StatsCollector as standalone modules. Claude CLI
logic encapsulated in ClaudeCliAdapter.

External API completely unchanged — all existing endpoints behave
identically. Legacy request path (callClaude/callClaudeStreaming)
untouched. v4 modules load in parallel for validation.

New endpoints:
  GET /backends  — backend health and status
  GET /routing   — agent routing table

Architecture:
  unified-chunk.mjs    — streaming protocol (delta/done/error)
  backends/base.mjs    — BackendAdapter interface
  backends/claude-cli.mjs — Claude CLI adapter (core)
  model-registry.mjs   — model → backend mapping (Layer 1)
  agent-router.mjs     — agent policy routing (Layer 2)
  session-manager.mjs  — conversation session management
  stats-collector.mjs  — per-model/backend/agent metrics

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 08:02:53 +10:00

91 lines
2.9 KiB
JavaScript

/**
* BackendAdapter — base class for all OCP backends.
*
* Each backend adapter MUST:
* 1. Implement chatCompletion() as an async generator yielding UnifiedChunks
* 2. Implement healthCheck()
* 3. Report its costType (actual | estimated | free)
* 4. Report its tier (core | community)
*
* Adapters do NOT handle:
* - Session management (SessionManager does that)
* - Stats collection (StatsCollector does that)
* - Routing decisions (agent-router does that)
*/
export class BackendAdapter {
/**
* @param {Object} config - Backend-specific configuration
*/
constructor(config = {}) {
this._config = config;
this._enabled = config.enabled !== false;
}
/** @returns {string} Unique backend identifier */
get id() { throw new Error("BackendAdapter.id must be implemented"); }
/** @returns {string} Human-readable name */
get displayName() { throw new Error("BackendAdapter.displayName must be implemented"); }
/** @returns {string[]} List of supported model IDs */
get models() { throw new Error("BackendAdapter.models must be implemented"); }
/** @returns {"actual"|"estimated"|"free"} */
get costType() { throw new Error("BackendAdapter.costType must be implemented"); }
/** @returns {"core"|"community"} */
get tier() { return "core"; }
/** @returns {boolean} */
get enabled() { return this._enabled; }
/**
* Initialize the backend (called once at startup).
* Override to do async setup (e.g. validate binary, check API key).
*/
async initialize() {}
/**
* Shutdown the backend (called on graceful shutdown).
* Override to clean up resources.
*/
async shutdown() {}
/**
* Check if this backend is healthy and reachable.
* @returns {Promise<{ok: boolean, message: string, latencyMs: number}>}
*/
async healthCheck() {
return { ok: false, message: "healthCheck not implemented", latencyMs: 0 };
}
/**
* Execute a chat completion request.
*
* MUST yield UnifiedChunk objects:
* { type: "delta", content: "...", model, backend } — streaming content
* { type: "done", model, backend, usage?, cost? } — stream finished
* { type: "error", error: "...", model, backend } — error occurred
*
* @param {Object} request
* @param {string} request.model - Canonical model ID
* @param {Array} request.messages - OpenAI-format messages array
* @param {Object} [request.session] - Session info { uuid, resume }
* @param {Object} [request.options] - Additional options (temperature, etc.)
* @yields {import("../unified-chunk.mjs").UnifiedChunk}
*/
async *chatCompletion(request) {
throw new Error("BackendAdapter.chatCompletion must be implemented");
}
/**
* Check if this backend supports a given model.
* Default: exact match against models list.
* Override for pattern matching (e.g. "gpt-*" → openai).
*/
supportsModel(model) {
return this.models.includes(model);
}
}