@ai-orchestration/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +27 -0
- package/README.md +516 -0
- package/dist/core/errors.d.ts +21 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +38 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/interfaces.d.ts +87 -0
- package/dist/core/interfaces.d.ts.map +1 -0
- package/dist/core/interfaces.js +5 -0
- package/dist/core/interfaces.js.map +1 -0
- package/dist/core/orchestrator.d.ts +55 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +147 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/types.d.ts +72 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/factory/index.d.ts +14 -0
- package/dist/factory/index.d.ts.map +1 -0
- package/dist/factory/index.js +184 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/base.d.ts +30 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +31 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/cerebras.d.ts +26 -0
- package/dist/providers/cerebras.d.ts.map +1 -0
- package/dist/providers/cerebras.js +190 -0
- package/dist/providers/cerebras.js.map +1 -0
- package/dist/providers/gemini.d.ts +26 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +181 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/groq.d.ts +26 -0
- package/dist/providers/groq.d.ts.map +1 -0
- package/dist/providers/groq.js +225 -0
- package/dist/providers/groq.js.map +1 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +10 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/local.d.ts +27 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +198 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/providers/openrouter.d.ts +26 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +172 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/strategies/base.d.ts +16 -0
- package/dist/strategies/base.d.ts.map +1 -0
- package/dist/strategies/base.js +21 -0
- package/dist/strategies/base.js.map +1 -0
- package/dist/strategies/fallback.d.ts +14 -0
- package/dist/strategies/fallback.d.ts.map +1 -0
- package/dist/strategies/fallback.js +29 -0
- package/dist/strategies/fallback.js.map +1 -0
- package/dist/strategies/health-aware.d.ts +20 -0
- package/dist/strategies/health-aware.d.ts.map +1 -0
- package/dist/strategies/health-aware.js +106 -0
- package/dist/strategies/health-aware.js.map +1 -0
- package/dist/strategies/index.d.ts +14 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +10 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/priority.d.ts +18 -0
- package/dist/strategies/priority.d.ts.map +1 -0
- package/dist/strategies/priority.js +35 -0
- package/dist/strategies/priority.js.map +1 -0
- package/dist/strategies/round-robin.d.ts +10 -0
- package/dist/strategies/round-robin.d.ts.map +1 -0
- package/dist/strategies/round-robin.js +21 -0
- package/dist/strategies/round-robin.js.map +1 -0
- package/dist/strategies/weighted.d.ts +20 -0
- package/dist/strategies/weighted.d.ts.map +1 -0
- package/dist/strategies/weighted.js +58 -0
- package/dist/strategies/weighted.js.map +1 -0
- package/docs/ARCHITECTURE.md +126 -0
- package/docs/CHANGELOG.md +30 -0
- package/docs/CONTRIBUTING.md +198 -0
- package/examples/basic.ts +58 -0
- package/examples/chat-app/README.md +146 -0
- package/examples/chat-app/config.json +34 -0
- package/examples/chat-app/index.ts +330 -0
- package/examples/chat-app/package-lock.json +570 -0
- package/examples/chat-app/package.json +20 -0
- package/examples/config.example.json +42 -0
- package/examples/strategies.ts +112 -0
- package/examples/test-local.ts +150 -0
- package/examples/test-mock.ts +172 -0
- package/package/.eslintrc.json +27 -0
- package/package/CHANGELOG.md +31 -0
- package/package/CONTRIBUTING.md +156 -0
- package/package/PUBLISHING.md +213 -0
- package/package/README.md +515 -0
- package/package/dist/core/errors.d.ts +21 -0
- package/package/dist/core/errors.d.ts.map +1 -0
- package/package/dist/core/errors.js +38 -0
- package/package/dist/core/errors.js.map +1 -0
- package/package/dist/core/interfaces.d.ts +87 -0
- package/package/dist/core/interfaces.d.ts.map +1 -0
- package/package/dist/core/interfaces.js +5 -0
- package/package/dist/core/interfaces.js.map +1 -0
- package/package/dist/core/orchestrator.d.ts +55 -0
- package/package/dist/core/orchestrator.d.ts.map +1 -0
- package/package/dist/core/orchestrator.js +147 -0
- package/package/dist/core/orchestrator.js.map +1 -0
- package/package/dist/core/types.d.ts +72 -0
- package/package/dist/core/types.d.ts.map +1 -0
- package/package/dist/core/types.js +5 -0
- package/package/dist/core/types.js.map +1 -0
- package/package/dist/factory/index.d.ts +14 -0
- package/package/dist/factory/index.d.ts.map +1 -0
- package/package/dist/factory/index.js +184 -0
- package/package/dist/factory/index.js.map +1 -0
- package/package/dist/index.d.ts +14 -0
- package/package/dist/index.d.ts.map +1 -0
- package/package/dist/index.js +15 -0
- package/package/dist/index.js.map +1 -0
- package/package/dist/providers/base.d.ts +30 -0
- package/package/dist/providers/base.d.ts.map +1 -0
- package/package/dist/providers/base.js +31 -0
- package/package/dist/providers/base.js.map +1 -0
- package/package/dist/providers/cerebras.d.ts +26 -0
- package/package/dist/providers/cerebras.d.ts.map +1 -0
- package/package/dist/providers/cerebras.js +190 -0
- package/package/dist/providers/cerebras.js.map +1 -0
- package/package/dist/providers/gemini.d.ts +26 -0
- package/package/dist/providers/gemini.d.ts.map +1 -0
- package/package/dist/providers/gemini.js +181 -0
- package/package/dist/providers/gemini.js.map +1 -0
- package/package/dist/providers/groq.d.ts +26 -0
- package/package/dist/providers/groq.d.ts.map +1 -0
- package/package/dist/providers/groq.js +225 -0
- package/package/dist/providers/groq.js.map +1 -0
- package/package/dist/providers/index.d.ts +15 -0
- package/package/dist/providers/index.d.ts.map +1 -0
- package/package/dist/providers/index.js +10 -0
- package/package/dist/providers/index.js.map +1 -0
- package/package/dist/providers/local.d.ts +27 -0
- package/package/dist/providers/local.d.ts.map +1 -0
- package/package/dist/providers/local.js +198 -0
- package/package/dist/providers/local.js.map +1 -0
- package/package/dist/providers/openrouter.d.ts +26 -0
- package/package/dist/providers/openrouter.d.ts.map +1 -0
- package/package/dist/providers/openrouter.js +172 -0
- package/package/dist/providers/openrouter.js.map +1 -0
- package/package/dist/strategies/base.d.ts +16 -0
- package/package/dist/strategies/base.d.ts.map +1 -0
- package/package/dist/strategies/base.js +21 -0
- package/package/dist/strategies/base.js.map +1 -0
- package/package/dist/strategies/fallback.d.ts +14 -0
- package/package/dist/strategies/fallback.d.ts.map +1 -0
- package/package/dist/strategies/fallback.js +29 -0
- package/package/dist/strategies/fallback.js.map +1 -0
- package/package/dist/strategies/health-aware.d.ts +20 -0
- package/package/dist/strategies/health-aware.d.ts.map +1 -0
- package/package/dist/strategies/health-aware.js +106 -0
- package/package/dist/strategies/health-aware.js.map +1 -0
- package/package/dist/strategies/index.d.ts +14 -0
- package/package/dist/strategies/index.d.ts.map +1 -0
- package/package/dist/strategies/index.js +10 -0
- package/package/dist/strategies/index.js.map +1 -0
- package/package/dist/strategies/priority.d.ts +18 -0
- package/package/dist/strategies/priority.d.ts.map +1 -0
- package/package/dist/strategies/priority.js +35 -0
- package/package/dist/strategies/priority.js.map +1 -0
- package/package/dist/strategies/round-robin.d.ts +10 -0
- package/package/dist/strategies/round-robin.d.ts.map +1 -0
- package/package/dist/strategies/round-robin.js +21 -0
- package/package/dist/strategies/round-robin.js.map +1 -0
- package/package/dist/strategies/weighted.d.ts +20 -0
- package/package/dist/strategies/weighted.d.ts.map +1 -0
- package/package/dist/strategies/weighted.js +58 -0
- package/package/dist/strategies/weighted.js.map +1 -0
- package/package/docs/ARCHITECTURE.md +127 -0
- package/package/examples/basic.ts +58 -0
- package/package/examples/chat-app/README.md +146 -0
- package/package/examples/chat-app/config.json +34 -0
- package/package/examples/chat-app/index.ts +330 -0
- package/package/examples/chat-app/package-lock.json +570 -0
- package/package/examples/chat-app/package.json +20 -0
- package/package/examples/config.example.json +42 -0
- package/package/examples/strategies.ts +112 -0
- package/package/examples/test-local.ts +150 -0
- package/package/examples/test-mock.ts +172 -0
- package/package/package.json +62 -0
- package/package/scripts/check-types.ts +15 -0
- package/package/scripts/link.sh +30 -0
- package/package/scripts/pack.sh +36 -0
- package/package.json +62 -0
- package/scripts/check-types.ts +15 -0
- package/scripts/link.sh +30 -0
- package/scripts/pack.sh +36 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weighted strategy: selects providers based on weights (for load balancing or cost-aware selection)
|
|
3
|
+
*/
|
|
4
|
+
import { BaseStrategy } from './base.js';
|
|
5
|
+
export class WeightedStrategy extends BaseStrategy {
|
|
6
|
+
weights = new Map();
|
|
7
|
+
costAware;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
super();
|
|
10
|
+
this.costAware = config?.costAware ?? false;
|
|
11
|
+
if (config?.weights) {
|
|
12
|
+
Object.entries(config.weights).forEach(([id, weight]) => {
|
|
13
|
+
this.weights.set(id, weight);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async select(providers, context) {
|
|
18
|
+
const available = this.filterAttempted(providers, context);
|
|
19
|
+
if (available.length === 0) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
// Calculate effective weights
|
|
23
|
+
const weightedProviders = available.map((provider) => {
|
|
24
|
+
let weight = this.weights.get(provider.id) ?? 1.0;
|
|
25
|
+
// Adjust weight based on cost if cost-aware
|
|
26
|
+
if (this.costAware && provider.metadata.costPerToken) {
|
|
27
|
+
const avgCost = (provider.metadata.costPerToken.prompt +
|
|
28
|
+
provider.metadata.costPerToken.completion) /
|
|
29
|
+
2;
|
|
30
|
+
// Lower cost = higher weight (inverse relationship)
|
|
31
|
+
weight = weight / (avgCost + 0.0001); // Add small epsilon to avoid division by zero
|
|
32
|
+
}
|
|
33
|
+
return { provider, weight };
|
|
34
|
+
});
|
|
35
|
+
// Calculate total weight
|
|
36
|
+
const totalWeight = weightedProviders.reduce((sum, wp) => sum + wp.weight, 0);
|
|
37
|
+
if (totalWeight === 0) {
|
|
38
|
+
return available[0]; // Fallback to first available
|
|
39
|
+
}
|
|
40
|
+
// Select using weighted random
|
|
41
|
+
let random = Math.random() * totalWeight;
|
|
42
|
+
for (const { provider, weight } of weightedProviders) {
|
|
43
|
+
random -= weight;
|
|
44
|
+
if (random <= 0) {
|
|
45
|
+
return provider;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Fallback (shouldn't reach here)
|
|
49
|
+
return available[0];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set weight for a provider
|
|
53
|
+
*/
|
|
54
|
+
setWeight(providerId, weight) {
|
|
55
|
+
this.weights.set(providerId, weight);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=weighted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weighted.js","sourceRoot":"","sources":["../../src/strategies/weighted.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAQzC,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IACxC,OAAO,GAAwB,IAAI,GAAG,EAAE,CAAC;IACzC,SAAS,CAAU;IAE3B,YAAY,MAA+B;QACzC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC;QAE5C,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;gBACtD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CACV,SAAsB,EACtB,OAA0B;QAE1B,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC3D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,8BAA8B;QAC9B,MAAM,iBAAiB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YACnD,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC;YAElD,4CAA4C;YAC5C,IAAI,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACrD,MAAM,OAAO,GACX,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM;oBACpC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,UAAU,CAAC;oBAC5C,CAAC,CAAC;gBACJ,oDAAoD;gBACpD,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,8CAA8C;YACtF,CAAC;YAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,yBAAyB;QACzB,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAC1C,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,MAAM,EAC5B,CAAC,CACF,CAAC;QAEF,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,8BAA8B;QACrD,CAAC;QAED,+BAA+B;QAC/B,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC;QACzC,KAAK,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,iBAAiB,EAAE,CAAC;YACrD,MAAM,IAAI,MAAM,CAAC;YACjB,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;gBAChB,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,UAAkB,EAAE,MAAc;QAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Framework Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The framework is designed following SOLID principles and plugin-based architecture, allowing extensibility without modifying core code.
|
|
6
|
+
|
|
7
|
+
## Main Components
|
|
8
|
+
|
|
9
|
+
### Core (`src/core/`)
|
|
10
|
+
|
|
11
|
+
#### `interfaces.ts`
|
|
12
|
+
Defines fundamental interfaces:
|
|
13
|
+
- `AIService`: Contract that all providers must implement
|
|
14
|
+
- `SelectionStrategy`: Contract for selection strategies
|
|
15
|
+
- `OrchestratorConfig`: Orchestrator configuration
|
|
16
|
+
- Configuration types for providers and strategies
|
|
17
|
+
|
|
18
|
+
#### `types.ts`
|
|
19
|
+
Shared types:
|
|
20
|
+
- `ChatMessage`: Message in a conversation
|
|
21
|
+
- `ChatOptions`: Options for chat completion
|
|
22
|
+
- `ChatResponse`: Non-streaming response
|
|
23
|
+
- `ChatChunk`: Streaming chunk
|
|
24
|
+
- `ProviderHealth`: Provider health status
|
|
25
|
+
- `ProviderMetadata`: Provider metadata
|
|
26
|
+
|
|
27
|
+
#### `orchestrator.ts`
|
|
28
|
+
Framework core:
|
|
29
|
+
- `Orchestrator`: Main class that manages providers and strategies
|
|
30
|
+
- Provider registration and management
|
|
31
|
+
- Automatic provider selection
|
|
32
|
+
- Automatic fallback on error
|
|
33
|
+
- Periodic health checks
|
|
34
|
+
|
|
35
|
+
### Providers (`src/providers/`)
|
|
36
|
+
|
|
37
|
+
Each provider extends `BaseProvider` and implements:
|
|
38
|
+
- `checkHealth()`: Health verification
|
|
39
|
+
- `chat()`: Chat completion (non-streaming)
|
|
40
|
+
- `chatStream()`: Chat completion (streaming)
|
|
41
|
+
- `formatMessages()`: Conversion from standard format to provider format
|
|
42
|
+
- `parseResponse()`: Conversion from provider response to standard format
|
|
43
|
+
- `parseStream()`: Conversion from provider stream to standard format
|
|
44
|
+
|
|
45
|
+
**Implemented providers:**
|
|
46
|
+
- `GroqProvider`: Groq API integration
|
|
47
|
+
- `OpenRouterProvider`: OpenRouter integration
|
|
48
|
+
- `GeminiProvider`: Google Gemini integration
|
|
49
|
+
- `CerebrasProvider`: Cerebras Inference API integration
|
|
50
|
+
- `LocalProvider`: For local models (OpenAI-compatible API)
|
|
51
|
+
|
|
52
|
+
### Strategies (`src/strategies/`)
|
|
53
|
+
|
|
54
|
+
Each strategy extends `BaseStrategy` and implements:
|
|
55
|
+
- `select()`: Provider selection logic
|
|
56
|
+
- `update()` (optional): Internal state update
|
|
57
|
+
|
|
58
|
+
**Implemented strategies:**
|
|
59
|
+
- `RoundRobinStrategy`: Cycles through providers
|
|
60
|
+
- `PriorityStrategy`: Selects by priority
|
|
61
|
+
- `FallbackStrategy`: Tries in order until success
|
|
62
|
+
- `WeightedStrategy`: Selection based on weights (load balancing)
|
|
63
|
+
- `HealthAwareStrategy`: Selection based on health metrics
|
|
64
|
+
|
|
65
|
+
### Factory (`src/factory/`)
|
|
66
|
+
|
|
67
|
+
- `createOrchestrator()`: Creates an orchestrator from declarative configuration
|
|
68
|
+
- `createProvider()`: Creates provider instances from configuration
|
|
69
|
+
- `createStrategy()`: Creates strategy instances from configuration
|
|
70
|
+
- `isValidOrchestratorConfig()`: Validates configuration
|
|
71
|
+
|
|
72
|
+
## Data Flow
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
User
|
|
76
|
+
↓
|
|
77
|
+
Orchestrator.chat() / chatStream()
|
|
78
|
+
↓
|
|
79
|
+
Strategy.select() → Selects provider
|
|
80
|
+
↓
|
|
81
|
+
Provider.chat() / chatStream()
|
|
82
|
+
↓
|
|
83
|
+
Provider formats messages → formatMessages()
|
|
84
|
+
↓
|
|
85
|
+
Provider API call
|
|
86
|
+
↓
|
|
87
|
+
Provider parses response → parseResponse() / parseStream()
|
|
88
|
+
↓
|
|
89
|
+
Standard response to user
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Extensibility
|
|
93
|
+
|
|
94
|
+
### Adding a New Provider
|
|
95
|
+
|
|
96
|
+
1. Create class extending `BaseProvider`
|
|
97
|
+
2. Implement required methods
|
|
98
|
+
3. Register in `factory/index.ts` (`createProvider` method)
|
|
99
|
+
|
|
100
|
+
### Adding a New Strategy
|
|
101
|
+
|
|
102
|
+
1. Create class extending `BaseStrategy`
|
|
103
|
+
2. Implement `select()` method
|
|
104
|
+
3. Optionally implement `update()`
|
|
105
|
+
4. Register in `factory/index.ts` (`createStrategy` method)
|
|
106
|
+
|
|
107
|
+
## Applied Design Principles
|
|
108
|
+
|
|
109
|
+
1. **Single Responsibility**: Each class has a single responsibility
|
|
110
|
+
2. **Open/Closed**: Open for extension, closed for modification
|
|
111
|
+
3. **Liskov Substitution**: Providers and strategies are interchangeable
|
|
112
|
+
4. **Interface Segregation**: Specific and cohesive interfaces
|
|
113
|
+
5. **Dependency Inversion**: Dependencies on abstractions, not implementations
|
|
114
|
+
|
|
115
|
+
## Compatibility
|
|
116
|
+
|
|
117
|
+
- **Node.js**: >= 18.0.0 (uses native ReadableStream)
|
|
118
|
+
- **TypeScript**: 5.3+
|
|
119
|
+
- **ES Modules**: Required
|
|
120
|
+
|
|
121
|
+
## Performance Considerations
|
|
122
|
+
|
|
123
|
+
- Health checks can run in parallel
|
|
124
|
+
- Automatic fallback avoids unnecessary waits
|
|
125
|
+
- Native streaming for long responses
|
|
126
|
+
- Strategies can cache metrics for better performance
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-12-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Complete AI orchestration framework
|
|
12
|
+
- Support for multiple providers: Groq, OpenRouter, Gemini, Cerebras, Local
|
|
13
|
+
- 5 selection strategies: Round-Robin, Priority, Fallback, Weighted, Health-Aware
|
|
14
|
+
- Native streaming with ReadableStream
|
|
15
|
+
- Automatic health checks with latency metrics
|
|
16
|
+
- Factory for declarative creation
|
|
17
|
+
- Custom error handling
|
|
18
|
+
- Configuration validation
|
|
19
|
+
- Complete documentation (README, ARCHITECTURE, CONTRIBUTING)
|
|
20
|
+
- Usage examples
|
|
21
|
+
- Basic tests
|
|
22
|
+
- Node.js compatibility
|
|
23
|
+
|
|
24
|
+
### Main Features
|
|
25
|
+
- Plugin-based architecture (extensible without modifying core)
|
|
26
|
+
- Declarative and programmatic API
|
|
27
|
+
- Type-safe with TypeScript
|
|
28
|
+
- Automatic fallback between providers
|
|
29
|
+
- Support for cost-aware selection
|
|
30
|
+
- Health-aware selection with real-time metrics
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Contributing Guide
|
|
2
|
+
|
|
3
|
+
## Project Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
src/
|
|
7
|
+
├── core/ # Framework core (interfaces, types, orchestrator)
|
|
8
|
+
├── providers/ # Provider implementations
|
|
9
|
+
├── strategies/ # Selection strategies
|
|
10
|
+
├── factory/ # Factory for declarative creation
|
|
11
|
+
└── index.ts # Main entry point
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Adding a New Provider
|
|
15
|
+
|
|
16
|
+
1. **Create the provider file** in `src/providers/`:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { BaseProvider } from './base.js';
|
|
20
|
+
import type {
|
|
21
|
+
ChatMessage,
|
|
22
|
+
ChatOptions,
|
|
23
|
+
ChatResponse,
|
|
24
|
+
ChatChunk,
|
|
25
|
+
ProviderHealth,
|
|
26
|
+
ProviderMetadata,
|
|
27
|
+
} from '../core/types.js';
|
|
28
|
+
|
|
29
|
+
export interface CustomProviderConfig {
|
|
30
|
+
id: string;
|
|
31
|
+
apiKey: string;
|
|
32
|
+
// ... other provider-specific fields
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class CustomProvider extends BaseProvider {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly metadata: ProviderMetadata;
|
|
38
|
+
|
|
39
|
+
constructor(config: CustomProviderConfig) {
|
|
40
|
+
super();
|
|
41
|
+
// Initialization
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async checkHealth(): Promise<ProviderHealth> {
|
|
45
|
+
// Implement health check
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse> {
|
|
49
|
+
// Implement chat
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async chatStream(messages: ChatMessage[], options?: ChatOptions): Promise<ReadableStream<ChatChunk>> {
|
|
53
|
+
// Implement streaming
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected formatMessages(messages: ChatMessage[]): unknown {
|
|
57
|
+
// Convert standard format to provider format
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected parseResponse(response: unknown): ChatResponse {
|
|
61
|
+
// Convert response to standard format
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected parseStream(stream: ReadableStream<unknown>): ReadableStream<ChatChunk> {
|
|
65
|
+
// Convert stream to standard format
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
2. **Export in `src/providers/index.ts`**:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
export { CustomProvider } from './custom.js';
|
|
74
|
+
export type { CustomProviderConfig } from './custom.js';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
3. **Register in `src/factory/index.ts`**:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { CustomProvider, type CustomProviderConfig } from '../providers/index.js';
|
|
81
|
+
|
|
82
|
+
// In the createProvider function:
|
|
83
|
+
case 'custom':
|
|
84
|
+
return new CustomProvider({
|
|
85
|
+
id,
|
|
86
|
+
...(rest as CustomProviderConfig),
|
|
87
|
+
} as CustomProviderConfig);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Adding a New Strategy
|
|
91
|
+
|
|
92
|
+
1. **Create the strategy file** in `src/strategies/`:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { BaseStrategy } from './base.js';
|
|
96
|
+
import type { AIService, SelectionContext } from '../core/interfaces.js';
|
|
97
|
+
|
|
98
|
+
export interface CustomStrategyConfig {
|
|
99
|
+
// Strategy-specific configuration
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class CustomStrategy extends BaseStrategy {
|
|
103
|
+
constructor(config?: CustomStrategyConfig) {
|
|
104
|
+
super();
|
|
105
|
+
// Initialization
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async select(
|
|
109
|
+
providers: AIService[],
|
|
110
|
+
context?: SelectionContext
|
|
111
|
+
): Promise<AIService | null> {
|
|
112
|
+
// Implement selection logic
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
update?(provider: AIService, success: boolean, metadata?: unknown): void {
|
|
116
|
+
// Optional: update internal state
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
2. **Export in `src/strategies/index.ts`**
|
|
122
|
+
|
|
123
|
+
3. **Register in `src/factory/index.ts`**
|
|
124
|
+
|
|
125
|
+
## Code Conventions
|
|
126
|
+
|
|
127
|
+
- **Strict TypeScript**: Use explicit types
|
|
128
|
+
- **Descriptive names**: Variables and functions with clear names
|
|
129
|
+
- **Documentation**: JSDoc for public functions
|
|
130
|
+
- **Error handling**: Use custom error classes
|
|
131
|
+
- **Tests**: Add tests for new functionality
|
|
132
|
+
|
|
133
|
+
## Testing
|
|
134
|
+
|
|
135
|
+
Tests are in `tests/`. Use Node.js test runner:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm test
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
For local testing with mock providers:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm run test:mock
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
For testing with real providers:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm run test:local
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Versioning
|
|
154
|
+
|
|
155
|
+
Follow [Semantic Versioning](https://semver.org/):
|
|
156
|
+
- **MAJOR**: Incompatible API changes
|
|
157
|
+
- **MINOR**: New backward-compatible functionality
|
|
158
|
+
- **PATCH**: Backward-compatible bug fixes
|
|
159
|
+
|
|
160
|
+
## Pull Requests
|
|
161
|
+
|
|
162
|
+
1. Create a branch from `main`
|
|
163
|
+
2. Implement changes
|
|
164
|
+
3. Add tests
|
|
165
|
+
4. Update documentation if necessary
|
|
166
|
+
5. Ensure all tests pass
|
|
167
|
+
6. Create PR with clear description
|
|
168
|
+
|
|
169
|
+
## Development Setup
|
|
170
|
+
|
|
171
|
+
1. **Clone the repository**
|
|
172
|
+
2. **Install dependencies**:
|
|
173
|
+
```bash
|
|
174
|
+
npm install
|
|
175
|
+
```
|
|
176
|
+
3. **Build the project**:
|
|
177
|
+
```bash
|
|
178
|
+
npm run build
|
|
179
|
+
```
|
|
180
|
+
4. **Run tests**:
|
|
181
|
+
```bash
|
|
182
|
+
npm test
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Code Style
|
|
186
|
+
|
|
187
|
+
- Use TypeScript strict mode
|
|
188
|
+
- Follow existing code style
|
|
189
|
+
- Use meaningful variable and function names
|
|
190
|
+
- Add comments for complex logic
|
|
191
|
+
- Keep functions focused and small
|
|
192
|
+
|
|
193
|
+
## Commit Messages
|
|
194
|
+
|
|
195
|
+
Use clear, descriptive commit messages:
|
|
196
|
+
- Use imperative mood ("Add feature" not "Added feature")
|
|
197
|
+
- Reference issues when applicable
|
|
198
|
+
- Keep messages concise but informative
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic usage example
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createOrchestrator } from '../src/index.js';
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
// Create orchestrator with declarative config
|
|
9
|
+
const orchestrator = createOrchestrator({
|
|
10
|
+
providers: [
|
|
11
|
+
{
|
|
12
|
+
id: 'groq-1',
|
|
13
|
+
type: 'groq',
|
|
14
|
+
apiKey: process.env.GROQ_API_KEY || '',
|
|
15
|
+
model: 'llama-3.3-70b-versatile', // Updated: llama-3.1-70b-versatile was decommissioned
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'openrouter-1',
|
|
19
|
+
type: 'openrouter',
|
|
20
|
+
apiKey: process.env.OPENROUTER_API_KEY || '',
|
|
21
|
+
model: 'openai/gpt-3.5-turbo',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
strategy: {
|
|
25
|
+
type: 'round-robin',
|
|
26
|
+
},
|
|
27
|
+
enableHealthChecks: true,
|
|
28
|
+
healthCheckInterval: 60000, // 60 seconds
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Simple chat
|
|
32
|
+
console.log('=== Simple Chat ===');
|
|
33
|
+
const response = await orchestrator.chat([
|
|
34
|
+
{ role: 'user', content: 'Say hello in one sentence' },
|
|
35
|
+
]);
|
|
36
|
+
console.log('Response:', response.content);
|
|
37
|
+
console.log('Usage:', response.usage);
|
|
38
|
+
|
|
39
|
+
// Streaming chat
|
|
40
|
+
console.log('\n=== Streaming Chat ===');
|
|
41
|
+
const stream = await orchestrator.chatStream([
|
|
42
|
+
{ role: 'user', content: 'Count from 1 to 5' },
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const reader = stream.getReader();
|
|
46
|
+
while (true) {
|
|
47
|
+
const { done, value } = await reader.read();
|
|
48
|
+
if (done) break;
|
|
49
|
+
process.stdout.write(value.content);
|
|
50
|
+
}
|
|
51
|
+
console.log('\n');
|
|
52
|
+
|
|
53
|
+
// Cleanup
|
|
54
|
+
orchestrator.dispose();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
main().catch(console.error);
|
|
58
|
+
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Chat App Example
|
|
2
|
+
|
|
3
|
+
A simple chat application to test `@ai-orchestration/core` using npm link.
|
|
4
|
+
|
|
5
|
+
## Quick Setup
|
|
6
|
+
|
|
7
|
+
### 1. Link the Package
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# In the ia-orchestration directory (from project root)
|
|
11
|
+
cd /path/to/ia-orchestration
|
|
12
|
+
npm run link
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Setup This Project
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# In this directory
|
|
19
|
+
cd examples/chat-app
|
|
20
|
+
npm install
|
|
21
|
+
npm link @ai-orchestration/core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 3. Configure Environment Variables
|
|
25
|
+
|
|
26
|
+
Create a `.env` file from the example:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Copy the example file
|
|
30
|
+
cp .env.example .env
|
|
31
|
+
|
|
32
|
+
# Edit .env with your real API keys
|
|
33
|
+
# GROQ_API_KEY=your-real-key-here
|
|
34
|
+
# OPENROUTER_API_KEY=your-real-key-here
|
|
35
|
+
# GEMINI_API_KEY=your-real-key-here
|
|
36
|
+
# CEREBRAS_API_KEY=your-real-key-here
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Important**: The `.env` file is in `.gitignore` and will not be committed to the repository.
|
|
40
|
+
|
|
41
|
+
**Note**: You only need to configure at least ONE API key for it to work.
|
|
42
|
+
|
|
43
|
+
### 4. (Optional) Customize Configuration
|
|
44
|
+
|
|
45
|
+
You can edit `config.json` to:
|
|
46
|
+
- Change default models
|
|
47
|
+
- Change initial strategy
|
|
48
|
+
- Adjust chat options (temperature, maxTokens)
|
|
49
|
+
- Add or remove providers
|
|
50
|
+
|
|
51
|
+
### 5. Run
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
The application allows you to:
|
|
60
|
+
- Chat with multiple AI providers
|
|
61
|
+
- Change strategy at runtime
|
|
62
|
+
- See which provider is being used
|
|
63
|
+
- View usage statistics
|
|
64
|
+
|
|
65
|
+
## Available Commands
|
|
66
|
+
|
|
67
|
+
- `/help` - Show help
|
|
68
|
+
- `/strategy <type>` - Change strategy (round-robin, priority, fallback)
|
|
69
|
+
- `/providers` - List available providers
|
|
70
|
+
- `/health` - Check provider health
|
|
71
|
+
- `/clear` - Clear conversation history
|
|
72
|
+
- `/exit` or `/quit` - Exit the application
|
|
73
|
+
|
|
74
|
+
## Example Session
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
🚀 Chat App - Example with @ai-orchestration/core
|
|
78
|
+
|
|
79
|
+
💡 Type /help to see available commands
|
|
80
|
+
|
|
81
|
+
🔧 Creating orchestrator...
|
|
82
|
+
✅ Orchestrator created with 2 provider(s)
|
|
83
|
+
|
|
84
|
+
💬 You: Hello!
|
|
85
|
+
🤔 Thinking...
|
|
86
|
+
✅ Response (1234ms):
|
|
87
|
+
|
|
88
|
+
Hello! How can I help you today?
|
|
89
|
+
|
|
90
|
+
💬 You: /providers
|
|
91
|
+
📋 Available providers:
|
|
92
|
+
1. groq-1 (Groq)
|
|
93
|
+
2. openrouter-1 (OpenRouter)
|
|
94
|
+
|
|
95
|
+
💬 You: /exit
|
|
96
|
+
👋 Goodbye!
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Verification
|
|
100
|
+
|
|
101
|
+
To verify everything is configured correctly:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Verify that the link works
|
|
105
|
+
npm list @ai-orchestration/core
|
|
106
|
+
|
|
107
|
+
# Should show:
|
|
108
|
+
# chat-app-example@1.0.0
|
|
109
|
+
# └── @ai-orchestration/core@0.1.0 -> /path/to/ia-orchestration
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
### Error: "Cannot find module '@ai-orchestration/core'"
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Verify link exists
|
|
118
|
+
npm list @ai-orchestration/core
|
|
119
|
+
|
|
120
|
+
# If it doesn't exist, re-link
|
|
121
|
+
npm link @ai-orchestration/core
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Error: "No providers configured"
|
|
125
|
+
|
|
126
|
+
- Verify that `.env` exists in `examples/chat-app/`
|
|
127
|
+
- Verify it has at least one API key configured
|
|
128
|
+
- Verify there are no spaces around `=` in `.env`
|
|
129
|
+
- Verify values are not the example ones (`your-*-api-key-here`)
|
|
130
|
+
|
|
131
|
+
### Error: "Module not found" or TypeScript errors
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Reinstall dependencies
|
|
135
|
+
rm -rf node_modules package-lock.json
|
|
136
|
+
npm install
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Changes in package not reflected
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# In the ia-orchestration directory (root)
|
|
143
|
+
npm run build
|
|
144
|
+
|
|
145
|
+
# Changes should be reflected automatically
|
|
146
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"providers": [
|
|
3
|
+
{
|
|
4
|
+
"id": "groq-1",
|
|
5
|
+
"type": "groq",
|
|
6
|
+
"envKey": "GROQ_API_KEY",
|
|
7
|
+
"model": "llama-3.3-70b-versatile"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "openrouter-1",
|
|
11
|
+
"type": "openrouter",
|
|
12
|
+
"envKey": "OPENROUTER_API_KEY",
|
|
13
|
+
"model": "openai/gpt-3.5-turbo"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "gemini-1",
|
|
17
|
+
"type": "gemini",
|
|
18
|
+
"envKey": "GEMINI_API_KEY",
|
|
19
|
+
"model": "gemini-pro"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "cerebras-1",
|
|
23
|
+
"type": "cerebras",
|
|
24
|
+
"envKey": "CEREBRAS_API_KEY",
|
|
25
|
+
"model": "llama-3.3-70b"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"defaultStrategy": "round-robin",
|
|
29
|
+
"chatOptions": {
|
|
30
|
+
"temperature": 0.7,
|
|
31
|
+
"maxTokens": 1000
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|