@nahisaho/katashiro-llm 2.0.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/LICENSE +21 -0
- package/dist/LLMClient.d.ts +64 -0
- package/dist/LLMClient.d.ts.map +1 -0
- package/dist/LLMClient.js +139 -0
- package/dist/LLMClient.js.map +1 -0
- package/dist/PromptManager.d.ts +66 -0
- package/dist/PromptManager.d.ts.map +1 -0
- package/dist/PromptManager.js +121 -0
- package/dist/PromptManager.js.map +1 -0
- package/dist/TokenCounter.d.ts +43 -0
- package/dist/TokenCounter.d.ts.map +1 -0
- package/dist/TokenCounter.js +100 -0
- package/dist/TokenCounter.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/AzureOpenAILLMProvider.d.ts +82 -0
- package/dist/providers/AzureOpenAILLMProvider.d.ts.map +1 -0
- package/dist/providers/AzureOpenAILLMProvider.js +339 -0
- package/dist/providers/AzureOpenAILLMProvider.js.map +1 -0
- package/dist/providers/BaseLLMProvider.d.ts +51 -0
- package/dist/providers/BaseLLMProvider.d.ts.map +1 -0
- package/dist/providers/BaseLLMProvider.js +72 -0
- package/dist/providers/BaseLLMProvider.js.map +1 -0
- package/dist/providers/LLMFactory.d.ts +75 -0
- package/dist/providers/LLMFactory.d.ts.map +1 -0
- package/dist/providers/LLMFactory.js +149 -0
- package/dist/providers/LLMFactory.js.map +1 -0
- package/dist/providers/MockLLMProvider.d.ts +57 -0
- package/dist/providers/MockLLMProvider.d.ts.map +1 -0
- package/dist/providers/MockLLMProvider.js +120 -0
- package/dist/providers/MockLLMProvider.js.map +1 -0
- package/dist/providers/OllamaLLMProvider.d.ts +73 -0
- package/dist/providers/OllamaLLMProvider.d.ts.map +1 -0
- package/dist/providers/OllamaLLMProvider.js +242 -0
- package/dist/providers/OllamaLLMProvider.js.map +1 -0
- package/dist/providers/OpenAILLMProvider.d.ts +87 -0
- package/dist/providers/OpenAILLMProvider.d.ts.map +1 -0
- package/dist/providers/OpenAILLMProvider.js +349 -0
- package/dist/providers/OpenAILLMProvider.js.map +1 -0
- package/dist/providers/index.d.ts +17 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/types.d.ts +251 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
- package/src/LLMClient.ts +171 -0
- package/src/PromptManager.ts +156 -0
- package/src/TokenCounter.ts +114 -0
- package/src/index.ts +35 -0
- package/src/providers/AzureOpenAILLMProvider.ts +494 -0
- package/src/providers/BaseLLMProvider.ts +110 -0
- package/src/providers/LLMFactory.ts +216 -0
- package/src/providers/MockLLMProvider.ts +173 -0
- package/src/providers/OllamaLLMProvider.ts +322 -0
- package/src/providers/OpenAILLMProvider.ts +500 -0
- package/src/providers/index.ts +35 -0
- package/src/types.ts +268 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Package Types
|
|
3
|
+
*
|
|
4
|
+
* @requirement REQ-LLM-001, REQ-LLM-005, REQ-LLM-006
|
|
5
|
+
* @design DES-KATASHIRO-003-LLM §3.1
|
|
6
|
+
*/
|
|
7
|
+
import type { ZodType, z } from 'zod';
|
|
8
|
+
/**
|
|
9
|
+
* メッセージロール
|
|
10
|
+
*/
|
|
11
|
+
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
12
|
+
/**
|
|
13
|
+
* コンテンツパート(マルチモーダル対応)
|
|
14
|
+
*/
|
|
15
|
+
export type ContentPart = {
|
|
16
|
+
type: 'text';
|
|
17
|
+
text: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'image_url';
|
|
20
|
+
image_url: {
|
|
21
|
+
url: string;
|
|
22
|
+
detail?: 'auto' | 'low' | 'high';
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* ツール呼び出し
|
|
27
|
+
*/
|
|
28
|
+
export interface ToolCall {
|
|
29
|
+
id: string;
|
|
30
|
+
type: 'function';
|
|
31
|
+
function: {
|
|
32
|
+
name: string;
|
|
33
|
+
arguments: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* ツール定義
|
|
38
|
+
*/
|
|
39
|
+
export interface ToolDefinition {
|
|
40
|
+
type: 'function';
|
|
41
|
+
function: {
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
parameters: Record<string, unknown>;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* メッセージ
|
|
49
|
+
*/
|
|
50
|
+
export interface Message {
|
|
51
|
+
role: MessageRole;
|
|
52
|
+
content: string | ContentPart[];
|
|
53
|
+
name?: string;
|
|
54
|
+
toolCallId?: string;
|
|
55
|
+
toolCalls?: ToolCall[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* ツール選択オプション
|
|
59
|
+
*/
|
|
60
|
+
export type ToolChoice = 'auto' | 'none' | 'required' | {
|
|
61
|
+
type: 'function';
|
|
62
|
+
function: {
|
|
63
|
+
name: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* レスポンスフォーマット
|
|
68
|
+
*/
|
|
69
|
+
export interface ResponseFormat {
|
|
70
|
+
type: 'text' | 'json_object';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 生成リクエスト
|
|
74
|
+
*/
|
|
75
|
+
export interface GenerateRequest {
|
|
76
|
+
/** モデル名 */
|
|
77
|
+
model?: string;
|
|
78
|
+
/** メッセージ履歴 */
|
|
79
|
+
messages: Message[];
|
|
80
|
+
/** 温度パラメータ (0-2) */
|
|
81
|
+
temperature?: number;
|
|
82
|
+
/** 最大トークン数 */
|
|
83
|
+
maxTokens?: number;
|
|
84
|
+
/** Top-P サンプリング */
|
|
85
|
+
topP?: number;
|
|
86
|
+
/** 停止シーケンス */
|
|
87
|
+
stopSequences?: string[];
|
|
88
|
+
/** ツール定義 */
|
|
89
|
+
tools?: ToolDefinition[];
|
|
90
|
+
/** ツール選択 */
|
|
91
|
+
toolChoice?: ToolChoice;
|
|
92
|
+
/** レスポンスフォーマット */
|
|
93
|
+
responseFormat?: ResponseFormat;
|
|
94
|
+
/** ユーザーID(監査用) */
|
|
95
|
+
user?: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* トークン使用量
|
|
99
|
+
*/
|
|
100
|
+
export interface TokenUsage {
|
|
101
|
+
promptTokens: number;
|
|
102
|
+
completionTokens: number;
|
|
103
|
+
totalTokens: number;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 終了理由
|
|
107
|
+
*/
|
|
108
|
+
export type FinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter';
|
|
109
|
+
/**
|
|
110
|
+
* 生成レスポンス
|
|
111
|
+
*/
|
|
112
|
+
export interface GenerateResponse {
|
|
113
|
+
/** レスポンスID */
|
|
114
|
+
id: string;
|
|
115
|
+
/** 使用モデル */
|
|
116
|
+
model: string;
|
|
117
|
+
/** 生成テキスト */
|
|
118
|
+
content: string;
|
|
119
|
+
/** ツール呼び出し */
|
|
120
|
+
toolCalls?: ToolCall[];
|
|
121
|
+
/** トークン使用量 */
|
|
122
|
+
usage: TokenUsage;
|
|
123
|
+
/** 終了理由 */
|
|
124
|
+
finishReason: FinishReason;
|
|
125
|
+
/** メタデータ */
|
|
126
|
+
metadata?: Record<string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* ストリームチャンク
|
|
130
|
+
*/
|
|
131
|
+
export interface StreamChunk {
|
|
132
|
+
type: 'content' | 'tool_call' | 'usage' | 'done';
|
|
133
|
+
content?: string;
|
|
134
|
+
toolCall?: Partial<ToolCall>;
|
|
135
|
+
usage?: TokenUsage;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* LLMプロバイダーインターフェース
|
|
139
|
+
*/
|
|
140
|
+
export interface LLMProvider {
|
|
141
|
+
/** プロバイダー名 */
|
|
142
|
+
readonly name: string;
|
|
143
|
+
/** サポートモデル */
|
|
144
|
+
readonly supportedModels: string[];
|
|
145
|
+
/**
|
|
146
|
+
* テキスト生成
|
|
147
|
+
*/
|
|
148
|
+
generate(request: GenerateRequest): Promise<GenerateResponse>;
|
|
149
|
+
/**
|
|
150
|
+
* ストリーミング生成
|
|
151
|
+
*/
|
|
152
|
+
generateStream(request: GenerateRequest): AsyncGenerator<StreamChunk>;
|
|
153
|
+
/**
|
|
154
|
+
* 構造化出力生成
|
|
155
|
+
*/
|
|
156
|
+
generateStructured<T extends ZodType>(request: GenerateRequest, schema: T): Promise<z.infer<T>>;
|
|
157
|
+
/**
|
|
158
|
+
* トークン数カウント
|
|
159
|
+
*/
|
|
160
|
+
countTokens(text: string, model?: string): Promise<number>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* プロバイダー設定
|
|
164
|
+
*/
|
|
165
|
+
export interface ProviderConfig {
|
|
166
|
+
/** APIキー */
|
|
167
|
+
apiKey?: string;
|
|
168
|
+
/** ベースURL */
|
|
169
|
+
baseURL?: string;
|
|
170
|
+
/** デフォルトモデル */
|
|
171
|
+
defaultModel?: string;
|
|
172
|
+
/** タイムアウト(ミリ秒) */
|
|
173
|
+
timeout?: number;
|
|
174
|
+
/** 最大リトライ回数 */
|
|
175
|
+
maxRetries?: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* LLMクライアント設定
|
|
179
|
+
*/
|
|
180
|
+
export interface LLMClientConfig {
|
|
181
|
+
/** プライマリプロバイダー */
|
|
182
|
+
provider: LLMProvider;
|
|
183
|
+
/** フォールバックプロバイダー */
|
|
184
|
+
fallbackProviders?: LLMProvider[];
|
|
185
|
+
/** セマンティックキャッシュ有効化 */
|
|
186
|
+
enableCache?: boolean;
|
|
187
|
+
/** キャッシュTTL(ミリ秒) */
|
|
188
|
+
cacheTTL?: number;
|
|
189
|
+
/** 自動リトライ有効化 */
|
|
190
|
+
enableRetry?: boolean;
|
|
191
|
+
/** リトライ回数 */
|
|
192
|
+
retryCount?: number;
|
|
193
|
+
/** リトライ遅延(ミリ秒) */
|
|
194
|
+
retryDelay?: number;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* プロンプトテンプレート
|
|
198
|
+
*/
|
|
199
|
+
export interface PromptTemplate {
|
|
200
|
+
/** テンプレートID */
|
|
201
|
+
id: string;
|
|
202
|
+
/** テンプレート名 */
|
|
203
|
+
name: string;
|
|
204
|
+
/** テンプレート内容 */
|
|
205
|
+
template: string;
|
|
206
|
+
/** 変数定義 */
|
|
207
|
+
variables: Array<{
|
|
208
|
+
name: string;
|
|
209
|
+
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
210
|
+
required?: boolean;
|
|
211
|
+
default?: unknown;
|
|
212
|
+
description?: string;
|
|
213
|
+
}>;
|
|
214
|
+
/** 説明 */
|
|
215
|
+
description?: string;
|
|
216
|
+
/** メタデータ */
|
|
217
|
+
metadata?: Record<string, unknown>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* キャッシュエントリ
|
|
221
|
+
*/
|
|
222
|
+
export interface CacheEntry<T = GenerateResponse> {
|
|
223
|
+
/** キー(ハッシュ) */
|
|
224
|
+
key: string;
|
|
225
|
+
/** 値 */
|
|
226
|
+
value: T;
|
|
227
|
+
/** 作成日時 */
|
|
228
|
+
createdAt: Date;
|
|
229
|
+
/** 有効期限 */
|
|
230
|
+
expiresAt: Date;
|
|
231
|
+
/** ヒット数 */
|
|
232
|
+
hits: number;
|
|
233
|
+
/** 類似度スコア(セマンティックキャッシュ用) */
|
|
234
|
+
similarity?: number;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* フォールバック結果
|
|
238
|
+
*/
|
|
239
|
+
export interface FallbackResult {
|
|
240
|
+
/** 成功プロバイダー */
|
|
241
|
+
provider: string;
|
|
242
|
+
/** 試行プロバイダー */
|
|
243
|
+
attemptedProviders: string[];
|
|
244
|
+
/** エラー履歴 */
|
|
245
|
+
errors: Array<{
|
|
246
|
+
provider: string;
|
|
247
|
+
error: Error;
|
|
248
|
+
timestamp: Date;
|
|
249
|
+
}>;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nahisaho/katashiro-llm",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "LLM Provider abstraction for KATASHIRO",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"zod": "^3.23.8",
|
|
20
|
+
"@nahisaho/katashiro-core": "2.0.0",
|
|
21
|
+
"@nahisaho/katashiro-observability": "2.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.6.3",
|
|
25
|
+
"vitest": "^3.0.0",
|
|
26
|
+
"@types/node": "^22.10.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"openai": "^4.0.0",
|
|
30
|
+
"@anthropic-ai/sdk": "^0.30.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"openai": {
|
|
34
|
+
"optional": true
|
|
35
|
+
},
|
|
36
|
+
"@anthropic-ai/sdk": {
|
|
37
|
+
"optional": true
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"author": "nahisaho",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:watch": "vitest",
|
|
49
|
+
"clean": "rm -rf dist"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/LLMClient.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Client - マルチプロバイダーファサード
|
|
3
|
+
*
|
|
4
|
+
* @requirement REQ-LLM-001, REQ-LLM-004
|
|
5
|
+
* @design DES-KATASHIRO-003-LLM §3.4
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ZodType, z } from 'zod';
|
|
9
|
+
import type {
|
|
10
|
+
LLMProvider,
|
|
11
|
+
LLMClientConfig,
|
|
12
|
+
GenerateRequest,
|
|
13
|
+
GenerateResponse,
|
|
14
|
+
StreamChunk,
|
|
15
|
+
FallbackResult,
|
|
16
|
+
} from './types.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* LLMクライアント
|
|
20
|
+
*
|
|
21
|
+
* フォールバック機能とリトライ機能を提供するファサードクラス
|
|
22
|
+
*/
|
|
23
|
+
export class LLMClient {
|
|
24
|
+
private primaryProvider: LLMProvider;
|
|
25
|
+
private fallbackProviders: LLMProvider[];
|
|
26
|
+
private retryCount: number;
|
|
27
|
+
private retryDelay: number;
|
|
28
|
+
|
|
29
|
+
constructor(config: LLMClientConfig) {
|
|
30
|
+
this.primaryProvider = config.provider;
|
|
31
|
+
this.fallbackProviders = config.fallbackProviders ?? [];
|
|
32
|
+
this.retryCount = config.enableRetry !== false ? (config.retryCount ?? 3) : 0;
|
|
33
|
+
this.retryDelay = config.retryDelay ?? 1000;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* テキスト生成(フォールバック対応)
|
|
38
|
+
*/
|
|
39
|
+
async generate(request: GenerateRequest): Promise<GenerateResponse & { _fallback?: FallbackResult }> {
|
|
40
|
+
const providers = [this.primaryProvider, ...this.fallbackProviders];
|
|
41
|
+
const errors: FallbackResult['errors'] = [];
|
|
42
|
+
|
|
43
|
+
for (const provider of providers) {
|
|
44
|
+
try {
|
|
45
|
+
const response = await this.withRetry(() => provider.generate(request));
|
|
46
|
+
return {
|
|
47
|
+
...response,
|
|
48
|
+
_fallback: errors.length > 0 ? {
|
|
49
|
+
provider: provider.name,
|
|
50
|
+
attemptedProviders: errors.map((e) => e.provider),
|
|
51
|
+
errors,
|
|
52
|
+
} : undefined,
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
errors.push({
|
|
56
|
+
provider: provider.name,
|
|
57
|
+
error: error as Error,
|
|
58
|
+
timestamp: new Date(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// すべてのプロバイダーが失敗
|
|
64
|
+
throw new AggregateError(
|
|
65
|
+
errors.map((e) => e.error),
|
|
66
|
+
`All LLM providers failed: ${errors.map((e) => e.provider).join(', ')}`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* ストリーミング生成
|
|
72
|
+
*/
|
|
73
|
+
async *generateStream(request: GenerateRequest): AsyncGenerator<StreamChunk> {
|
|
74
|
+
const providers = [this.primaryProvider, ...this.fallbackProviders];
|
|
75
|
+
const errors: Error[] = [];
|
|
76
|
+
|
|
77
|
+
for (const provider of providers) {
|
|
78
|
+
try {
|
|
79
|
+
yield* provider.generateStream(request);
|
|
80
|
+
return;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
errors.push(error as Error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw new AggregateError(errors, 'All LLM providers failed for streaming');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 構造化出力生成
|
|
91
|
+
*/
|
|
92
|
+
async generateStructured<T extends ZodType>(
|
|
93
|
+
request: GenerateRequest,
|
|
94
|
+
schema: T
|
|
95
|
+
): Promise<z.infer<T>> {
|
|
96
|
+
return this.primaryProvider.generateStructured(request, schema);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* トークン数カウント
|
|
101
|
+
*/
|
|
102
|
+
async countTokens(text: string, model?: string): Promise<number> {
|
|
103
|
+
return this.primaryProvider.countTokens(text, model);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* プライマリプロバイダー取得
|
|
108
|
+
*/
|
|
109
|
+
getProvider(): LLMProvider {
|
|
110
|
+
return this.primaryProvider;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* プロバイダー一覧取得
|
|
115
|
+
*/
|
|
116
|
+
getProviders(): LLMProvider[] {
|
|
117
|
+
return [this.primaryProvider, ...this.fallbackProviders];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* リトライラッパー
|
|
122
|
+
*/
|
|
123
|
+
private async withRetry<T>(fn: () => Promise<T>): Promise<T> {
|
|
124
|
+
let lastError: Error | undefined;
|
|
125
|
+
|
|
126
|
+
for (let attempt = 0; attempt <= this.retryCount; attempt++) {
|
|
127
|
+
try {
|
|
128
|
+
return await fn();
|
|
129
|
+
} catch (error) {
|
|
130
|
+
lastError = error as Error;
|
|
131
|
+
if (attempt < this.retryCount) {
|
|
132
|
+
await this.sleep(this.retryDelay * Math.pow(2, attempt));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
throw lastError;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private sleep(ms: number): Promise<void> {
|
|
141
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// シングルトン管理
|
|
146
|
+
let defaultClient: LLMClient | null = null;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* デフォルトLLMクライアント取得
|
|
150
|
+
*/
|
|
151
|
+
export function getLLMClient(): LLMClient {
|
|
152
|
+
if (!defaultClient) {
|
|
153
|
+
throw new Error('LLM client not initialized. Call initLLMClient() first.');
|
|
154
|
+
}
|
|
155
|
+
return defaultClient;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* LLMクライアント初期化
|
|
160
|
+
*/
|
|
161
|
+
export function initLLMClient(config: LLMClientConfig): LLMClient {
|
|
162
|
+
defaultClient = new LLMClient(config);
|
|
163
|
+
return defaultClient;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* LLMクライアントリセット(テスト用)
|
|
168
|
+
*/
|
|
169
|
+
export function resetLLMClient(): void {
|
|
170
|
+
defaultClient = null;
|
|
171
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Manager - プロンプトテンプレート管理
|
|
3
|
+
*
|
|
4
|
+
* @requirement REQ-LLM-002
|
|
5
|
+
* @design DES-KATASHIRO-003-LLM §3.2
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { PromptTemplate, Message } from './types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* テンプレート変数
|
|
12
|
+
*/
|
|
13
|
+
export type TemplateVariables = Record<string, unknown>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* PromptManager - プロンプトテンプレート管理
|
|
17
|
+
*/
|
|
18
|
+
export class PromptManager {
|
|
19
|
+
private templates: Map<string, PromptTemplate> = new Map();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* テンプレート登録
|
|
23
|
+
*/
|
|
24
|
+
register(template: PromptTemplate): void {
|
|
25
|
+
this.templates.set(template.id, template);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* テンプレート取得
|
|
30
|
+
*/
|
|
31
|
+
get(id: string): PromptTemplate | undefined {
|
|
32
|
+
return this.templates.get(id);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* テンプレート一覧取得
|
|
37
|
+
*/
|
|
38
|
+
list(): PromptTemplate[] {
|
|
39
|
+
return Array.from(this.templates.values());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* テンプレート削除
|
|
44
|
+
*/
|
|
45
|
+
unregister(id: string): boolean {
|
|
46
|
+
return this.templates.delete(id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* テンプレートをレンダリング
|
|
51
|
+
*/
|
|
52
|
+
render(id: string, variables: TemplateVariables = {}): string {
|
|
53
|
+
const template = this.templates.get(id);
|
|
54
|
+
if (!template) {
|
|
55
|
+
throw new Error(`Template not found: ${id}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return this.renderTemplate(template, variables);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* テンプレートをメッセージとしてレンダリング
|
|
63
|
+
*/
|
|
64
|
+
renderAsMessage(
|
|
65
|
+
id: string,
|
|
66
|
+
variables: TemplateVariables = {},
|
|
67
|
+
role: Message['role'] = 'user'
|
|
68
|
+
): Message {
|
|
69
|
+
const content = this.render(id, variables);
|
|
70
|
+
return { role, content };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 複数テンプレートをチェーン
|
|
75
|
+
*/
|
|
76
|
+
chain(
|
|
77
|
+
templateIds: string[],
|
|
78
|
+
variables: TemplateVariables = {},
|
|
79
|
+
separator = '\n\n'
|
|
80
|
+
): string {
|
|
81
|
+
return templateIds
|
|
82
|
+
.map((id) => this.render(id, variables))
|
|
83
|
+
.join(separator);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* テンプレート文字列をレンダリング(直接)
|
|
88
|
+
*/
|
|
89
|
+
renderString(template: string, variables: TemplateVariables = {}): string {
|
|
90
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
91
|
+
const value = variables[key];
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
return `{{${key}}}`;
|
|
94
|
+
}
|
|
95
|
+
return String(value);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* テンプレートをレンダリング(内部)
|
|
101
|
+
*/
|
|
102
|
+
private renderTemplate(
|
|
103
|
+
template: PromptTemplate,
|
|
104
|
+
variables: TemplateVariables
|
|
105
|
+
): string {
|
|
106
|
+
// 必須変数のチェック
|
|
107
|
+
for (const varDef of template.variables) {
|
|
108
|
+
if (varDef.required && variables[varDef.name] === undefined) {
|
|
109
|
+
if (varDef.default !== undefined) {
|
|
110
|
+
variables[varDef.name] = varDef.default;
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Missing required variable: ${varDef.name} for template: ${template.id}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// デフォルト値の適用
|
|
120
|
+
for (const varDef of template.variables) {
|
|
121
|
+
if (variables[varDef.name] === undefined && varDef.default !== undefined) {
|
|
122
|
+
variables[varDef.name] = varDef.default;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// テンプレートのレンダリング
|
|
127
|
+
return this.renderString(template.template, variables);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* クリア
|
|
132
|
+
*/
|
|
133
|
+
clear(): void {
|
|
134
|
+
this.templates.clear();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// シングルトン
|
|
139
|
+
let promptManagerInstance: PromptManager | null = null;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* PromptManager シングルトン取得
|
|
143
|
+
*/
|
|
144
|
+
export function getPromptManager(): PromptManager {
|
|
145
|
+
if (!promptManagerInstance) {
|
|
146
|
+
promptManagerInstance = new PromptManager();
|
|
147
|
+
}
|
|
148
|
+
return promptManagerInstance;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* PromptManager リセット(テスト用)
|
|
153
|
+
*/
|
|
154
|
+
export function resetPromptManager(): void {
|
|
155
|
+
promptManagerInstance = null;
|
|
156
|
+
}
|