@astrive-ai/providers 1.0.1

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.
@@ -0,0 +1,21 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { IProvider, ProviderConfig, ProviderType, ChatRequest, ChatResponse, ChatChunk, ILogger, IEventEmitter } from '@astrive-ai/types';
3
+ export declare abstract class BaseProvider implements IProvider {
4
+ readonly name: string;
5
+ readonly type: ProviderType;
6
+ protected logger: ILogger;
7
+ protected events: IEventEmitter;
8
+ protected config: ProviderConfig;
9
+ constructor(name: string, type: ProviderType, logger: ILogger, events: IEventEmitter);
10
+ init(config: ProviderConfig): Promise<void>;
11
+ abstract chat(request: ChatRequest): Promise<ChatResponse>;
12
+ chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown>;
13
+ isAvailable(): boolean;
14
+ abstract getModels(): string[];
15
+ abstract supportsFeature(feature: string): boolean;
16
+ destroy(): Promise<void>;
17
+ protected buildHeaders(): Record<string, string>;
18
+ protected fetchJSON<T>(url: string, options: RequestInit): Promise<T>;
19
+ protected parseSSE(text: string): any[];
20
+ }
21
+ //# sourceMappingURL=base-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-provider.d.ts","sourceRoot":"","sources":["../src/base-provider.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,SAAS,EACT,OAAO,EACP,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B,8BAAsB,YAAa,YAAW,SAAS;aAInC,IAAI,EAAE,MAAM;aACZ,IAAI,EAAE,YAAY;IAClC,SAAS,CAAC,MAAM,EAAE,OAAO;IACzB,SAAS,CAAC,MAAM,EAAE,aAAa;IANjC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAM;gBAGpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,EACxB,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,aAAa;IAGpB,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;aAKxC,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAEnD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC;IAejF,WAAW,IAAI,OAAO;aAIb,SAAS,IAAI,MAAM,EAAE;aACrB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAE5C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrC,SAAS,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;cAUhC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAc3E,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE;CAkBxC"}
@@ -0,0 +1,81 @@
1
+ export class BaseProvider {
2
+ name;
3
+ type;
4
+ logger;
5
+ events;
6
+ config = {};
7
+ constructor(name, type, logger, events) {
8
+ this.name = name;
9
+ this.type = type;
10
+ this.logger = logger;
11
+ this.events = events;
12
+ }
13
+ async init(config) {
14
+ this.config = { ...this.config, ...config };
15
+ this.logger.debug(`Provider ${this.name} initialized with config.`);
16
+ }
17
+ async *chatStream(request) {
18
+ const response = await this.chat(request);
19
+ const content = response.content;
20
+ const chunkSize = 10;
21
+ for (let i = 0; i < content.length; i += chunkSize) {
22
+ const chunk = content.slice(i, i + chunkSize);
23
+ yield {
24
+ content: chunk,
25
+ done: i + chunkSize >= content.length,
26
+ toolCalls: i + chunkSize >= content.length ? response.toolCalls : undefined
27
+ };
28
+ }
29
+ }
30
+ isAvailable() {
31
+ return !!this.config.apiKey;
32
+ }
33
+ async destroy() {
34
+ this.config = {};
35
+ this.logger.debug(`Provider ${this.name} destroyed.`);
36
+ }
37
+ buildHeaders() {
38
+ const headers = {
39
+ 'Content-Type': 'application/json'
40
+ };
41
+ if (this.config.apiKey) {
42
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
43
+ }
44
+ return headers;
45
+ }
46
+ async fetchJSON(url, options) {
47
+ try {
48
+ const response = await fetch(url, options);
49
+ if (!response.ok) {
50
+ const errorText = await response.text();
51
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
52
+ }
53
+ return (await response.json());
54
+ }
55
+ catch (error) {
56
+ this.logger.error(`fetchJSON error from ${url}:`, error);
57
+ throw error;
58
+ }
59
+ }
60
+ parseSSE(text) {
61
+ const lines = text.split('\n');
62
+ const events = [];
63
+ for (const line of lines) {
64
+ if (line.startsWith('data: ')) {
65
+ const data = line.slice(6).trim();
66
+ if (data === '[DONE]')
67
+ continue;
68
+ if (data) {
69
+ try {
70
+ events.push(JSON.parse(data));
71
+ }
72
+ catch (e) {
73
+ this.logger.warn(`Failed to parse SSE line: ${line}`);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return events;
79
+ }
80
+ }
81
+ //# sourceMappingURL=base-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-provider.js","sourceRoot":"","sources":["../src/base-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ import { ChatRequest, ChatResponse, ChatChunk, ILogger, IEventEmitter } from '@astrive-ai/types';
3
+ export declare class GroqProvider extends BaseProvider {
4
+ private baseUrl;
5
+ private models;
6
+ constructor(logger: ILogger, events: IEventEmitter);
7
+ chat(request: ChatRequest): Promise<ChatResponse>;
8
+ chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown>;
9
+ getModels(): string[];
10
+ supportsFeature(feature: string): boolean;
11
+ }
12
+ //# sourceMappingURL=groq-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groq-provider.d.ts","sourceRoot":"","sources":["../src/groq-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjG,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,MAAM,CAMZ;gBAEU,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa;IAIrC,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAmChD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC;IAsDjF,SAAS,IAAI,MAAM,EAAE;IAIrB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAIjD"}
@@ -0,0 +1,102 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ export class GroqProvider extends BaseProvider {
3
+ baseUrl = 'https://api.groq.com/openai/v1';
4
+ models = [
5
+ 'llama-3.1-8b-instant',
6
+ 'llama-3.3-70b-versatile',
7
+ 'llama-3.1-70b-versatile',
8
+ 'mixtral-8x7b-32768',
9
+ 'gemma2-9b-it'
10
+ ];
11
+ constructor(logger, events) {
12
+ super('groq', 'official', logger, events);
13
+ }
14
+ async chat(request) {
15
+ const url = `${this.baseUrl}/chat/completions`;
16
+ const payload = {
17
+ messages: request.messages,
18
+ model: request.model || this.models[0],
19
+ temperature: request.temperature,
20
+ max_tokens: request.maxTokens,
21
+ tools: request.tools
22
+ };
23
+ const data = await this.fetchJSON(url, {
24
+ method: 'POST',
25
+ headers: this.buildHeaders(),
26
+ body: JSON.stringify(payload)
27
+ });
28
+ return {
29
+ id: data.id,
30
+ content: data.choices[0].message.content || '',
31
+ role: 'assistant',
32
+ toolCalls: data.choices[0].message.tool_calls?.map((tc) => ({
33
+ id: tc.id,
34
+ name: tc.function.name,
35
+ arguments: typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments
36
+ })),
37
+ usage: data.usage ? {
38
+ promptTokens: data.usage.prompt_tokens,
39
+ completionTokens: data.usage.completion_tokens,
40
+ totalTokens: data.usage.total_tokens
41
+ } : undefined,
42
+ model: data.model,
43
+ finishReason: data.choices[0].finish_reason || 'stop'
44
+ };
45
+ }
46
+ async *chatStream(request) {
47
+ const url = `${this.baseUrl}/chat/completions`;
48
+ const payload = {
49
+ messages: request.messages,
50
+ model: request.model || this.models[0],
51
+ temperature: request.temperature,
52
+ max_tokens: request.maxTokens,
53
+ tools: request.tools,
54
+ stream: true
55
+ };
56
+ const response = await fetch(url, {
57
+ method: 'POST',
58
+ headers: this.buildHeaders(),
59
+ body: JSON.stringify(payload)
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
63
+ }
64
+ if (!response.body)
65
+ throw new Error('No response body');
66
+ const reader = response.body.getReader();
67
+ const decoder = new TextDecoder('utf-8');
68
+ let buffer = '';
69
+ while (true) {
70
+ const { done, value } = await reader.read();
71
+ if (done)
72
+ break;
73
+ buffer += decoder.decode(value, { stream: true });
74
+ const lines = buffer.split('\n');
75
+ buffer = lines.pop() || '';
76
+ const events = this.parseSSE(lines.join('\n'));
77
+ for (const event of events) {
78
+ const delta = event.choices?.[0]?.delta;
79
+ if (delta && delta.content) {
80
+ yield {
81
+ content: delta.content,
82
+ done: false
83
+ };
84
+ }
85
+ if (event.choices?.[0]?.finish_reason) {
86
+ yield {
87
+ content: '',
88
+ done: true
89
+ };
90
+ }
91
+ }
92
+ }
93
+ }
94
+ getModels() {
95
+ return [...this.models];
96
+ }
97
+ supportsFeature(feature) {
98
+ const supported = ['chat', 'function_calling', 'streaming'];
99
+ return supported.includes(feature);
100
+ }
101
+ }
102
+ //# sourceMappingURL=groq-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groq-provider.js","sourceRoot":"","sources":["../src/groq-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,OAAO,YAAa,SAAQ,YAAY;IACpC,OAAO,GAAG,gCAAgC,CAAC;IAC3C,MAAM,GAAG;QACf,sBAAsB;QACtB,yBAAyB;QACzB,yBAAyB;QACzB,oBAAoB;QACpB,cAAc;KACf,CAAC;IAEF,YAAY,MAAe,EAAE,MAAqB;QAChD,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,OAAoB;QACpC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,mBAAmB,CAAC;QAC/C,MAAM,OAAO,GAAG;YACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAM,GAAG,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE;YAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9C,IAAI,EAAE,WAAoB;YAC1B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,EAAO,EAAE,EAAE,CAAC,CAAC;gBAC/D,EAAE,EAAE,EAAE,CAAC,EAAE;gBACT,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI;gBACtB,SAAS,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS;aACjH,CAAC,CAAC;YACH,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClB,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa;gBACtC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB;gBAC9C,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY;aACrC,CAAC,CAAC,CAAC,SAAS;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,IAAI,MAAM;SACtD,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,CAAC,UAAU,CAAC,OAAoB;QAC3C,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,mBAAmB,CAAC;QAC/C,MAAM,OAAO,GAAG;YACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE;YAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAElD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAE3B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;gBACxC,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAC3B,MAAM;wBACJ,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,IAAI,EAAE,KAAK;qBACZ,CAAC;gBACJ,CAAC;gBACD,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC;oBACtC,MAAM;wBACJ,OAAO,EAAE,EAAE;wBACX,IAAI,EAAE,IAAI;qBACX,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEM,SAAS;QACd,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAEM,eAAe,CAAC,OAAe;QACpC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,WAAW,CAAC,CAAC;QAC5D,OAAO,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export * from './base-provider.js';
2
+ export * from './provider-manager.js';
3
+ export * from './groq-provider.js';
4
+ export * from './openai-compatible-provider.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './base-provider.js';
2
+ export * from './provider-manager.js';
3
+ export * from './groq-provider.js';
4
+ export * from './openai-compatible-provider.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ import { ChatRequest, ChatResponse, ChatChunk, ILogger, IEventEmitter } from '@astrive-ai/types';
3
+ export interface OpenAIConfig {
4
+ baseUrl: string;
5
+ models: string[];
6
+ }
7
+ export declare class OpenAICompatibleProvider extends BaseProvider {
8
+ private openaiConfig;
9
+ constructor(name: string, logger: ILogger, events: IEventEmitter, config: OpenAIConfig);
10
+ chat(request: ChatRequest): Promise<ChatResponse>;
11
+ chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown>;
12
+ getModels(): string[];
13
+ supportsFeature(feature: string): boolean;
14
+ }
15
+ //# sourceMappingURL=openai-compatible-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible-provider.d.ts","sourceRoot":"","sources":["../src/openai-compatible-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,qBAAa,wBAAyB,SAAQ,YAAY;IACxD,OAAO,CAAC,YAAY,CAAe;gBAGjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY;IAMT,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAmChD,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC;IAsDjF,SAAS,IAAI,MAAM,EAAE;IAIrB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAIjD"}
@@ -0,0 +1,96 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ export class OpenAICompatibleProvider extends BaseProvider {
3
+ openaiConfig;
4
+ constructor(name, logger, events, config) {
5
+ super(name, 'custom', logger, events);
6
+ this.openaiConfig = config;
7
+ }
8
+ async chat(request) {
9
+ const url = `${this.openaiConfig.baseUrl}/chat/completions`;
10
+ const payload = {
11
+ messages: request.messages,
12
+ model: request.model || this.openaiConfig.models[0],
13
+ temperature: request.temperature,
14
+ max_tokens: request.maxTokens,
15
+ tools: request.tools
16
+ };
17
+ const data = await this.fetchJSON(url, {
18
+ method: 'POST',
19
+ headers: this.buildHeaders(),
20
+ body: JSON.stringify(payload)
21
+ });
22
+ return {
23
+ id: data.id,
24
+ content: data.choices[0].message.content || '',
25
+ role: 'assistant',
26
+ toolCalls: data.choices[0].message.tool_calls?.map((tc) => ({
27
+ id: tc.id,
28
+ name: tc.function.name,
29
+ arguments: typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments
30
+ })),
31
+ usage: data.usage ? {
32
+ promptTokens: data.usage.prompt_tokens,
33
+ completionTokens: data.usage.completion_tokens,
34
+ totalTokens: data.usage.total_tokens
35
+ } : undefined,
36
+ model: data.model,
37
+ finishReason: data.choices[0].finish_reason || 'stop'
38
+ };
39
+ }
40
+ async *chatStream(request) {
41
+ const url = `${this.openaiConfig.baseUrl}/chat/completions`;
42
+ const payload = {
43
+ messages: request.messages,
44
+ model: request.model || this.openaiConfig.models[0],
45
+ temperature: request.temperature,
46
+ max_tokens: request.maxTokens,
47
+ tools: request.tools,
48
+ stream: true
49
+ };
50
+ const response = await fetch(url, {
51
+ method: 'POST',
52
+ headers: this.buildHeaders(),
53
+ body: JSON.stringify(payload)
54
+ });
55
+ if (!response.ok) {
56
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
57
+ }
58
+ if (!response.body)
59
+ throw new Error('No response body');
60
+ const reader = response.body.getReader();
61
+ const decoder = new TextDecoder('utf-8');
62
+ let buffer = '';
63
+ while (true) {
64
+ const { done, value } = await reader.read();
65
+ if (done)
66
+ break;
67
+ buffer += decoder.decode(value, { stream: true });
68
+ const lines = buffer.split('\n');
69
+ buffer = lines.pop() || '';
70
+ const events = this.parseSSE(lines.join('\n'));
71
+ for (const event of events) {
72
+ const delta = event.choices?.[0]?.delta;
73
+ if (delta && delta.content) {
74
+ yield {
75
+ content: delta.content,
76
+ done: false
77
+ };
78
+ }
79
+ if (event.choices?.[0]?.finish_reason) {
80
+ yield {
81
+ content: '',
82
+ done: true
83
+ };
84
+ }
85
+ }
86
+ }
87
+ }
88
+ getModels() {
89
+ return [...this.openaiConfig.models];
90
+ }
91
+ supportsFeature(feature) {
92
+ const supported = ['chat', 'function_calling', 'streaming'];
93
+ return supported.includes(feature);
94
+ }
95
+ }
96
+ //# sourceMappingURL=openai-compatible-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible-provider.js","sourceRoot":"","sources":["../src/openai-compatible-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { IProvider, ProviderType, ProviderConfig } from '@astrive-ai/types';
2
+ export declare class ProviderManager {
3
+ private providers;
4
+ register(provider: IProvider): void;
5
+ get(name: string): IProvider | undefined;
6
+ getAll(): IProvider[];
7
+ getByType(type: ProviderType): IProvider[];
8
+ has(name: string): boolean;
9
+ initAll(configs: Record<string, ProviderConfig>): Promise<void>;
10
+ selectProvider(preferred?: string, feature?: string): IProvider;
11
+ destroyAll(): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=provider-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-manager.d.ts","sourceRoot":"","sources":["../src/provider-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE5E,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAqC;IAE/C,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI;IAInC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC,MAAM,IAAI,SAAS,EAAE;IAIrB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,EAAE;IAI1C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpB,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;IAezD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAUzC"}
@@ -0,0 +1,52 @@
1
+ export class ProviderManager {
2
+ providers = new Map();
3
+ register(provider) {
4
+ this.providers.set(provider.name, provider);
5
+ }
6
+ get(name) {
7
+ return this.providers.get(name);
8
+ }
9
+ getAll() {
10
+ return Array.from(this.providers.values());
11
+ }
12
+ getByType(type) {
13
+ return Array.from(this.providers.values()).filter(p => p.type === type);
14
+ }
15
+ has(name) {
16
+ return this.providers.has(name);
17
+ }
18
+ async initAll(configs) {
19
+ const promises = [];
20
+ for (const [name, provider] of this.providers.entries()) {
21
+ if (configs[name]) {
22
+ promises.push(provider.init(configs[name]));
23
+ }
24
+ }
25
+ await Promise.all(promises);
26
+ }
27
+ selectProvider(preferred, feature) {
28
+ if (preferred && this.providers.has(preferred)) {
29
+ const prefProv = this.providers.get(preferred);
30
+ if (prefProv.isAvailable() && (!feature || prefProv.supportsFeature(feature))) {
31
+ return prefProv;
32
+ }
33
+ }
34
+ for (const provider of this.providers.values()) {
35
+ if (provider.isAvailable() && (!feature || provider.supportsFeature(feature))) {
36
+ return provider;
37
+ }
38
+ }
39
+ throw new Error('No suitable provider available');
40
+ }
41
+ async destroyAll() {
42
+ const promises = [];
43
+ for (const provider of this.providers.values()) {
44
+ if (provider.destroy) {
45
+ promises.push(provider.destroy());
46
+ }
47
+ }
48
+ await Promise.all(promises);
49
+ this.providers.clear();
50
+ }
51
+ }
52
+ //# sourceMappingURL=provider-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-manager.js","sourceRoot":"","sources":["../src/provider-manager.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,eAAe;IAClB,SAAS,GAA2B,IAAI,GAAG,EAAE,CAAC;IAE/C,QAAQ,CAAC,QAAmB;QACjC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAEM,GAAG,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAEM,MAAM;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IAEM,SAAS,CAAC,IAAkB;QACjC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC1E,CAAC;IAEM,GAAG,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,OAAuC;QAC1D,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YACxD,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QACD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAEM,cAAc,CAAC,SAAkB,EAAE,OAAgB;QACxD,IAAI,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;YAChD,IAAI,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;gBAC9E,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/C,IAAI,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;gBAC9E,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,UAAU;QACrB,MAAM,QAAQ,GAAG,EAAE,CAAC;QACpB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/C,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QACD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@astrive-ai/providers",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "dependencies": {
18
+ "@astrive-ai/types": "*",
19
+ "@astrive-ai/logger": "*",
20
+ "@astrive-ai/events": "*"
21
+ },
22
+ "devDependencies": {
23
+ "typescript": "5.4.5"
24
+ }
25
+ }
@@ -0,0 +1,98 @@
1
+ import {
2
+ IProvider,
3
+ ProviderConfig,
4
+ ProviderType,
5
+ ChatRequest,
6
+ ChatResponse,
7
+ ChatChunk,
8
+ ILogger,
9
+ IEventEmitter
10
+ } from '@astrive-ai/types';
11
+
12
+ export abstract class BaseProvider implements IProvider {
13
+ protected config: ProviderConfig = {};
14
+
15
+ constructor(
16
+ public readonly name: string,
17
+ public readonly type: ProviderType,
18
+ protected logger: ILogger,
19
+ protected events: IEventEmitter
20
+ ) {}
21
+
22
+ public async init(config: ProviderConfig): Promise<void> {
23
+ this.config = { ...this.config, ...config };
24
+ this.logger.debug(`Provider ${this.name} initialized with config.`);
25
+ }
26
+
27
+ public abstract chat(request: ChatRequest): Promise<ChatResponse>;
28
+
29
+ public async *chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown> {
30
+ const response = await this.chat(request);
31
+ const content = response.content;
32
+ const chunkSize = 10;
33
+
34
+ for (let i = 0; i < content.length; i += chunkSize) {
35
+ const chunk = content.slice(i, i + chunkSize);
36
+ yield {
37
+ content: chunk,
38
+ done: i + chunkSize >= content.length,
39
+ toolCalls: i + chunkSize >= content.length ? response.toolCalls : undefined
40
+ };
41
+ }
42
+ }
43
+
44
+ public isAvailable(): boolean {
45
+ return !!this.config.apiKey;
46
+ }
47
+
48
+ public abstract getModels(): string[];
49
+ public abstract supportsFeature(feature: string): boolean;
50
+
51
+ public async destroy(): Promise<void> {
52
+ this.config = {};
53
+ this.logger.debug(`Provider ${this.name} destroyed.`);
54
+ }
55
+
56
+ protected buildHeaders(): Record<string, string> {
57
+ const headers: Record<string, string> = {
58
+ 'Content-Type': 'application/json'
59
+ };
60
+ if (this.config.apiKey) {
61
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
62
+ }
63
+ return headers;
64
+ }
65
+
66
+ protected async fetchJSON<T>(url: string, options: RequestInit): Promise<T> {
67
+ try {
68
+ const response = await fetch(url, options);
69
+ if (!response.ok) {
70
+ const errorText = await response.text();
71
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
72
+ }
73
+ return (await response.json()) as T;
74
+ } catch (error) {
75
+ this.logger.error(`fetchJSON error from ${url}:`, error);
76
+ throw error;
77
+ }
78
+ }
79
+
80
+ protected parseSSE(text: string): any[] {
81
+ const lines = text.split('\n');
82
+ const events: any[] = [];
83
+ for (const line of lines) {
84
+ if (line.startsWith('data: ')) {
85
+ const data = line.slice(6).trim();
86
+ if (data === '[DONE]') continue;
87
+ if (data) {
88
+ try {
89
+ events.push(JSON.parse(data));
90
+ } catch (e) {
91
+ this.logger.warn(`Failed to parse SSE line: ${line}`);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return events;
97
+ }
98
+ }
@@ -0,0 +1,115 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ import { ChatRequest, ChatResponse, ChatChunk, ILogger, IEventEmitter } from '@astrive-ai/types';
3
+
4
+ export class GroqProvider extends BaseProvider {
5
+ private baseUrl = 'https://api.groq.com/openai/v1';
6
+ private models = [
7
+ 'llama-3.1-8b-instant',
8
+ 'llama-3.3-70b-versatile',
9
+ 'llama-3.1-70b-versatile',
10
+ 'mixtral-8x7b-32768',
11
+ 'gemma2-9b-it'
12
+ ];
13
+
14
+ constructor(logger: ILogger, events: IEventEmitter) {
15
+ super('groq', 'official', logger, events);
16
+ }
17
+
18
+ public async chat(request: ChatRequest): Promise<ChatResponse> {
19
+ const url = `${this.baseUrl}/chat/completions`;
20
+ const payload = {
21
+ messages: request.messages,
22
+ model: request.model || this.models[0],
23
+ temperature: request.temperature,
24
+ max_tokens: request.maxTokens,
25
+ tools: request.tools
26
+ };
27
+
28
+ const data = await this.fetchJSON<any>(url, {
29
+ method: 'POST',
30
+ headers: this.buildHeaders(),
31
+ body: JSON.stringify(payload)
32
+ });
33
+
34
+ return {
35
+ id: data.id,
36
+ content: data.choices[0].message.content || '',
37
+ role: 'assistant' as const,
38
+ toolCalls: data.choices[0].message.tool_calls?.map((tc: any) => ({
39
+ id: tc.id,
40
+ name: tc.function.name,
41
+ arguments: typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments
42
+ })),
43
+ usage: data.usage ? {
44
+ promptTokens: data.usage.prompt_tokens,
45
+ completionTokens: data.usage.completion_tokens,
46
+ totalTokens: data.usage.total_tokens
47
+ } : undefined,
48
+ model: data.model,
49
+ finishReason: data.choices[0].finish_reason || 'stop'
50
+ };
51
+ }
52
+
53
+ public async *chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown> {
54
+ const url = `${this.baseUrl}/chat/completions`;
55
+ const payload = {
56
+ messages: request.messages,
57
+ model: request.model || this.models[0],
58
+ temperature: request.temperature,
59
+ max_tokens: request.maxTokens,
60
+ tools: request.tools,
61
+ stream: true
62
+ };
63
+
64
+ const response = await fetch(url, {
65
+ method: 'POST',
66
+ headers: this.buildHeaders(),
67
+ body: JSON.stringify(payload)
68
+ });
69
+
70
+ if (!response.ok) {
71
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
72
+ }
73
+
74
+ if (!response.body) throw new Error('No response body');
75
+
76
+ const reader = response.body.getReader();
77
+ const decoder = new TextDecoder('utf-8');
78
+ let buffer = '';
79
+
80
+ while (true) {
81
+ const { done, value } = await reader.read();
82
+ if (done) break;
83
+ buffer += decoder.decode(value, { stream: true });
84
+
85
+ const lines = buffer.split('\n');
86
+ buffer = lines.pop() || '';
87
+
88
+ const events = this.parseSSE(lines.join('\n'));
89
+ for (const event of events) {
90
+ const delta = event.choices?.[0]?.delta;
91
+ if (delta && delta.content) {
92
+ yield {
93
+ content: delta.content,
94
+ done: false
95
+ };
96
+ }
97
+ if (event.choices?.[0]?.finish_reason) {
98
+ yield {
99
+ content: '',
100
+ done: true
101
+ };
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ public getModels(): string[] {
108
+ return [...this.models];
109
+ }
110
+
111
+ public supportsFeature(feature: string): boolean {
112
+ const supported = ['chat', 'function_calling', 'streaming'];
113
+ return supported.includes(feature);
114
+ }
115
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './base-provider.js';
2
+ export * from './provider-manager.js';
3
+ export * from './groq-provider.js';
4
+ export * from './openai-compatible-provider.js';
@@ -0,0 +1,119 @@
1
+ import { BaseProvider } from './base-provider.js';
2
+ import { ChatRequest, ChatResponse, ChatChunk, ILogger, IEventEmitter } from '@astrive-ai/types';
3
+
4
+ export interface OpenAIConfig {
5
+ baseUrl: string;
6
+ models: string[];
7
+ }
8
+
9
+ export class OpenAICompatibleProvider extends BaseProvider {
10
+ private openaiConfig: OpenAIConfig;
11
+
12
+ constructor(
13
+ name: string,
14
+ logger: ILogger,
15
+ events: IEventEmitter,
16
+ config: OpenAIConfig
17
+ ) {
18
+ super(name, 'custom', logger, events);
19
+ this.openaiConfig = config;
20
+ }
21
+
22
+ public async chat(request: ChatRequest): Promise<ChatResponse> {
23
+ const url = `${this.openaiConfig.baseUrl}/chat/completions`;
24
+ const payload = {
25
+ messages: request.messages,
26
+ model: request.model || this.openaiConfig.models[0],
27
+ temperature: request.temperature,
28
+ max_tokens: request.maxTokens,
29
+ tools: request.tools
30
+ };
31
+
32
+ const data = await this.fetchJSON<any>(url, {
33
+ method: 'POST',
34
+ headers: this.buildHeaders(),
35
+ body: JSON.stringify(payload)
36
+ });
37
+
38
+ return {
39
+ id: data.id,
40
+ content: data.choices[0].message.content || '',
41
+ role: 'assistant' as const,
42
+ toolCalls: data.choices[0].message.tool_calls?.map((tc: any) => ({
43
+ id: tc.id,
44
+ name: tc.function.name,
45
+ arguments: typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments
46
+ })),
47
+ usage: data.usage ? {
48
+ promptTokens: data.usage.prompt_tokens,
49
+ completionTokens: data.usage.completion_tokens,
50
+ totalTokens: data.usage.total_tokens
51
+ } : undefined,
52
+ model: data.model,
53
+ finishReason: data.choices[0].finish_reason || 'stop'
54
+ };
55
+ }
56
+
57
+ public async *chatStream(request: ChatRequest): AsyncGenerator<ChatChunk, void, unknown> {
58
+ const url = `${this.openaiConfig.baseUrl}/chat/completions`;
59
+ const payload = {
60
+ messages: request.messages,
61
+ model: request.model || this.openaiConfig.models[0],
62
+ temperature: request.temperature,
63
+ max_tokens: request.maxTokens,
64
+ tools: request.tools,
65
+ stream: true
66
+ };
67
+
68
+ const response = await fetch(url, {
69
+ method: 'POST',
70
+ headers: this.buildHeaders(),
71
+ body: JSON.stringify(payload)
72
+ });
73
+
74
+ if (!response.ok) {
75
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
76
+ }
77
+
78
+ if (!response.body) throw new Error('No response body');
79
+
80
+ const reader = response.body.getReader();
81
+ const decoder = new TextDecoder('utf-8');
82
+ let buffer = '';
83
+
84
+ while (true) {
85
+ const { done, value } = await reader.read();
86
+ if (done) break;
87
+ buffer += decoder.decode(value, { stream: true });
88
+
89
+ const lines = buffer.split('\n');
90
+ buffer = lines.pop() || '';
91
+
92
+ const events = this.parseSSE(lines.join('\n'));
93
+ for (const event of events) {
94
+ const delta = event.choices?.[0]?.delta;
95
+ if (delta && delta.content) {
96
+ yield {
97
+ content: delta.content,
98
+ done: false
99
+ };
100
+ }
101
+ if (event.choices?.[0]?.finish_reason) {
102
+ yield {
103
+ content: '',
104
+ done: true
105
+ };
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ public getModels(): string[] {
112
+ return [...this.openaiConfig.models];
113
+ }
114
+
115
+ public supportsFeature(feature: string): boolean {
116
+ const supported = ['chat', 'function_calling', 'streaming'];
117
+ return supported.includes(feature);
118
+ }
119
+ }
@@ -0,0 +1,61 @@
1
+ import { IProvider, ProviderType, ProviderConfig } from '@astrive-ai/types';
2
+
3
+ export class ProviderManager {
4
+ private providers: Map<string, IProvider> = new Map();
5
+
6
+ public register(provider: IProvider): void {
7
+ this.providers.set(provider.name, provider);
8
+ }
9
+
10
+ public get(name: string): IProvider | undefined {
11
+ return this.providers.get(name);
12
+ }
13
+
14
+ public getAll(): IProvider[] {
15
+ return Array.from(this.providers.values());
16
+ }
17
+
18
+ public getByType(type: ProviderType): IProvider[] {
19
+ return Array.from(this.providers.values()).filter(p => p.type === type);
20
+ }
21
+
22
+ public has(name: string): boolean {
23
+ return this.providers.has(name);
24
+ }
25
+
26
+ public async initAll(configs: Record<string, ProviderConfig>): Promise<void> {
27
+ const promises = [];
28
+ for (const [name, provider] of this.providers.entries()) {
29
+ if (configs[name]) {
30
+ promises.push(provider.init(configs[name]));
31
+ }
32
+ }
33
+ await Promise.all(promises);
34
+ }
35
+
36
+ public selectProvider(preferred?: string, feature?: string): IProvider {
37
+ if (preferred && this.providers.has(preferred)) {
38
+ const prefProv = this.providers.get(preferred)!;
39
+ if (prefProv.isAvailable() && (!feature || prefProv.supportsFeature(feature))) {
40
+ return prefProv;
41
+ }
42
+ }
43
+ for (const provider of this.providers.values()) {
44
+ if (provider.isAvailable() && (!feature || provider.supportsFeature(feature))) {
45
+ return provider;
46
+ }
47
+ }
48
+ throw new Error('No suitable provider available');
49
+ }
50
+
51
+ public async destroyAll(): Promise<void> {
52
+ const promises = [];
53
+ for (const provider of this.providers.values()) {
54
+ if (provider.destroy) {
55
+ promises.push(provider.destroy());
56
+ }
57
+ }
58
+ await Promise.all(promises);
59
+ this.providers.clear();
60
+ }
61
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"]
8
+ }