{"_id":"@ai-orchestration/core","_rev":"4-85155de5ca6ad8e6b3b90e8d2aefebbf","name":"@ai-orchestration/core","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@ai-orchestration/core","version":"0.1.0","keywords":["ai","llm","orchestration","grok","gemini","openrouter","cerebras"],"author":{"name":"Hugo Moraga Morales"},"license":"MIT","_id":"@ai-orchestration/core@0.1.0","maintainers":[{"name":"kndl","email":"hg.moraga@gmail.com"}],"dist":{"shasum":"52f99a40bb4a35b3bb6ef80e6bef01e94801beef","tarball":"https://registry.npmjs.org/@ai-orchestration/core/-/core-0.1.0.tgz","fileCount":199,"integrity":"sha512-YEiuU8b7vHm+ASbH0XcqLNLLcnCla2z8Nl7hcE1IYZofS79gyHQ52LGyR+rO8F65M/X4CWqXkykA1X5c5gQrFQ==","signatures":[{"sig":"MEYCIQCt9+irjxBnRI1mOdsqLGN5FX7z7MM0te3sRzePtySvhwIhAL3rBbf7P8/EHQmCV+cFf/okbabCFYo285TdK+15gSwM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":445732},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsc --watch","link":"npm run build && npm link","lint":"eslint src --ext .ts","test":"npx tsx tests/basic.test.ts","build":"tsc","test:mock":"npx tsx examples/test-mock.ts","typecheck":"tsc --noEmit","pack:local":"npm run build && npm pack","test:local":"npx tsx examples/test-local.ts","prepublishOnly":"npm run build && npm run typecheck"},"_npmUser":{"name":"kndl","email":"hg.moraga@gmail.com"},"_npmVersion":"10.1.0","description":"Modular AI orchestration framework for multiple LLM providers","directories":{},"_nodeVersion":"20.8.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.7.0","typescript":"^5.3.3","@types/node":"^20.10.0"},"peerDependencies":{"openai":"^4.20.0","groq-sdk":"^0.3.0","@google/generative-ai":"^0.2.0"},"peerDependenciesMeta":{"openai":{"optional":true},"groq-sdk":{"optional":true},"@google/generative-ai":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.0_1767738827539_0.07810970722906929","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ai-orchestration/core","version":"0.2.0","keywords":["ai","llm","orchestration","grok","gemini","openrouter","cerebras"],"author":{"name":"Hugo Moraga Morales"},"license":"MIT","_id":"@ai-orchestration/core@0.2.0","maintainers":[{"name":"kndl","email":"hg.moraga@gmail.com"}],"dist":{"shasum":"4bc8fbc7a128dd55d29f720bbefa9163a4c658af","tarball":"https://registry.npmjs.org/@ai-orchestration/core/-/core-0.2.0.tgz","fileCount":206,"integrity":"sha512-OMvenVfLuzXQy8R5Nha2q97Rp4mDjq/rGqg1ZgK5HO7dIGrXrhtEMXpZKqE4NSx809nxedUpA5sxNnSDtlgHhg==","signatures":[{"sig":"MEUCIQDhtMsyxMwn4bvTC0yvn75gt2ZqY5I7PUIkPNoocpoN2AIgJ4kMekI8v5LU/zhdEZGjoBRbDOoUTfAwxA4RwrMgb28=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":529296},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e87dc44ec15ca953f7d64907e73bfcfcdfbccdf6","scripts":{"dev":"tsc --watch","link":"npm run build && npm link","lint":"eslint src --ext .ts","test":"node --test --loader tsx tests/**/*.test.ts","build":"tsc","test:mock":"npx tsx examples/test-mock.ts","typecheck":"tsc --noEmit","pack:local":"npm run build && npm pack","test:local":"npx tsx examples/test-local.ts","example:basic":"npx tsx examples/basic.ts","prepublishOnly":"npm run build && npm run typecheck","example:metrics":"npx tsx examples/metrics.ts","example:language":"npx tsx examples/language.ts","example:strategies":"npx tsx examples/strategies.ts"},"_npmUser":{"name":"kndl","email":"hg.moraga@gmail.com"},"_npmVersion":"10.1.0","description":"Modular AI orchestration framework for multiple LLM providers","directories":{},"_nodeVersion":"20.8.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.7.0","typescript":"^5.3.3","@types/node":"^20.10.0"},"peerDependencies":{"openai":"^4.20.0","groq-sdk":"^0.3.0","@google/generative-ai":"^0.2.0"},"peerDependenciesMeta":{"openai":{"optional":true},"groq-sdk":{"optional":true},"@google/generative-ai":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/core_0.2.0_1767744743719_0.7951789773353588","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ai-orchestration/core","version":"0.3.0","keywords":["ai","llm","orchestration","grok","gemini","openrouter","cerebras"],"author":{"name":"Hugo Moraga Morales"},"license":"MIT","_id":"@ai-orchestration/core@0.3.0","maintainers":[{"name":"kndl","email":"hg.moraga@gmail.com"}],"dist":{"shasum":"6812942c10a63cf216b8660955599f1d05eecd0c","tarball":"https://registry.npmjs.org/@ai-orchestration/core/-/core-0.3.0.tgz","fileCount":376,"integrity":"sha512-viQYEK6E2GB9+e/CSiRwMKw94jGl6aV/sdHD8rL2bPK/fiMTi53+UQNhH4p5vEU2B0SYbUZaLXHZsi7ljHAqVA==","signatures":[{"sig":"MEUCIQDWS6/bT84sfTooYoloV+2XyrGuwAgZ+Au6qNmkBAF3wgIgBREWIJjgHyuJW4X98jyEuT5xF0kltpyhs2yGTJWmPOA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":953390},"main":"./dist/cjs/index.js","type":"module","types":"./dist/esm/index.d.ts","module":"./dist/esm/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}}},"gitHead":"7f6be1c8f6ef3198fd0f0d529614827da01fa405","scripts":{"dev":"tsc --watch","link":"npm run build && npm link","lint":"eslint src --ext .ts","test":"node --test --loader tsx tests/**/*.test.ts","build":"npm run build:esm && npm run build:cjs","build:cjs":"tsc -p tsconfig.cjs.json","build:esm":"tsc -p tsconfig.esm.json","test:mock":"npx tsx examples/test-mock.ts","typecheck":"tsc --noEmit","pack:local":"npm run build && npm pack","test:local":"npx tsx examples/test-local.ts","example:basic":"npx tsx examples/basic.ts","prepublishOnly":"npm run build && npm run typecheck","example:metrics":"npx tsx examples/metrics.ts","example:language":"npx tsx examples/language.ts","example:strategies":"npx tsx examples/strategies.ts"},"_npmUser":{"name":"kndl","email":"hg.moraga@gmail.com"},"_npmVersion":"10.1.0","description":"Modular AI orchestration framework for multiple LLM providers","directories":{},"_nodeVersion":"20.8.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.7.0","typescript":"^5.3.3","@types/node":"^20.10.0"},"peerDependencies":{"openai":"^4.20.0","groq-sdk":"^0.3.0","@google/generative-ai":"^0.2.0"},"peerDependenciesMeta":{"openai":{"optional":true},"groq-sdk":{"optional":true},"@google/generative-ai":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/core_0.3.0_1767754623099_0.41801900648904566","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ai-orchestration/core","version":"0.4.0","description":"Modular AI orchestration framework for multiple LLM providers","type":"module","main":"./dist/cjs/index.js","module":"./dist/esm/index.js","types":"./dist/esm/index.d.ts","exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}}},"scripts":{"build":"npm run build:esm && npm run build:cjs","build:esm":"tsc -p tsconfig.esm.json","build:cjs":"tsc -p tsconfig.cjs.json","dev":"tsc --watch","test":"node --test --import tsx tests/basic.test.ts tests/image-generation.test.ts tests/multimodal.test.ts","test:local":"npx tsx examples/test-local.ts","test:mock":"npx tsx examples/test-mock.ts","example:basic":"npx tsx examples/basic.ts","example:strategies":"npx tsx examples/strategies.ts","example:language":"npx tsx examples/language.ts","example:metrics":"npx tsx examples/metrics.ts","example:images":"npx tsx examples/images.ts","example:image-generation":"npx tsx examples/image-generation.ts","lint":"eslint src --ext .ts","typecheck":"tsc --noEmit","link":"npm run build && npm link","pack:local":"npm run build && npm pack","prepublishOnly":"npm run build && npm run typecheck"},"keywords":["ai","llm","orchestration","grok","gemini","openrouter","cerebras"],"author":{"name":"Hugo Moraga Morales"},"license":"MIT","engines":{"node":">=18.0.0"},"devDependencies":{"@types/node":"^20.10.0","typescript":"^5.3.3","tsx":"^4.7.0"},"peerDependencies":{"@google/generative-ai":"^0.2.0","groq-sdk":"^0.3.0","openai":"^4.20.0"},"peerDependenciesMeta":{"@google/generative-ai":{"optional":true},"groq-sdk":{"optional":true},"openai":{"optional":true}},"_id":"@ai-orchestration/core@0.4.0","gitHead":"2b82871f23627aaf7950e1bbe7a8b7d071989069","_nodeVersion":"20.8.0","_npmVersion":"10.1.0","dist":{"integrity":"sha512-ZQkGdMomLS2qOfWhfwDa5f6DghJ7ddjf/xJTN6EFiApywcTo0PmhARLSBo1uIh+TWbDZEqGv3rVh7KPPPOxaXQ==","shasum":"482558101134bdd8004396ab47443e40a92ad040","tarball":"https://registry.npmjs.org/@ai-orchestration/core/-/core-0.4.0.tgz","fileCount":386,"unpackedSize":1083654,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCz5AAbiim7xMJh4DZzDL321b+zvL3iI1mYvaxgsi/MJAIhAO4l/NxxMRbHfpmtm430+IaKB5FR+Tr0dewrnAeEcyW3"}]},"_npmUser":{"name":"kndl","email":"hg.moraga@gmail.com"},"directories":{},"maintainers":[{"name":"kndl","email":"hg.moraga@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.4.0_1768880780704_0.8513028927081607"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-06T22:33:47.414Z","modified":"2026-01-20T03:46:20.974Z","0.1.0":"2026-01-06T22:33:47.697Z","0.2.0":"2026-01-07T00:12:23.919Z","0.3.0":"2026-01-07T02:57:03.264Z","0.4.0":"2026-01-20T03:46:20.848Z"},"author":{"name":"Hugo Moraga Morales"},"license":"MIT","keywords":["ai","llm","orchestration","grok","gemini","openrouter","cerebras"],"description":"Modular AI orchestration framework for multiple LLM providers","maintainers":[{"name":"kndl","email":"hg.moraga@gmail.com"}],"readme":"# AI Orchestration Framework\n\nA modular and extensible framework for orchestrating multiple AI/LLM providers consistently and configurable.\n\n**📦 This is an npm package**: API keys must be configured in the project that uses this package (using environment variables or `.env` files in that project), not in the package itself.\n\n## Features\n\n- 🔌 **Plugin-based architecture**: Add new providers or strategies without modifying the core\n- 🎯 **Multiple selection strategies**: Round-robin, priority, fallback, weighted, health-aware\n- 🌊 **Native streaming**: Full support for streaming responses using ReadableStream\n- 🔄 **Automatic fallback**: Automatically tries multiple providers if one fails\n- 💚 **Health checks**: Provider health monitoring with latency metrics\n- 📦 **Runtime agnostic**: Compatible with Node.js and Bun\n- 🎨 **Declarative API**: Simple configuration via JSON/JS objects\n- 🔒 **Type-safe**: Fully typed with TypeScript\n\n## Installation\n\n```bash\nnpm install @ai-orchestration/core\n```\n\n### Module System Compatibility\n\nThis package supports both **ESM** (ECMAScript Modules) and **CommonJS**, so you can use it in any Node.js project:\n\n**ESM Projects** (recommended):\n```typescript\nimport { createOrchestrator } from '@ai-orchestration/core';\n```\n\n**CommonJS Projects**:\n```javascript\nconst { createOrchestrator } = require('@ai-orchestration/core');\n```\n\nThe package automatically exports the correct format based on your project's module system.\n\n## Quick Start\n\n### Basic Usage\n\n```typescript\nimport { createOrchestrator } from '@ai-orchestration/core';\n\n// API keys should come from environment variables configured in YOUR project\n// Example: export GROQ_API_KEY=\"your-key\" or using dotenv in your project\nconst orchestrator = createOrchestrator({\n  providers: [\n    {\n      id: 'groq-1',\n      type: 'groq',\n      apiKey: process.env.GROQ_API_KEY!, // Configure this variable in your project\n      model: 'llama-3.3-70b-versatile',\n    },\n    {\n      id: 'openrouter-1',\n      type: 'openrouter',\n      apiKey: process.env.OPENROUTER_API_KEY!,\n      model: 'openai/gpt-3.5-turbo',\n    },\n  ],\n  strategy: {\n    type: 'round-robin',\n  },\n});\n\n// Simple chat\nconst response = await orchestrator.chat([\n  { role: 'user', content: 'Hello, world!' },\n]);\n\nconsole.log(response.content);\n\n// Streaming chat\nconst stream = await orchestrator.chatStream([\n  { role: 'user', content: 'Tell me a story' },\n]);\n\nconst reader = stream.getReader();\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n  process.stdout.write(value.content);\n}\n```\n\n### Programmatic Usage\n\n```typescript\nimport {\n  Orchestrator,\n  RoundRobinStrategy,\n  GroqProvider,\n  OpenRouterProvider,\n} from '@ai-orchestration/core';\n\n// Create strategy\nconst strategy = new RoundRobinStrategy();\n\n// Create orchestrator\nconst orchestrator = new Orchestrator(strategy);\n\n// Register providers\n// API keys should come from environment variables configured in YOUR project\norchestrator.registerProvider(\n  new GroqProvider({\n    id: 'groq-1',\n    apiKey: process.env.GROQ_API_KEY!,\n  })\n);\n\norchestrator.registerProvider(\n  new OpenRouterProvider({\n    id: 'openrouter-1',\n    apiKey: process.env.OPENROUTER_API_KEY!,\n  })\n);\n\n// Use\nconst response = await orchestrator.chat([\n  { role: 'user', content: 'Hello!' },\n]);\n```\n\n## Selection Strategies\n\n### Round-Robin\n\nCycles through providers in order:\n\n```typescript\n{\n  strategy: {\n    type: 'round-robin',\n  },\n}\n```\n\n### Priority\n\nSelects providers based on priority (lower number = higher priority):\n\n```typescript\n{\n  strategy: {\n    type: 'priority',\n    priorities: {\n      'groq-1': 1,\n      'openrouter-1': 2,\n      'gemini-1': 3,\n    },\n  },\n}\n```\n\n### Fallback\n\nTries providers in order until one works:\n\n```typescript\n{\n  strategy: {\n    type: 'fallback',\n    order: ['groq-1', 'openrouter-1', 'gemini-1'],\n  },\n}\n```\n\n### Weighted\n\nSelection based on weights (useful for load balancing):\n\n```typescript\n{\n  strategy: {\n    type: 'weighted',\n    weights: {\n      'groq-1': 0.7,\n      'openrouter-1': 0.3,\n    },\n  },\n}\n```\n\n### Weighted Cost-Aware\n\nConsiders cost per token:\n\n```typescript\n{\n  strategy: {\n    type: 'weighted',\n    costAware: true,\n    weights: {\n      'groq-1': 1.0,\n      'openrouter-1': 1.0,\n    },\n  },\n}\n```\n\n### Health-Aware\n\nSelects based on health metrics (latency, success rate):\n\n```typescript\n{\n  strategy: {\n    type: 'health-aware',\n    preferLowLatency: true,\n    minHealthScore: 0.5,\n  },\n}\n```\n\n## Supported Providers\n\n### Groq\n\n```typescript\n{\n  id: 'groq-1',\n  type: 'groq',\n  apiKey: 'your-api-key',\n  model: 'llama-3.3-70b-versatile', // optional, default\n  baseURL: 'https://api.groq.com/openai/v1', // optional\n}\n```\n\n### OpenRouter\n\n```typescript\n{\n  id: 'openrouter-1',\n  type: 'openrouter',\n  apiKey: 'your-api-key',\n  model: 'openai/gpt-3.5-turbo', // optional\n  baseURL: 'https://openrouter.ai/api/v1', // optional\n}\n```\n\n### Google Gemini\n\n```typescript\n{\n  id: 'gemini-1',\n  type: 'gemini',\n  apiKey: 'your-api-key',\n  model: 'gemini-pro', // optional\n  baseURL: 'https://generativelanguage.googleapis.com/v1beta', // optional\n}\n```\n\n### Cerebras\n\nCerebras Inference API - OpenAI compatible. Documentation: [inference-docs.cerebras.ai](https://inference-docs.cerebras.ai/quickstart)\n\n```typescript\n{\n  id: 'cerebras-1',\n  type: 'cerebras',\n  apiKey: 'your-api-key', // Get at: https://inference-docs.cerebras.ai\n  model: 'llama-3.3-70b', // optional, default\n  baseURL: 'https://api.cerebras.ai/v1', // optional\n}\n```\n\n**Note**: Cerebras API requires the `User-Agent` header to avoid CloudFront blocking. This is included automatically.\n\n### Local (Local Models)\n\nFor local models that expose an OpenAI-compatible API:\n\n```typescript\n{\n  id: 'local-1',\n  type: 'local',\n  baseURL: 'http://localhost:8000',\n  model: 'local-model', // optional\n  apiKey: 'optional-key', // optional\n}\n```\n\n## Advanced Configuration\n\n### Retry and Timeout Configuration\n\n```typescript\nconst orchestrator = createOrchestrator({\n  providers: [...],\n  strategy: {...},\n  maxRetries: 3, // Maximum retry attempts (default: number of providers)\n  requestTimeout: 30000, // Global timeout in milliseconds (default: 30000)\n  retryDelay: 'exponential', // or number in milliseconds (default: 1000)\n});\n```\n\n### Circuit Breaker\n\nAutomatically disable providers after consecutive failures:\n\n```typescript\nconst orchestrator = createOrchestrator({\n  providers: [...],\n  strategy: {...},\n  circuitBreaker: {\n    enabled: true,\n    failureThreshold: 5, // Open circuit after 5 failures\n    resetTimeout: 60000, // Reset after 60 seconds\n  },\n});\n```\n\n### Health Checks\n\nEnhanced health check configuration:\n\n```typescript\nconst orchestrator = createOrchestrator({\n  providers: [...],\n  strategy: {...},\n  healthCheck: {\n    enabled: true,\n    interval: 60000, // Check every 60 seconds\n    timeout: 5000, // Health check timeout (default: 5000ms)\n    maxConsecutiveFailures: 3, // Mark unhealthy after 3 failures (default: 3)\n    latencyThreshold: 10000, // Max latency in ms (default: 10000ms)\n  },\n  // Legacy format still supported:\n  // enableHealthChecks: true,\n  // healthCheckInterval: 60000,\n});\n```\n\nOr manually check health:\n\n```typescript\nconst health = await provider.checkHealth();\nconsole.log(health.healthy, health.latency);\n```\n\n## Chat Options\n\n```typescript\nconst response = await orchestrator.chat(messages, {\n  temperature: 0.7,\n  maxTokens: 1000,\n  topP: 0.9,\n  topK: 40,\n  stopSequences: ['\\n\\n'],\n  responseLanguage: 'es', // Force response in Spanish\n  frequencyPenalty: 0.5, // Reduce repetition\n  presencePenalty: 0.3, // Encourage new topics\n  seed: 42, // For reproducible outputs\n  timeout: 30000, // Request timeout in milliseconds\n  user: 'user-123', // User identifier for tracking\n});\n```\n\n### Available Chat Options\n\n- **`temperature`**: Controls randomness (0.0 to 2.0)\n- **`maxTokens`**: Maximum tokens in response\n- **`topP`**: Nucleus sampling threshold\n- **`topK`**: Top-K sampling\n- **`stopSequences`**: Stop generation on these sequences\n- **`responseLanguage`**: Force response language (see below)\n- **`frequencyPenalty`**: Penalize frequent tokens (-2.0 to 2.0)\n- **`presencePenalty`**: Penalize existing tokens (-2.0 to 2.0)\n- **`seed`**: Seed for reproducible outputs\n- **`timeout`**: Request timeout in milliseconds (overrides global timeout)\n- **`user`**: User identifier for tracking/rate limiting\n\n### Forcing Response Language\n\nYou can force the AI to respond in a specific language using the `responseLanguage` option:\n\n```typescript\n// Using ISO 639-1 language codes\nconst response = await orchestrator.chat(messages, {\n  responseLanguage: 'es', // Spanish\n  // or 'en', 'fr', 'de', 'it', 'pt', 'ja', 'zh', 'ru', etc.\n});\n\n// Using full language names\nconst response2 = await orchestrator.chat(messages, {\n  responseLanguage: 'spanish', // Also works\n  // or 'english', 'french', 'german', 'italian', etc.\n});\n```\n\n**How it works**: When `responseLanguage` is specified, the framework automatically prepends a system message instructing the model to respond in the specified language. If you already have a system message, the language instruction will be prepended to it.\n\n**Supported languages**: Spanish, English, French, German, Italian, Portuguese, Japanese, Chinese, Russian, Korean, Arabic, Hindi, Dutch, Polish, Swedish, Turkish (and more via ISO 639-1 codes).\n\n## Metrics and Analytics\n\nTrack provider usage, costs, and strategy effectiveness:\n\n```typescript\nconst orchestrator = createOrchestrator({\n  providers: [...],\n  strategy: {...},\n  enableMetrics: true, // Enabled by default\n  onMetricsEvent: (event) => {\n    // Optional: Real-time event tracking\n    console.log('Event:', event.type, event.providerId);\n  },\n});\n\n// Make some requests...\n\n// Get overall metrics\nconst metrics = orchestrator.getMetrics().getOrchestratorMetrics();\nconsole.log('Total Requests:', metrics.totalRequests);\nconsole.log('Total Cost:', metrics.totalCost);\nconsole.log('Error Rate:', metrics.errorRate);\n\n// Get provider-specific metrics\nconst providerMetrics = orchestrator.getMetrics().getProviderMetrics('groq-1');\nconsole.log('Provider Requests:', providerMetrics?.totalRequests);\nconsole.log('Provider Cost:', providerMetrics?.totalCost);\nconsole.log('Success Rate:', providerMetrics?.successfulRequests / providerMetrics?.totalRequests);\n\n// Get strategy metrics\nconst strategyMetrics = orchestrator.getMetrics().getStrategyMetrics();\nconsole.log('Selections by Provider:', strategyMetrics.selectionsByProvider);\nconsole.log('Average Selection Time:', strategyMetrics.averageSelectionTime);\n```\n\n### Available Metrics\n\n- **Provider Metrics**: Requests, success/failure rates, latency, token usage, costs\n- **Strategy Metrics**: Selection counts, distribution, selection time\n- **Overall Metrics**: Total requests, costs, error rates, requests per minute\n- **Request History**: Detailed history with filtering options\n\nSee `examples/metrics.ts` for a complete example.\n\n## Extensibility\n\n### Adding a New Provider\n\n```typescript\nimport { BaseProvider } from '@ai-orchestration/core';\nimport type {\n  ChatMessage,\n  ChatOptions,\n  ChatResponse,\n  ChatChunk,\n  ProviderHealth,\n  ProviderMetadata,\n} from '@ai-orchestration/core';\n\nexport class CustomProvider extends BaseProvider {\n  readonly id: string;\n  readonly metadata: ProviderMetadata;\n  \n  constructor(config: CustomConfig) {\n    super();\n    this.id = config.id;\n    this.metadata = {\n      id: this.id,\n      name: 'Custom Provider',\n    };\n  }\n  \n  async checkHealth(): Promise<ProviderHealth> {\n    // Implement health check\n  }\n  \n  async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse> {\n    // Implement chat\n  }\n  \n  async chatStream(messages: ChatMessage[], options?: ChatOptions): Promise<ReadableStream<ChatChunk>> {\n    // Implement streaming\n  }\n  \n  protected formatMessages(messages: ChatMessage[]): unknown {\n    // Convert standard format to provider format\n  }\n  \n  protected parseResponse(response: unknown): ChatResponse {\n    // Convert provider response to standard format\n  }\n  \n  protected parseStream(stream: ReadableStream<unknown>): ReadableStream<ChatChunk> {\n    // Convert provider stream to standard format\n  }\n}\n```\n\n### Adding a New Strategy\n\n```typescript\nimport { BaseStrategy } from '@ai-orchestration/core';\nimport type { AIService, SelectionContext } from '@ai-orchestration/core';\n\nexport class CustomStrategy extends BaseStrategy {\n  async select(\n    providers: AIService[],\n    context?: SelectionContext\n  ): Promise<AIService | null> {\n    // Implement selection logic\n    return providers[0];\n  }\n  \n  update?(provider: AIService, success: boolean, metadata?: unknown): void {\n    // Optional: update internal state\n  }\n}\n```\n\n## Architecture\n\n```\nsrc/\n├── core/\n│   ├── interfaces.ts      # Main interfaces\n│   ├── types.ts           # Shared types\n│   ├── orchestrator.ts    # Orchestrator core\n│   └── errors.ts          # Custom error classes\n├── providers/\n│   ├── base.ts            # Base class for providers\n│   ├── groq.ts\n│   ├── openrouter.ts\n│   ├── gemini.ts\n│   ├── cerebras.ts\n│   └── local.ts\n├── strategies/\n│   ├── base.ts            # Base class for strategies\n│   ├── round-robin.ts\n│   ├── priority.ts\n│   ├── fallback.ts\n│   ├── weighted.ts\n│   └── health-aware.ts\n├── factory/\n│   └── index.ts           # Factory for declarative creation\n└── index.ts               # Main entry point\n```\n\n## Design Principles\n\n- **Single Responsibility**: Each class has a single responsibility\n- **Open/Closed Principle**: Extensible without modifying the core\n- **Plugin-based Architecture**: Providers and strategies are plugins\n- **Composition over Inheritance**: Preference for composition\n- **Configuration over Hard-coding**: Declarative configuration\n- **Declarative APIs**: Simple and expressive APIs\n\n## Development\n\n### Setup\n\n```bash\n# Install dependencies\nnpm install\n\n# Build\nnpm run build\n\n# Development with watch\nnpm run dev\n\n# Type checking\nnpm run typecheck\n\n# Tests\nnpm test\n```\n\n### Testing\n\n#### Quick Test (No API Keys Required)\n\nTest the framework with mock providers without needing API keys:\n\n```bash\nnpm run test:mock\n```\n\n#### Test with Real Providers\n\n**Note**: The `@ai-orchestration/core` package does not include `.env` files. Environment variables must be configured in your project or in the examples.\n\n1. **Set environment variables:**\n\n```bash\nexport GROQ_API_KEY=\"your-key\"\nexport OPENROUTER_API_KEY=\"your-key\"\nexport GEMINI_API_KEY=\"your-key\"\nexport CEREBRAS_API_KEY=\"your-key\"\n```\n\n2. **Run tests:**\n\n```bash\nnpm run test:local\n```\n\n### Local Development in Other Projects\n\n#### Method 1: npm link (Recommended)\n\n```bash\n# In this directory (ai-orchestration)\nnpm run link\n\n# In your other project\nnpm link @ai-orchestration/core\n```\n\nNow you can import normally:\n```typescript\nimport { createOrchestrator } from '@ai-orchestration/core';\n```\n\n#### Method 2: npm pack\n\n```bash\n# In this directory\nnpm run pack:local\n\n# In your other project\nnpm install ./@ai-orchestration-core-0.1.0.tgz\n```\n\n## Requirements\n\n- **Node.js**: >= 18.0.0 (for native ReadableStream and test runner)\n- **TypeScript**: 5.3+ (already included in devDependencies)\n\n## Examples\n\nSee the `examples/` directory for more code examples:\n- `basic.ts` - Basic usage example\n- `strategies.ts` - Strategy examples\n- `test-local.ts` - Testing with real providers\n- `test-mock.ts` - Testing with mock providers\n- `chat-app/` - Full chat application example\n\n## License\n\nMIT\n\n## Contributing\n\nSee [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for guidelines on contributing to this project.\n\n## Related Documentation\n\n- [ARCHITECTURE.md](./docs/ARCHITECTURE.md) - Detailed architecture documentation\n- [CHANGELOG.md](./docs/CHANGELOG.md) - Version history and changes","readmeFilename":"README.md"}