@astro-minimax/ai 0.2.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/README.md +223 -0
- package/dist/cache/global-cache.d.ts +31 -0
- package/dist/cache/global-cache.d.ts.map +1 -0
- package/dist/cache/global-cache.js +141 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +62 -0
- package/dist/cache/kv-adapter.d.ts +21 -0
- package/dist/cache/kv-adapter.d.ts.map +1 -0
- package/dist/cache/kv-adapter.js +102 -0
- package/dist/cache/memory-adapter.d.ts +24 -0
- package/dist/cache/memory-adapter.d.ts.map +1 -0
- package/dist/cache/memory-adapter.js +95 -0
- package/dist/cache/response-cache.d.ts +45 -0
- package/dist/cache/response-cache.d.ts.map +1 -0
- package/dist/cache/response-cache.js +85 -0
- package/dist/cache/types.d.ts +118 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +16 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.d.ts.map +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/metadata-loader.d.ts +37 -0
- package/dist/data/metadata-loader.d.ts.map +1 -0
- package/dist/data/metadata-loader.js +54 -0
- package/dist/data/types.d.ts +51 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/data/types.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/intelligence/citation-guard.d.ts +24 -0
- package/dist/intelligence/citation-guard.d.ts.map +1 -0
- package/dist/intelligence/citation-guard.js +82 -0
- package/dist/intelligence/evidence-analysis.d.ts +29 -0
- package/dist/intelligence/evidence-analysis.d.ts.map +1 -0
- package/dist/intelligence/evidence-analysis.js +88 -0
- package/dist/intelligence/index.d.ts +6 -0
- package/dist/intelligence/index.d.ts.map +1 -0
- package/dist/intelligence/index.js +4 -0
- package/dist/intelligence/intent-detect.d.ts +29 -0
- package/dist/intelligence/intent-detect.d.ts.map +1 -0
- package/dist/intelligence/intent-detect.js +64 -0
- package/dist/intelligence/keyword-extract.d.ts +31 -0
- package/dist/intelligence/keyword-extract.d.ts.map +1 -0
- package/dist/intelligence/keyword-extract.js +114 -0
- package/dist/intelligence/types.d.ts +27 -0
- package/dist/intelligence/types.d.ts.map +1 -0
- package/dist/intelligence/types.js +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/middleware/rate-limiter.d.ts +26 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +129 -0
- package/dist/prompt/dynamic-layer.d.ts +7 -0
- package/dist/prompt/dynamic-layer.d.ts.map +1 -0
- package/dist/prompt/dynamic-layer.js +40 -0
- package/dist/prompt/index.d.ts +6 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/index.js +4 -0
- package/dist/prompt/prompt-builder.d.ts +11 -0
- package/dist/prompt/prompt-builder.d.ts.map +1 -0
- package/dist/prompt/prompt-builder.js +19 -0
- package/dist/prompt/semi-static-layer.d.ts +7 -0
- package/dist/prompt/semi-static-layer.d.ts.map +1 -0
- package/dist/prompt/semi-static-layer.js +32 -0
- package/dist/prompt/static-layer.d.ts +3 -0
- package/dist/prompt/static-layer.d.ts.map +1 -0
- package/dist/prompt/static-layer.js +78 -0
- package/dist/prompt/types.d.ts +25 -0
- package/dist/prompt/types.d.ts.map +1 -0
- package/dist/prompt/types.js +1 -0
- package/dist/provider-manager/base.d.ts +26 -0
- package/dist/provider-manager/base.d.ts.map +1 -0
- package/dist/provider-manager/base.js +47 -0
- package/dist/provider-manager/config.d.ts +7 -0
- package/dist/provider-manager/config.d.ts.map +1 -0
- package/dist/provider-manager/config.js +134 -0
- package/dist/provider-manager/index.d.ts +8 -0
- package/dist/provider-manager/index.d.ts.map +1 -0
- package/dist/provider-manager/index.js +6 -0
- package/dist/provider-manager/manager.d.ts +18 -0
- package/dist/provider-manager/manager.d.ts.map +1 -0
- package/dist/provider-manager/manager.js +121 -0
- package/dist/provider-manager/mock.d.ts +18 -0
- package/dist/provider-manager/mock.d.ts.map +1 -0
- package/dist/provider-manager/mock.js +56 -0
- package/dist/provider-manager/openai.d.ts +20 -0
- package/dist/provider-manager/openai.d.ts.map +1 -0
- package/dist/provider-manager/openai.js +83 -0
- package/dist/provider-manager/types.d.ts +217 -0
- package/dist/provider-manager/types.d.ts.map +1 -0
- package/dist/provider-manager/types.js +6 -0
- package/dist/provider-manager/workers.d.ts +20 -0
- package/dist/provider-manager/workers.d.ts.map +1 -0
- package/dist/provider-manager/workers.js +74 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/mock.d.ts +14 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +234 -0
- package/dist/search/index.d.ts +5 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +3 -0
- package/dist/search/search-api.d.ts +28 -0
- package/dist/search/search-api.d.ts.map +1 -0
- package/dist/search/search-api.js +110 -0
- package/dist/search/search-index.d.ts +6 -0
- package/dist/search/search-index.d.ts.map +1 -0
- package/dist/search/search-index.js +22 -0
- package/dist/search/search-utils.d.ts +43 -0
- package/dist/search/search-utils.d.ts.map +1 -0
- package/dist/search/search-utils.js +114 -0
- package/dist/search/session-cache.d.ts +19 -0
- package/dist/search/session-cache.d.ts.map +1 -0
- package/dist/search/session-cache.js +92 -0
- package/dist/search/types.d.ts +41 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +1 -0
- package/dist/server/chat-handler.d.ts +3 -0
- package/dist/server/chat-handler.d.ts.map +1 -0
- package/dist/server/chat-handler.js +750 -0
- package/dist/server/dev-server.d.ts +18 -0
- package/dist/server/dev-server.d.ts.map +1 -0
- package/dist/server/dev-server.js +294 -0
- package/dist/server/errors.d.ts +17 -0
- package/dist/server/errors.d.ts.map +1 -0
- package/dist/server/errors.js +41 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +5 -0
- package/dist/server/metadata-init.d.ts +11 -0
- package/dist/server/metadata-init.d.ts.map +1 -0
- package/dist/server/metadata-init.js +45 -0
- package/dist/server/notify.d.ts +25 -0
- package/dist/server/notify.d.ts.map +1 -0
- package/dist/server/notify.js +62 -0
- package/dist/server/types.d.ts +56 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +13 -0
- package/dist/stream/index.d.ts +3 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +2 -0
- package/dist/stream/mock-stream.d.ts +12 -0
- package/dist/stream/mock-stream.d.ts.map +1 -0
- package/dist/stream/mock-stream.js +27 -0
- package/dist/stream/response.d.ts +10 -0
- package/dist/stream/response.d.ts.map +1 -0
- package/dist/stream/response.js +22 -0
- package/dist/utils/i18n.d.ts +18 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +148 -0
- package/package.json +93 -0
- package/src/components/AIChatContainer.tsx +30 -0
- package/src/components/AIChatWidget.astro +30 -0
- package/src/components/ChatPanel.tsx +865 -0
- package/src/styles/source.css +2 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProviderAdapter, ProviderManagerEnv, ProviderManagerOptions, ProviderStatus, StreamTextOptions, StreamTextResult } from './types.js';
|
|
2
|
+
export declare class ProviderManager {
|
|
3
|
+
private providers;
|
|
4
|
+
private mockAdapter;
|
|
5
|
+
private options;
|
|
6
|
+
constructor(env: ProviderManagerEnv, options?: ProviderManagerOptions);
|
|
7
|
+
private initializeProviders;
|
|
8
|
+
private createAdapter;
|
|
9
|
+
getAvailableProvider(): Promise<ProviderAdapter | null>;
|
|
10
|
+
streamText(options: StreamTextOptions): Promise<StreamTextResult>;
|
|
11
|
+
getProviderStatus(): ProviderStatus[];
|
|
12
|
+
hasProviders(): boolean;
|
|
13
|
+
getProviderCount(): number;
|
|
14
|
+
getAvailableAdapter(): Promise<ProviderAdapter | null>;
|
|
15
|
+
}
|
|
16
|
+
export declare function getProviderManager(env: ProviderManagerEnv, options?: ProviderManagerOptions): ProviderManager;
|
|
17
|
+
export declare function resetProviderManager(): void;
|
|
18
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/provider-manager/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,kBAAkB,EAClB,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAMpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,OAAO,CAA0L;gBAE7L,GAAG,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAcrE,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,CAAC,aAAa;IAWf,oBAAoB,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IASvD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqCvE,iBAAiB,IAAI,cAAc,EAAE;IAWrC,YAAY,IAAI,OAAO;IAIvB,gBAAgB,IAAI,MAAM;IAIpB,mBAAmB,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;CAG7D;AAID,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,eAAe,CAK7G;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { parseProviderConfigs, validateProviderConfig } from './config.js';
|
|
2
|
+
import { OpenAIAdapter } from './openai.js';
|
|
3
|
+
import { WorkersAIAdapter } from './workers.js';
|
|
4
|
+
import { MockAdapter } from './mock.js';
|
|
5
|
+
export class ProviderManager {
|
|
6
|
+
providers = [];
|
|
7
|
+
mockAdapter;
|
|
8
|
+
options;
|
|
9
|
+
constructor(env, options) {
|
|
10
|
+
this.options = {
|
|
11
|
+
unhealthyThreshold: options?.unhealthyThreshold ?? 3,
|
|
12
|
+
healthRecoveryTTL: options?.healthRecoveryTTL ?? 60000,
|
|
13
|
+
enableMockFallback: options?.enableMockFallback ?? true,
|
|
14
|
+
onProviderSwitch: options?.onProviderSwitch,
|
|
15
|
+
onStreamError: options?.onStreamError,
|
|
16
|
+
onHealthChange: options?.onHealthChange,
|
|
17
|
+
};
|
|
18
|
+
this.mockAdapter = new MockAdapter();
|
|
19
|
+
this.initializeProviders(env);
|
|
20
|
+
}
|
|
21
|
+
initializeProviders(env) {
|
|
22
|
+
const configs = parseProviderConfigs(env);
|
|
23
|
+
for (const config of configs) {
|
|
24
|
+
if (config.enabled === false)
|
|
25
|
+
continue;
|
|
26
|
+
const validationError = validateProviderConfig(config);
|
|
27
|
+
if (validationError) {
|
|
28
|
+
console.warn(`[ProviderManager] Skipping invalid config: ${validationError}`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const adapter = this.createAdapter(config, env);
|
|
33
|
+
if (adapter) {
|
|
34
|
+
this.providers.push(adapter);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.warn(`[ProviderManager] Failed to create adapter for ${config.id}:`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
this.providers.sort((a, b) => b.weight - a.weight);
|
|
42
|
+
}
|
|
43
|
+
createAdapter(config, env) {
|
|
44
|
+
switch (config.type) {
|
|
45
|
+
case 'openai':
|
|
46
|
+
return new OpenAIAdapter(config);
|
|
47
|
+
case 'workers':
|
|
48
|
+
return new WorkersAIAdapter(config, env);
|
|
49
|
+
default:
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async getAvailableProvider() {
|
|
54
|
+
for (const provider of this.providers) {
|
|
55
|
+
if (await provider.isAvailable()) {
|
|
56
|
+
return provider;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
async streamText(options) {
|
|
62
|
+
let lastProviderId = null;
|
|
63
|
+
let lastError = null;
|
|
64
|
+
for (const provider of this.providers) {
|
|
65
|
+
const isAvailable = await provider.isAvailable();
|
|
66
|
+
if (!isAvailable)
|
|
67
|
+
continue;
|
|
68
|
+
try {
|
|
69
|
+
const result = await provider.streamText(options);
|
|
70
|
+
provider.recordSuccess();
|
|
71
|
+
if (lastProviderId && lastProviderId !== provider.id) {
|
|
72
|
+
this.options.onProviderSwitch?.(lastProviderId, provider.id, 'fallback success');
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
78
|
+
lastProviderId = provider.id;
|
|
79
|
+
provider.recordFailure(lastError);
|
|
80
|
+
this.options.onStreamError?.(provider.id, lastError);
|
|
81
|
+
if (!provider.getHealth().healthy) {
|
|
82
|
+
this.options.onHealthChange?.(provider.id, false);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (this.options.enableMockFallback) {
|
|
87
|
+
this.options.onProviderSwitch?.(lastProviderId, 'mock', 'all providers failed');
|
|
88
|
+
return this.mockAdapter.streamText(options);
|
|
89
|
+
}
|
|
90
|
+
throw lastError || new Error('No providers available');
|
|
91
|
+
}
|
|
92
|
+
getProviderStatus() {
|
|
93
|
+
return this.providers.map(provider => ({
|
|
94
|
+
id: provider.id,
|
|
95
|
+
type: provider.type,
|
|
96
|
+
weight: provider.weight,
|
|
97
|
+
enabled: true,
|
|
98
|
+
health: provider.getHealth(),
|
|
99
|
+
model: provider.model,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
hasProviders() {
|
|
103
|
+
return this.providers.length > 0;
|
|
104
|
+
}
|
|
105
|
+
getProviderCount() {
|
|
106
|
+
return this.providers.length;
|
|
107
|
+
}
|
|
108
|
+
async getAvailableAdapter() {
|
|
109
|
+
return this.getAvailableProvider();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
let managerInstance = null;
|
|
113
|
+
export function getProviderManager(env, options) {
|
|
114
|
+
if (!managerInstance) {
|
|
115
|
+
managerInstance = new ProviderManager(env, options);
|
|
116
|
+
}
|
|
117
|
+
return managerInstance;
|
|
118
|
+
}
|
|
119
|
+
export function resetProviderManager() {
|
|
120
|
+
managerInstance = null;
|
|
121
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StreamTextOptions, StreamTextResult } from './types.js';
|
|
2
|
+
import { BaseProviderAdapter } from './base.js';
|
|
3
|
+
export declare class MockAdapter extends BaseProviderAdapter {
|
|
4
|
+
readonly id: "mock";
|
|
5
|
+
readonly type: "mock";
|
|
6
|
+
readonly weight = 0;
|
|
7
|
+
readonly model = "mock";
|
|
8
|
+
readonly keywordModel = "mock";
|
|
9
|
+
readonly evidenceModel = "mock";
|
|
10
|
+
readonly timeout = 0;
|
|
11
|
+
constructor();
|
|
12
|
+
isAvailable(): Promise<boolean>;
|
|
13
|
+
streamText(options: StreamTextOptions): Promise<StreamTextResult>;
|
|
14
|
+
getProvider(): {
|
|
15
|
+
chatModel: (model: string) => unknown;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=mock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/provider-manager/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAMhD,qBAAa,WAAY,SAAQ,mBAAmB;IAClD,QAAQ,CAAC,EAAE,EAAG,MAAM,CAAU;IAC9B,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,MAAM,KAAe;IAC9B,QAAQ,CAAC,KAAK,UAAU;IACxB,QAAQ,CAAC,YAAY,UAAU;IAC/B,QAAQ,CAAC,aAAa,UAAU;IAChC,QAAQ,CAAC,OAAO,KAAK;;IAMf,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqDvE,WAAW,IAAI;QAAE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAA;KAAE;CAGzD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BaseProviderAdapter } from './base.js';
|
|
2
|
+
import { getMockResponse } from '../providers/mock.js';
|
|
3
|
+
const MOCK_WEIGHT = 0;
|
|
4
|
+
const CHAR_DELAY_MS = 15;
|
|
5
|
+
export class MockAdapter extends BaseProviderAdapter {
|
|
6
|
+
id = 'mock';
|
|
7
|
+
type = 'mock';
|
|
8
|
+
weight = MOCK_WEIGHT;
|
|
9
|
+
model = 'mock';
|
|
10
|
+
keywordModel = 'mock';
|
|
11
|
+
evidenceModel = 'mock';
|
|
12
|
+
timeout = 0;
|
|
13
|
+
constructor() {
|
|
14
|
+
super({ unhealthyThreshold: 999 });
|
|
15
|
+
}
|
|
16
|
+
async isAvailable() {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
async streamText(options) {
|
|
20
|
+
const { userQuestion = '', lang = 'zh' } = options;
|
|
21
|
+
const text = getMockResponse(userQuestion, lang);
|
|
22
|
+
const partId = `mock-${Date.now()}`;
|
|
23
|
+
const encoder = new TextEncoder();
|
|
24
|
+
const stream = new ReadableStream({
|
|
25
|
+
async start(controller) {
|
|
26
|
+
const write = (event) => controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
|
|
27
|
+
write({ type: 'text-start', id: partId });
|
|
28
|
+
for (let i = 0; i < text.length;) {
|
|
29
|
+
const chunkSize = Math.random() < 0.3 ? 3 : Math.random() < 0.5 ? 2 : 1;
|
|
30
|
+
const chunk = text.slice(i, i + chunkSize);
|
|
31
|
+
i += chunkSize;
|
|
32
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'text-delta', id: partId, delta: chunk })}\n\n`));
|
|
33
|
+
await new Promise(r => setTimeout(r, CHAR_DELAY_MS + Math.random() * 20));
|
|
34
|
+
}
|
|
35
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'text-end', id: partId })}\n\n`));
|
|
36
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'finish', finishReason: 'stop' })}\n\n`));
|
|
37
|
+
controller.close();
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const response = new Response(stream, {
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
43
|
+
'Cache-Control': 'no-cache, no-store',
|
|
44
|
+
'Access-Control-Allow-Origin': '*',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
toUIMessageStreamResponse: () => response,
|
|
49
|
+
providerId: this.id,
|
|
50
|
+
isMock: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
getProvider() {
|
|
54
|
+
throw new Error('Mock provider does not support chatModel interface');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OpenAIProviderConfig, StreamTextOptions, StreamTextResult } from './types.js';
|
|
2
|
+
import { BaseProviderAdapter } from './base.js';
|
|
3
|
+
export declare class OpenAIAdapter extends BaseProviderAdapter {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly type: "openai";
|
|
6
|
+
readonly weight: number;
|
|
7
|
+
readonly model: string;
|
|
8
|
+
readonly keywordModel: string;
|
|
9
|
+
readonly evidenceModel: string;
|
|
10
|
+
readonly timeout: number;
|
|
11
|
+
private provider;
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config: OpenAIProviderConfig);
|
|
14
|
+
streamText(options: StreamTextOptions): Promise<StreamTextResult>;
|
|
15
|
+
getConfig(): OpenAIProviderConfig;
|
|
16
|
+
getProvider(): {
|
|
17
|
+
chatModel: (model: string) => unknown;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/provider-manager/openai.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAUhD,qBAAa,aAAc,SAAQ,mBAAmB;IACpD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,MAAM,CAAuB;gBAEzB,MAAM,EAAE,oBAAoB;IAwBlC,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuCvE,SAAS,IAAI,oBAAoB;IAIjC,WAAW,IAAI;QAAE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAA;KAAE;CAGzD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
2
|
+
import { streamText, convertToModelMessages } from 'ai';
|
|
3
|
+
import { ProxyAgent, fetch as undiciFetch } from 'undici';
|
|
4
|
+
import { BaseProviderAdapter } from './base.js';
|
|
5
|
+
function createProxyFetch() {
|
|
6
|
+
const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY;
|
|
7
|
+
if (!proxyUrl)
|
|
8
|
+
return undefined;
|
|
9
|
+
const agent = new ProxyAgent(proxyUrl);
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
return ((url, init) => undiciFetch(url, { ...init, dispatcher: agent }));
|
|
12
|
+
}
|
|
13
|
+
export class OpenAIAdapter extends BaseProviderAdapter {
|
|
14
|
+
id;
|
|
15
|
+
type = 'openai';
|
|
16
|
+
weight;
|
|
17
|
+
model;
|
|
18
|
+
keywordModel;
|
|
19
|
+
evidenceModel;
|
|
20
|
+
timeout;
|
|
21
|
+
provider;
|
|
22
|
+
config;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
super({
|
|
25
|
+
unhealthyThreshold: config.maxRetries ? config.maxRetries + 2 : 3,
|
|
26
|
+
});
|
|
27
|
+
this.id = config.id;
|
|
28
|
+
this.weight = config.weight ?? 100;
|
|
29
|
+
this.model = config.model;
|
|
30
|
+
this.keywordModel = config.keywordModel ?? config.model;
|
|
31
|
+
this.evidenceModel = config.evidenceModel ?? this.keywordModel;
|
|
32
|
+
this.timeout = config.timeout ?? 30000;
|
|
33
|
+
this.config = config;
|
|
34
|
+
const proxyFetch = createProxyFetch();
|
|
35
|
+
this.provider = createOpenAICompatible({
|
|
36
|
+
name: `openai-${config.id}`,
|
|
37
|
+
baseURL: config.baseURL,
|
|
38
|
+
apiKey: config.apiKey,
|
|
39
|
+
includeUsage: true,
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
...(proxyFetch && { fetch: proxyFetch }),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async streamText(options) {
|
|
45
|
+
const { system, messages, temperature = 0.7, maxOutputTokens, topP, abortSignal, onError } = options;
|
|
46
|
+
const abortController = new AbortController();
|
|
47
|
+
const timeoutId = setTimeout(() => abortController.abort(), this.timeout);
|
|
48
|
+
if (abortSignal) {
|
|
49
|
+
abortSignal.addEventListener('abort', () => abortController.abort());
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const result = streamText({
|
|
53
|
+
model: this.provider.chatModel(this.model),
|
|
54
|
+
system,
|
|
55
|
+
messages: await convertToModelMessages(messages),
|
|
56
|
+
temperature,
|
|
57
|
+
maxOutputTokens,
|
|
58
|
+
topP,
|
|
59
|
+
abortSignal: abortController.signal,
|
|
60
|
+
onError: ({ error }) => {
|
|
61
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
const streamResult = {
|
|
65
|
+
toUIMessageStreamResponse: (responseOptions) => result.toUIMessageStreamResponse(responseOptions),
|
|
66
|
+
providerId: this.id,
|
|
67
|
+
isMock: false,
|
|
68
|
+
};
|
|
69
|
+
clearTimeout(timeoutId);
|
|
70
|
+
return streamResult;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
clearTimeout(timeoutId);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
getConfig() {
|
|
78
|
+
return { ...this.config };
|
|
79
|
+
}
|
|
80
|
+
getProvider() {
|
|
81
|
+
return this.provider;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the AI Provider Manager.
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple provider types with priority-based fallback.
|
|
5
|
+
*/
|
|
6
|
+
import type { UIMessage } from 'ai';
|
|
7
|
+
/**
|
|
8
|
+
* Base configuration shared by all provider types.
|
|
9
|
+
*/
|
|
10
|
+
export interface BaseProviderConfig {
|
|
11
|
+
/** Unique identifier for this provider instance */
|
|
12
|
+
id: string;
|
|
13
|
+
/** Provider type */
|
|
14
|
+
type: 'openai' | 'workers';
|
|
15
|
+
/** Priority weight (higher = more preferred). Default: 100 */
|
|
16
|
+
weight?: number;
|
|
17
|
+
/** Default model for chat */
|
|
18
|
+
model: string;
|
|
19
|
+
/** Model for keyword extraction (optional, defaults to model) */
|
|
20
|
+
keywordModel?: string;
|
|
21
|
+
/** Model for evidence analysis (optional, defaults to keywordModel) */
|
|
22
|
+
evidenceModel?: string;
|
|
23
|
+
/** Request timeout in milliseconds. Default: 30000 */
|
|
24
|
+
timeout?: number;
|
|
25
|
+
/** Max retries on failure. Default: 0 (no retry, fallback to next provider) */
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
/** Enable this provider. Default: true */
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* OpenAI-compatible provider configuration.
|
|
32
|
+
* Supports DeepSeek, Moonshot, Qwen, OpenAI, and any OpenAI-compatible API.
|
|
33
|
+
*/
|
|
34
|
+
export interface OpenAIProviderConfig extends BaseProviderConfig {
|
|
35
|
+
type: 'openai';
|
|
36
|
+
/** API base URL (e.g., https://api.deepseek.com/v1) */
|
|
37
|
+
baseURL: string;
|
|
38
|
+
/** API key */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Cloudflare Workers AI provider configuration.
|
|
43
|
+
* Uses AI binding directly from the Cloudflare environment.
|
|
44
|
+
*/
|
|
45
|
+
export interface WorkersAIProviderConfig extends BaseProviderConfig {
|
|
46
|
+
type: 'workers';
|
|
47
|
+
/** AI binding name in Cloudflare environment. Default: 'minimaxAI' */
|
|
48
|
+
bindingName: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Union type for all provider configurations.
|
|
52
|
+
*/
|
|
53
|
+
export type ProviderConfig = OpenAIProviderConfig | WorkersAIProviderConfig;
|
|
54
|
+
/**
|
|
55
|
+
* Environment variable interface for provider configuration.
|
|
56
|
+
* Used to build ProviderConfig from environment variables.
|
|
57
|
+
*/
|
|
58
|
+
export interface ProviderManagerEnv {
|
|
59
|
+
[key: string]: unknown;
|
|
60
|
+
/** JSON string containing array of ProviderConfig */
|
|
61
|
+
AI_PROVIDERS?: string;
|
|
62
|
+
AI_BASE_URL?: string;
|
|
63
|
+
AI_API_KEY?: string;
|
|
64
|
+
AI_MODEL?: string;
|
|
65
|
+
AI_KEYWORD_MODEL?: string;
|
|
66
|
+
AI_EVIDENCE_MODEL?: string;
|
|
67
|
+
AI_BINDING_NAME?: string;
|
|
68
|
+
AI_WORKERS_MODEL?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Health status of a provider instance.
|
|
72
|
+
*/
|
|
73
|
+
export interface ProviderHealth {
|
|
74
|
+
/** Whether the provider is currently healthy */
|
|
75
|
+
healthy: boolean;
|
|
76
|
+
/** Number of consecutive failures */
|
|
77
|
+
consecutiveFailures: number;
|
|
78
|
+
/** Total number of requests */
|
|
79
|
+
totalRequests: number;
|
|
80
|
+
/** Total number of successful requests */
|
|
81
|
+
successfulRequests: number;
|
|
82
|
+
/** Last error message (if any) */
|
|
83
|
+
lastError?: string;
|
|
84
|
+
/** Timestamp of last error */
|
|
85
|
+
lastErrorTime?: number;
|
|
86
|
+
/** Timestamp of last successful request */
|
|
87
|
+
lastSuccessTime?: number;
|
|
88
|
+
/** Timestamp when health status was last updated */
|
|
89
|
+
lastChecked: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Runtime status of a provider.
|
|
93
|
+
*/
|
|
94
|
+
export interface ProviderStatus {
|
|
95
|
+
/** Provider ID */
|
|
96
|
+
id: string;
|
|
97
|
+
/** Provider type */
|
|
98
|
+
type: 'openai' | 'workers' | 'mock';
|
|
99
|
+
/** Priority weight */
|
|
100
|
+
weight: number;
|
|
101
|
+
/** Whether the provider is enabled */
|
|
102
|
+
enabled: boolean;
|
|
103
|
+
/** Current health status */
|
|
104
|
+
health: ProviderHealth;
|
|
105
|
+
/** Model name */
|
|
106
|
+
model: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Options for streaming text generation.
|
|
110
|
+
*/
|
|
111
|
+
export interface StreamTextOptions {
|
|
112
|
+
/** System prompt */
|
|
113
|
+
system?: string;
|
|
114
|
+
/** Conversation messages */
|
|
115
|
+
messages: UIMessage[];
|
|
116
|
+
/** Temperature (0-1). Default: 0.7 */
|
|
117
|
+
temperature?: number;
|
|
118
|
+
/** Maximum output tokens */
|
|
119
|
+
maxOutputTokens?: number;
|
|
120
|
+
/** Top-p sampling */
|
|
121
|
+
topP?: number;
|
|
122
|
+
/** Abort signal for cancellation */
|
|
123
|
+
abortSignal?: AbortSignal;
|
|
124
|
+
/** Language for mock responses (zh/en) */
|
|
125
|
+
lang?: string;
|
|
126
|
+
/** User question (for mock responses) */
|
|
127
|
+
userQuestion?: string;
|
|
128
|
+
/** Callback for errors during streaming */
|
|
129
|
+
onError?: (error: Error) => void;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Result from streamText operation.
|
|
133
|
+
* Compatible with AI SDK's streamText result.
|
|
134
|
+
*/
|
|
135
|
+
export interface StreamTextResult {
|
|
136
|
+
/** Convert to UI Message Stream Response for AI SDK v6 */
|
|
137
|
+
toUIMessageStreamResponse: (options?: {
|
|
138
|
+
headers?: HeadersInit;
|
|
139
|
+
}) => Response;
|
|
140
|
+
/** The text content (for non-streaming usage) */
|
|
141
|
+
text?: Promise<string>;
|
|
142
|
+
/** Provider ID that handled the request */
|
|
143
|
+
providerId: string;
|
|
144
|
+
/** Whether this is a mock response */
|
|
145
|
+
isMock: boolean;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Result from provider health check.
|
|
149
|
+
*/
|
|
150
|
+
export interface HealthCheckResult {
|
|
151
|
+
providerId: string;
|
|
152
|
+
healthy: boolean;
|
|
153
|
+
latency?: number;
|
|
154
|
+
error?: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Options for creating a ProviderManager.
|
|
158
|
+
*/
|
|
159
|
+
export interface ProviderManagerOptions {
|
|
160
|
+
/** Number of consecutive failures before marking unhealthy. Default: 3 */
|
|
161
|
+
unhealthyThreshold?: number;
|
|
162
|
+
/** Time in ms before retrying an unhealthy provider. Default: 60000 (1 min) */
|
|
163
|
+
healthRecoveryTTL?: number;
|
|
164
|
+
/** Enable mock provider as final fallback. Default: true */
|
|
165
|
+
enableMockFallback?: boolean;
|
|
166
|
+
/** Callback when provider switch occurs */
|
|
167
|
+
onProviderSwitch?: (fromId: string | null, toId: string, reason: string) => void;
|
|
168
|
+
/** Callback when streaming error occurs */
|
|
169
|
+
onStreamError?: (providerId: string, error: Error) => void;
|
|
170
|
+
/** Callback when health status changes */
|
|
171
|
+
onHealthChange?: (providerId: string, healthy: boolean) => void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Abstract interface for provider adapters.
|
|
175
|
+
* All provider types must implement this interface.
|
|
176
|
+
*/
|
|
177
|
+
export interface ProviderAdapter {
|
|
178
|
+
/** Provider identifier */
|
|
179
|
+
readonly id: string;
|
|
180
|
+
/** Provider type */
|
|
181
|
+
readonly type: 'openai' | 'workers' | 'mock';
|
|
182
|
+
/** Priority weight */
|
|
183
|
+
readonly weight: number;
|
|
184
|
+
/** Default model */
|
|
185
|
+
readonly model: string;
|
|
186
|
+
/** Model for keyword extraction */
|
|
187
|
+
readonly keywordModel: string;
|
|
188
|
+
/** Model for evidence analysis */
|
|
189
|
+
readonly evidenceModel: string;
|
|
190
|
+
/** Request timeout in ms */
|
|
191
|
+
readonly timeout: number;
|
|
192
|
+
/**
|
|
193
|
+
* Check if this provider is currently available and healthy.
|
|
194
|
+
*/
|
|
195
|
+
isAvailable(): Promise<boolean>;
|
|
196
|
+
/**
|
|
197
|
+
* Stream text generation.
|
|
198
|
+
*/
|
|
199
|
+
streamText(options: StreamTextOptions): Promise<StreamTextResult>;
|
|
200
|
+
/**
|
|
201
|
+
* Get current health status.
|
|
202
|
+
*/
|
|
203
|
+
getHealth(): ProviderHealth;
|
|
204
|
+
/**
|
|
205
|
+
* Record a successful request.
|
|
206
|
+
*/
|
|
207
|
+
recordSuccess(): void;
|
|
208
|
+
/**
|
|
209
|
+
* Record a failed request.
|
|
210
|
+
*/
|
|
211
|
+
recordFailure(error: Error): void;
|
|
212
|
+
getProvider(): {
|
|
213
|
+
chatModel: (model: string) => unknown;
|
|
214
|
+
};
|
|
215
|
+
dispose?(): void;
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/provider-manager/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WorkersAIProviderConfig, StreamTextOptions, StreamTextResult, ProviderManagerEnv } from './types.js';
|
|
2
|
+
import { BaseProviderAdapter } from './base.js';
|
|
3
|
+
export declare class WorkersAIAdapter extends BaseProviderAdapter {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly type: "workers";
|
|
6
|
+
readonly weight: number;
|
|
7
|
+
readonly model: string;
|
|
8
|
+
readonly keywordModel: string;
|
|
9
|
+
readonly evidenceModel: string;
|
|
10
|
+
readonly timeout: number;
|
|
11
|
+
private provider;
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config: WorkersAIProviderConfig, env: ProviderManagerEnv);
|
|
14
|
+
streamText(options: StreamTextOptions): Promise<StreamTextResult>;
|
|
15
|
+
getConfig(): WorkersAIProviderConfig;
|
|
16
|
+
getProvider(): {
|
|
17
|
+
chatModel: (model: string) => unknown;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=workers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../src/provider-manager/workers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACnH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAU;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAGzB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,MAAM,CAA0B;gBAE5B,MAAM,EAAE,uBAAuB,EAAE,GAAG,EAAE,kBAAkB;IAqB9D,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyCvE,SAAS,IAAI,uBAAuB;IAIpC,WAAW,IAAI;QAAE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAA;KAAE;CAKzD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createWorkersAI } from 'workers-ai-provider';
|
|
2
|
+
import { streamText, convertToModelMessages } from 'ai';
|
|
3
|
+
import { BaseProviderAdapter } from './base.js';
|
|
4
|
+
export class WorkersAIAdapter extends BaseProviderAdapter {
|
|
5
|
+
id;
|
|
6
|
+
type = 'workers';
|
|
7
|
+
weight;
|
|
8
|
+
model;
|
|
9
|
+
keywordModel;
|
|
10
|
+
evidenceModel;
|
|
11
|
+
timeout;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
provider;
|
|
14
|
+
config;
|
|
15
|
+
constructor(config, env) {
|
|
16
|
+
super({
|
|
17
|
+
unhealthyThreshold: config.maxRetries ? config.maxRetries + 2 : 3,
|
|
18
|
+
});
|
|
19
|
+
this.id = config.id;
|
|
20
|
+
this.weight = config.weight ?? 90;
|
|
21
|
+
this.model = config.model;
|
|
22
|
+
this.keywordModel = config.keywordModel ?? config.model;
|
|
23
|
+
this.evidenceModel = config.evidenceModel ?? this.keywordModel;
|
|
24
|
+
this.timeout = config.timeout ?? 30000;
|
|
25
|
+
this.config = config;
|
|
26
|
+
const binding = env[config.bindingName];
|
|
27
|
+
if (!binding) {
|
|
28
|
+
throw new Error(`Workers AI binding '${config.bindingName}' not found in environment`);
|
|
29
|
+
}
|
|
30
|
+
this.provider = createWorkersAI({ binding: binding });
|
|
31
|
+
}
|
|
32
|
+
async streamText(options) {
|
|
33
|
+
const { system, messages, temperature = 0.7, maxOutputTokens, topP, abortSignal, onError } = options;
|
|
34
|
+
const abortController = new AbortController();
|
|
35
|
+
const timeoutId = setTimeout(() => abortController.abort(), this.timeout);
|
|
36
|
+
if (abortSignal) {
|
|
37
|
+
abortSignal.addEventListener('abort', () => abortController.abort());
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const model = this.provider(this.model, { safePrompt: true });
|
|
41
|
+
const result = streamText({
|
|
42
|
+
model,
|
|
43
|
+
system,
|
|
44
|
+
messages: await convertToModelMessages(messages),
|
|
45
|
+
temperature,
|
|
46
|
+
maxOutputTokens,
|
|
47
|
+
topP,
|
|
48
|
+
abortSignal: abortController.signal,
|
|
49
|
+
onError: ({ error }) => {
|
|
50
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const streamResult = {
|
|
54
|
+
toUIMessageStreamResponse: (responseOptions) => result.toUIMessageStreamResponse(responseOptions),
|
|
55
|
+
providerId: this.id,
|
|
56
|
+
isMock: false,
|
|
57
|
+
};
|
|
58
|
+
clearTimeout(timeoutId);
|
|
59
|
+
return streamResult;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
getConfig() {
|
|
67
|
+
return { ...this.config };
|
|
68
|
+
}
|
|
69
|
+
getProvider() {
|
|
70
|
+
return {
|
|
71
|
+
chatModel: (modelId) => this.provider(modelId, { safePrompt: true }),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|