@hyperfixi/patterns-reference 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.
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Unified LLM Adapter
3
+ *
4
+ * This adapter provides a unified interface for LLM example operations,
5
+ * supporting both sync and async access patterns for backward compatibility
6
+ * with packages/core/src/context/llm-examples-query.ts.
7
+ *
8
+ * @module @hyperfixi/patterns-reference/adapters/llm-adapter
9
+ */
10
+
11
+ import { getDatabase, closeDatabase } from '../database/connection';
12
+ import type { LLMExample, ConnectionOptions } from '../types';
13
+ import {
14
+ getLLMExamples,
15
+ getExamplesByCommand,
16
+ getHighQualityExamples,
17
+ getMostUsedExamples,
18
+ buildFewShotContext,
19
+ getLLMStats,
20
+ } from '../api/llm';
21
+
22
+ // =============================================================================
23
+ // Sync Interface (Backward Compatibility)
24
+ // =============================================================================
25
+
26
+ /**
27
+ * Legacy record type matching packages/core/src/context/llm-examples-query.ts
28
+ */
29
+ export interface LLMExampleRecord {
30
+ id: number;
31
+ prompt: string;
32
+ completion: string;
33
+ language: string;
34
+ qualityScore: number;
35
+ }
36
+
37
+ /**
38
+ * Database row type for internal use
39
+ */
40
+ interface LLMExampleRow {
41
+ id: number;
42
+ code_example_id: string;
43
+ language: string;
44
+ prompt: string;
45
+ completion: string;
46
+ quality_score: number;
47
+ usage_count: number;
48
+ created_at: string;
49
+ }
50
+
51
+ // State for sync operations
52
+ let syncDatabaseAvailable = true;
53
+
54
+ /**
55
+ * Check if the database is available for sync operations.
56
+ */
57
+ export function isDatabaseAvailable(): boolean {
58
+ try {
59
+ getDatabase({ readonly: true });
60
+ return true;
61
+ } catch {
62
+ syncDatabaseAvailable = false;
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Find relevant examples (sync interface - matches llm-examples-query.ts).
69
+ *
70
+ * This is the synchronous version for backward compatibility.
71
+ * Prefer async getLLMExamples() for new code.
72
+ *
73
+ * @param prompt - The user's request/prompt
74
+ * @param language - Target language code (default: 'en')
75
+ * @param limit - Maximum number of examples to return (default: 5)
76
+ */
77
+ export function findRelevantExamples(
78
+ prompt: string,
79
+ language: string = 'en',
80
+ limit: number = 5
81
+ ): LLMExampleRecord[] {
82
+ if (!syncDatabaseAvailable) return [];
83
+
84
+ try {
85
+ const db = getDatabase({ readonly: true });
86
+
87
+ // Extract keywords from prompt
88
+ const keywords = extractKeywords(prompt);
89
+
90
+ if (keywords.length === 0) {
91
+ // Return top-quality examples as fallback
92
+ const rows = db
93
+ .prepare(
94
+ `
95
+ SELECT id, prompt, completion, language, quality_score as qualityScore
96
+ FROM llm_examples
97
+ WHERE language = ?
98
+ ORDER BY quality_score DESC, usage_count DESC
99
+ LIMIT ?
100
+ `
101
+ )
102
+ .all(language, limit) as LLMExampleRecord[];
103
+
104
+ trackUsageSync(
105
+ db,
106
+ rows.map(r => r.id)
107
+ );
108
+ return rows;
109
+ }
110
+
111
+ // Build LIKE clauses for keyword matching
112
+ const likeClauses = keywords.map(() => '(prompt LIKE ? OR completion LIKE ?)').join(' OR ');
113
+ const params = keywords.flatMap(k => [`%${k}%`, `%${k}%`]);
114
+
115
+ const rows = db
116
+ .prepare(
117
+ `
118
+ SELECT id, prompt, completion, language, quality_score as qualityScore
119
+ FROM llm_examples
120
+ WHERE language = ? AND (${likeClauses})
121
+ ORDER BY quality_score DESC
122
+ LIMIT ?
123
+ `
124
+ )
125
+ .all(language, ...params, limit) as LLMExampleRecord[];
126
+
127
+ trackUsageSync(
128
+ db,
129
+ rows.map(r => r.id)
130
+ );
131
+ return rows;
132
+ } catch (error) {
133
+ console.warn(
134
+ '[LLM Adapter] Query failed:',
135
+ error instanceof Error ? error.message : String(error)
136
+ );
137
+ syncDatabaseAvailable = false;
138
+ return [];
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Find examples by command type (sync interface).
144
+ */
145
+ export function findExamplesByCommand(
146
+ command: string,
147
+ language: string = 'en',
148
+ limit: number = 5
149
+ ): LLMExampleRecord[] {
150
+ if (!syncDatabaseAvailable) return [];
151
+
152
+ try {
153
+ const db = getDatabase({ readonly: true });
154
+
155
+ const rows = db
156
+ .prepare(
157
+ `
158
+ SELECT id, prompt, completion, language, quality_score as qualityScore
159
+ FROM llm_examples
160
+ WHERE language = ? AND completion LIKE ?
161
+ ORDER BY quality_score DESC
162
+ LIMIT ?
163
+ `
164
+ )
165
+ .all(language, `%${command}%`, limit) as LLMExampleRecord[];
166
+
167
+ return rows;
168
+ } catch (error) {
169
+ console.warn(
170
+ '[LLM Adapter] Query failed:',
171
+ error instanceof Error ? error.message : String(error)
172
+ );
173
+ return [];
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Build few-shot context (sync interface).
179
+ */
180
+ export function buildFewShotContextSync(
181
+ prompt: string,
182
+ language: string = 'en',
183
+ numExamples: number = 3
184
+ ): string {
185
+ const examples = findRelevantExamples(prompt, language, numExamples);
186
+
187
+ if (examples.length === 0) {
188
+ return '';
189
+ }
190
+
191
+ let context = 'Here are some example hyperscript patterns:\n\n';
192
+
193
+ for (const ex of examples) {
194
+ context += `Task: ${ex.prompt}\n`;
195
+ context += `Code: ${ex.completion}\n\n`;
196
+ }
197
+
198
+ context += `Now generate hyperscript for: ${prompt}\n`;
199
+
200
+ return context;
201
+ }
202
+
203
+ /**
204
+ * Track example usage (sync interface).
205
+ */
206
+ export function trackExampleUsage(ids: number[]): void {
207
+ if (!syncDatabaseAvailable || ids.length === 0) return;
208
+
209
+ try {
210
+ const db = getDatabase();
211
+ trackUsageSync(db, ids);
212
+ } catch {
213
+ // Silently ignore tracking errors
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Get LLM example statistics (sync interface).
219
+ */
220
+ export function getLLMExampleStats(): {
221
+ total: number;
222
+ byLanguage: Record<string, number>;
223
+ avgQuality: number;
224
+ } | null {
225
+ if (!syncDatabaseAvailable) return null;
226
+
227
+ try {
228
+ const db = getDatabase({ readonly: true });
229
+
230
+ const totalResult = db.prepare('SELECT COUNT(*) as count FROM llm_examples').get() as {
231
+ count: number;
232
+ };
233
+
234
+ const byLangResult = db
235
+ .prepare(
236
+ `
237
+ SELECT language, COUNT(*) as count
238
+ FROM llm_examples
239
+ GROUP BY language
240
+ `
241
+ )
242
+ .all() as { language: string; count: number }[];
243
+
244
+ const avgResult = db.prepare('SELECT AVG(quality_score) as avg FROM llm_examples').get() as {
245
+ avg: number;
246
+ };
247
+
248
+ const byLanguage: Record<string, number> = {};
249
+ for (const { language, count } of byLangResult) {
250
+ byLanguage[language] = count;
251
+ }
252
+
253
+ return {
254
+ total: totalResult.count,
255
+ byLanguage,
256
+ avgQuality: avgResult.avg || 0,
257
+ };
258
+ } catch {
259
+ return null;
260
+ }
261
+ }
262
+
263
+ // =============================================================================
264
+ // Async Interface Re-exports
265
+ // =============================================================================
266
+
267
+ export {
268
+ // Async versions (preferred for new code)
269
+ getLLMExamples,
270
+ getExamplesByCommand,
271
+ getHighQualityExamples,
272
+ getMostUsedExamples,
273
+ buildFewShotContext,
274
+ getLLMStats,
275
+ // Database management
276
+ closeDatabase,
277
+ };
278
+
279
+ // Re-export types
280
+ export type { LLMExample, ConnectionOptions };
281
+
282
+ // =============================================================================
283
+ // Helper Functions
284
+ // =============================================================================
285
+
286
+ /**
287
+ * Extract keywords from a prompt for matching.
288
+ */
289
+ function extractKeywords(prompt: string): string[] {
290
+ const stopWords = new Set([
291
+ 'a',
292
+ 'an',
293
+ 'the',
294
+ 'to',
295
+ 'on',
296
+ 'in',
297
+ 'for',
298
+ 'is',
299
+ 'it',
300
+ 'when',
301
+ 'i',
302
+ 'want',
303
+ 'need',
304
+ 'create',
305
+ 'make',
306
+ 'please',
307
+ 'can',
308
+ 'you',
309
+ 'would',
310
+ 'should',
311
+ 'like',
312
+ 'that',
313
+ 'this',
314
+ 'with',
315
+ 'from',
316
+ ]);
317
+
318
+ return prompt
319
+ .toLowerCase()
320
+ .split(/\W+/)
321
+ .filter(word => word.length > 2 && !stopWords.has(word));
322
+ }
323
+
324
+ /**
325
+ * Track usage (sync internal helper).
326
+ */
327
+ function trackUsageSync(db: any, ids: number[]): void {
328
+ if (ids.length === 0) return;
329
+
330
+ try {
331
+ const stmt = db.prepare(`
332
+ UPDATE llm_examples SET usage_count = usage_count + 1 WHERE id = ?
333
+ `);
334
+
335
+ for (const id of ids) {
336
+ stmt.run(id);
337
+ }
338
+ } catch {
339
+ // Silently ignore tracking errors
340
+ }
341
+ }
342
+
343
+ // =============================================================================
344
+ // Full-Featured Interface
345
+ // =============================================================================
346
+
347
+ /**
348
+ * Create a unified LLM adapter with both sync and async methods.
349
+ *
350
+ * @example
351
+ * ```typescript
352
+ * import { createLLMAdapter } from '@hyperfixi/patterns-reference/adapters/llm-adapter';
353
+ *
354
+ * const adapter = createLLMAdapter();
355
+ *
356
+ * // Sync (backward compat)
357
+ * const examples = adapter.findRelevantExamples('toggle a class');
358
+ *
359
+ * // Async (preferred)
360
+ * const asyncExamples = await adapter.getLLMExamples('toggle a class');
361
+ *
362
+ * adapter.close();
363
+ * ```
364
+ */
365
+ export function createLLMAdapter(options?: ConnectionOptions) {
366
+ // Initialize database connection
367
+ getDatabase(options);
368
+
369
+ return {
370
+ // Sync methods (backward compatibility with llm-examples-query.ts)
371
+ findRelevantExamples,
372
+ findExamplesByCommand,
373
+ buildFewShotContextSync,
374
+ trackExampleUsage,
375
+ getLLMExampleStats,
376
+ isDatabaseAvailable,
377
+
378
+ // Async methods (preferred for new code)
379
+ getLLMExamples: (prompt: string, language?: string, limit?: number) =>
380
+ getLLMExamples(prompt, language, limit, options),
381
+ getExamplesByCommand: (command: string, language?: string, limit?: number) =>
382
+ getExamplesByCommand(command, language, limit, options),
383
+ getHighQualityExamples: (language?: string, minQuality?: number, limit?: number) =>
384
+ getHighQualityExamples(language, minQuality, limit, options),
385
+ getMostUsedExamples: (language?: string, limit?: number) =>
386
+ getMostUsedExamples(language, limit, options),
387
+ buildFewShotContext: (prompt: string, language?: string, numExamples?: number) =>
388
+ buildFewShotContext(prompt, language, numExamples, options),
389
+ getLLMStats: () => getLLMStats(options),
390
+
391
+ // Cleanup
392
+ close: closeDatabase,
393
+ };
394
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Patterns Reference API
3
+ *
4
+ * Re-exports all API functions for querying patterns, translations, and LLM examples.
5
+ */
6
+
7
+ // Patterns
8
+ export {
9
+ getPatternById,
10
+ getPatternsByCategory,
11
+ getPatternsByCommand,
12
+ searchPatterns,
13
+ getAllPatterns,
14
+ getPatternStats,
15
+ } from './patterns';
16
+
17
+ // Translations
18
+ export {
19
+ getTranslation,
20
+ getAllTranslations,
21
+ getTranslationsByLanguage,
22
+ getVerifiedTranslations,
23
+ getHighConfidenceTranslations,
24
+ verifyTranslation,
25
+ getTranslationStats,
26
+ getWordOrder,
27
+ } from './translations';
28
+
29
+ // LLM
30
+ export {
31
+ getLLMExamples,
32
+ getExamplesByCommand,
33
+ getHighQualityExamples,
34
+ getMostUsedExamples,
35
+ buildFewShotContext,
36
+ addLLMExample,
37
+ updateQualityScore,
38
+ getLLMStats,
39
+ } from './llm';
40
+
41
+ // Roles
42
+ export {
43
+ getPatternRoles,
44
+ getPatternsByRole,
45
+ getPatternsByRoles,
46
+ getPatternsByRoleValue,
47
+ getRoleStats,
48
+ getRolesByCommand,
49
+ insertPatternRole,
50
+ deletePatternRoles,
51
+ clearAllRoles,
52
+ } from './roles';