omgkit 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/package.json +6 -3
  2. package/plugin/agents/architect.md +357 -43
  3. package/plugin/agents/code-reviewer.md +481 -22
  4. package/plugin/agents/debugger.md +397 -30
  5. package/plugin/agents/docs-manager.md +431 -23
  6. package/plugin/agents/fullstack-developer.md +395 -34
  7. package/plugin/agents/git-manager.md +438 -20
  8. package/plugin/agents/oracle.md +329 -53
  9. package/plugin/agents/planner.md +275 -32
  10. package/plugin/agents/researcher.md +343 -21
  11. package/plugin/agents/scout.md +423 -18
  12. package/plugin/agents/sprint-master.md +418 -48
  13. package/plugin/agents/tester.md +551 -26
  14. package/plugin/skills/backend/api-architecture/SKILL.md +857 -0
  15. package/plugin/skills/backend/caching-strategies/SKILL.md +755 -0
  16. package/plugin/skills/backend/event-driven-architecture/SKILL.md +753 -0
  17. package/plugin/skills/backend/real-time-systems/SKILL.md +635 -0
  18. package/plugin/skills/databases/database-optimization/SKILL.md +571 -0
  19. package/plugin/skills/devops/monorepo-management/SKILL.md +595 -0
  20. package/plugin/skills/devops/observability/SKILL.md +622 -0
  21. package/plugin/skills/devops/performance-profiling/SKILL.md +905 -0
  22. package/plugin/skills/frontend/advanced-ui-design/SKILL.md +426 -0
  23. package/plugin/skills/integrations/ai-integration/SKILL.md +730 -0
  24. package/plugin/skills/integrations/payment-integration/SKILL.md +735 -0
  25. package/plugin/skills/methodology/problem-solving/SKILL.md +355 -0
  26. package/plugin/skills/methodology/research-validation/SKILL.md +668 -0
  27. package/plugin/skills/methodology/sequential-thinking/SKILL.md +260 -0
  28. package/plugin/skills/mobile/mobile-development/SKILL.md +756 -0
  29. package/plugin/skills/security/security-hardening/SKILL.md +633 -0
  30. package/plugin/skills/tools/document-processing/SKILL.md +916 -0
  31. package/plugin/skills/tools/image-processing/SKILL.md +748 -0
  32. package/plugin/skills/tools/mcp-development/SKILL.md +883 -0
  33. package/plugin/skills/tools/media-processing/SKILL.md +831 -0
@@ -0,0 +1,730 @@
1
+ ---
2
+ name: ai-integration
3
+ description: AI/ML model integration including vision, audio, embeddings, and RAG implementation patterns
4
+ category: integrations
5
+ triggers:
6
+ - ai integration
7
+ - ai ml
8
+ - embeddings
9
+ - rag
10
+ - vision api
11
+ - audio transcription
12
+ - openai
13
+ - anthropic
14
+ ---
15
+
16
+ # AI Integration
17
+
18
+ Enterprise **AI/ML model integration** patterns for vision, audio, embeddings, and RAG systems. This skill covers API integration, prompt engineering, and production deployment.
19
+
20
+ ## Purpose
21
+
22
+ Integrate AI capabilities into applications effectively:
23
+
24
+ - Implement vision and image understanding
25
+ - Add audio transcription and processing
26
+ - Build semantic search with embeddings
27
+ - Create RAG (Retrieval Augmented Generation) systems
28
+ - Handle rate limiting and error recovery
29
+ - Optimize costs and latency
30
+
31
+ ## Features
32
+
33
+ ### 1. Vision API Integration
34
+
35
+ ```typescript
36
+ import Anthropic from '@anthropic-ai/sdk';
37
+ import OpenAI from 'openai';
38
+
39
+ const anthropic = new Anthropic();
40
+ const openai = new OpenAI();
41
+
42
+ // Analyze image with Claude
43
+ async function analyzeImageWithClaude(
44
+ imageUrl: string | Buffer,
45
+ prompt: string
46
+ ): Promise<string> {
47
+ const imageSource = typeof imageUrl === 'string'
48
+ ? { type: 'url' as const, url: imageUrl }
49
+ : {
50
+ type: 'base64' as const,
51
+ media_type: 'image/jpeg' as const,
52
+ data: imageUrl.toString('base64'),
53
+ };
54
+
55
+ const response = await anthropic.messages.create({
56
+ model: 'claude-sonnet-4-20250514',
57
+ max_tokens: 1024,
58
+ messages: [{
59
+ role: 'user',
60
+ content: [
61
+ {
62
+ type: 'image',
63
+ source: imageSource,
64
+ },
65
+ {
66
+ type: 'text',
67
+ text: prompt,
68
+ },
69
+ ],
70
+ }],
71
+ });
72
+
73
+ return response.content[0].type === 'text'
74
+ ? response.content[0].text
75
+ : '';
76
+ }
77
+
78
+ // Extract structured data from image
79
+ interface ProductInfo {
80
+ name: string;
81
+ description: string;
82
+ price?: string;
83
+ category?: string;
84
+ features: string[];
85
+ }
86
+
87
+ async function extractProductFromImage(imageBuffer: Buffer): Promise<ProductInfo> {
88
+ const prompt = `Analyze this product image and extract:
89
+ 1. Product name
90
+ 2. Description (2-3 sentences)
91
+ 3. Price (if visible)
92
+ 4. Category
93
+ 5. Key features (list)
94
+
95
+ Return as JSON only, no explanation.`;
96
+
97
+ const response = await analyzeImageWithClaude(imageBuffer, prompt);
98
+
99
+ try {
100
+ return JSON.parse(response);
101
+ } catch {
102
+ throw new Error('Failed to parse product information');
103
+ }
104
+ }
105
+
106
+ // OCR with GPT-4 Vision
107
+ async function extractTextFromImage(imageUrl: string): Promise<string> {
108
+ const response = await openai.chat.completions.create({
109
+ model: 'gpt-4o',
110
+ messages: [{
111
+ role: 'user',
112
+ content: [
113
+ {
114
+ type: 'image_url',
115
+ image_url: { url: imageUrl, detail: 'high' },
116
+ },
117
+ {
118
+ type: 'text',
119
+ text: 'Extract all text from this image. Preserve the original formatting and structure as much as possible.',
120
+ },
121
+ ],
122
+ }],
123
+ max_tokens: 4096,
124
+ });
125
+
126
+ return response.choices[0].message.content || '';
127
+ }
128
+
129
+ // Batch image processing
130
+ async function batchAnalyzeImages(
131
+ images: Array<{ id: string; url: string }>,
132
+ prompt: string,
133
+ concurrency: number = 3
134
+ ): Promise<Map<string, string>> {
135
+ const results = new Map<string, string>();
136
+ const queue = new PQueue({ concurrency });
137
+
138
+ await Promise.all(
139
+ images.map(image =>
140
+ queue.add(async () => {
141
+ try {
142
+ const result = await analyzeImageWithClaude(image.url, prompt);
143
+ results.set(image.id, result);
144
+ } catch (error) {
145
+ results.set(image.id, `Error: ${error.message}`);
146
+ }
147
+ })
148
+ )
149
+ );
150
+
151
+ return results;
152
+ }
153
+ ```
154
+
155
+ ### 2. Audio Processing
156
+
157
+ ```typescript
158
+ import { Readable } from 'stream';
159
+
160
+ // Transcribe audio with Whisper
161
+ async function transcribeAudio(
162
+ audioFile: Buffer | string,
163
+ options: {
164
+ language?: string;
165
+ prompt?: string;
166
+ responseFormat?: 'json' | 'text' | 'srt' | 'vtt';
167
+ timestamps?: boolean;
168
+ } = {}
169
+ ): Promise<TranscriptionResult> {
170
+ const {
171
+ language,
172
+ prompt,
173
+ responseFormat = 'json',
174
+ timestamps = false,
175
+ } = options;
176
+
177
+ const file = typeof audioFile === 'string'
178
+ ? fs.createReadStream(audioFile)
179
+ : Readable.from(audioFile);
180
+
181
+ const response = await openai.audio.transcriptions.create({
182
+ file,
183
+ model: 'whisper-1',
184
+ language,
185
+ prompt,
186
+ response_format: timestamps ? 'verbose_json' : responseFormat,
187
+ });
188
+
189
+ if (timestamps && typeof response !== 'string') {
190
+ return {
191
+ text: response.text,
192
+ segments: response.segments?.map(seg => ({
193
+ start: seg.start,
194
+ end: seg.end,
195
+ text: seg.text,
196
+ })),
197
+ language: response.language,
198
+ };
199
+ }
200
+
201
+ return { text: typeof response === 'string' ? response : response.text };
202
+ }
203
+
204
+ // Real-time transcription with streaming
205
+ async function* streamTranscription(
206
+ audioStream: ReadableStream
207
+ ): AsyncGenerator<string> {
208
+ // For real-time, use Deepgram or AssemblyAI
209
+ const deepgram = new Deepgram(process.env.DEEPGRAM_API_KEY!);
210
+
211
+ const connection = await deepgram.transcription.live({
212
+ model: 'nova-2',
213
+ language: 'en',
214
+ smart_format: true,
215
+ interim_results: true,
216
+ });
217
+
218
+ connection.on('transcriptReceived', (message) => {
219
+ const transcript = message.channel?.alternatives?.[0]?.transcript;
220
+ if (transcript) {
221
+ yield transcript;
222
+ }
223
+ });
224
+
225
+ // Pipe audio to connection
226
+ const reader = audioStream.getReader();
227
+ while (true) {
228
+ const { done, value } = await reader.read();
229
+ if (done) break;
230
+ connection.send(value);
231
+ }
232
+
233
+ connection.close();
234
+ }
235
+
236
+ // Generate speech from text
237
+ async function generateSpeech(
238
+ text: string,
239
+ options: {
240
+ voice?: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer';
241
+ model?: 'tts-1' | 'tts-1-hd';
242
+ speed?: number;
243
+ } = {}
244
+ ): Promise<Buffer> {
245
+ const { voice = 'alloy', model = 'tts-1', speed = 1 } = options;
246
+
247
+ const response = await openai.audio.speech.create({
248
+ model,
249
+ voice,
250
+ input: text,
251
+ speed,
252
+ });
253
+
254
+ return Buffer.from(await response.arrayBuffer());
255
+ }
256
+ ```
257
+
258
+ ### 3. Embeddings & Vector Search
259
+
260
+ ```typescript
261
+ import { Pinecone } from '@pinecone-database/pinecone';
262
+
263
+ const pinecone = new Pinecone();
264
+
265
+ // Generate embeddings
266
+ async function generateEmbeddings(
267
+ texts: string[],
268
+ model: string = 'text-embedding-3-small'
269
+ ): Promise<number[][]> {
270
+ const response = await openai.embeddings.create({
271
+ model,
272
+ input: texts,
273
+ });
274
+
275
+ return response.data.map(d => d.embedding);
276
+ }
277
+
278
+ // Index documents
279
+ interface Document {
280
+ id: string;
281
+ content: string;
282
+ metadata?: Record<string, any>;
283
+ }
284
+
285
+ async function indexDocuments(
286
+ documents: Document[],
287
+ indexName: string,
288
+ namespace: string = 'default'
289
+ ): Promise<void> {
290
+ const index = pinecone.index(indexName);
291
+
292
+ // Process in batches
293
+ const batchSize = 100;
294
+ for (let i = 0; i < documents.length; i += batchSize) {
295
+ const batch = documents.slice(i, i + batchSize);
296
+
297
+ const embeddings = await generateEmbeddings(
298
+ batch.map(d => d.content)
299
+ );
300
+
301
+ const vectors = batch.map((doc, j) => ({
302
+ id: doc.id,
303
+ values: embeddings[j],
304
+ metadata: {
305
+ content: doc.content.substring(0, 1000), // Store truncated content
306
+ ...doc.metadata,
307
+ },
308
+ }));
309
+
310
+ await index.namespace(namespace).upsert(vectors);
311
+ }
312
+ }
313
+
314
+ // Semantic search
315
+ interface SearchResult {
316
+ id: string;
317
+ score: number;
318
+ content: string;
319
+ metadata?: Record<string, any>;
320
+ }
321
+
322
+ async function semanticSearch(
323
+ query: string,
324
+ indexName: string,
325
+ options: {
326
+ namespace?: string;
327
+ topK?: number;
328
+ filter?: Record<string, any>;
329
+ minScore?: number;
330
+ } = {}
331
+ ): Promise<SearchResult[]> {
332
+ const {
333
+ namespace = 'default',
334
+ topK = 10,
335
+ filter,
336
+ minScore = 0.7,
337
+ } = options;
338
+
339
+ const [queryEmbedding] = await generateEmbeddings([query]);
340
+
341
+ const index = pinecone.index(indexName);
342
+ const results = await index.namespace(namespace).query({
343
+ vector: queryEmbedding,
344
+ topK,
345
+ filter,
346
+ includeMetadata: true,
347
+ });
348
+
349
+ return results.matches
350
+ ?.filter(m => m.score && m.score >= minScore)
351
+ .map(match => ({
352
+ id: match.id,
353
+ score: match.score || 0,
354
+ content: match.metadata?.content as string || '',
355
+ metadata: match.metadata,
356
+ })) || [];
357
+ }
358
+ ```
359
+
360
+ ### 4. RAG Implementation
361
+
362
+ ```typescript
363
+ interface RAGConfig {
364
+ indexName: string;
365
+ namespace?: string;
366
+ topK?: number;
367
+ model?: string;
368
+ systemPrompt?: string;
369
+ }
370
+
371
+ class RAGSystem {
372
+ private config: RAGConfig;
373
+
374
+ constructor(config: RAGConfig) {
375
+ this.config = {
376
+ namespace: 'default',
377
+ topK: 5,
378
+ model: 'claude-sonnet-4-20250514',
379
+ systemPrompt: 'You are a helpful assistant. Answer based on the provided context.',
380
+ ...config,
381
+ };
382
+ }
383
+
384
+ async query(question: string): Promise<RAGResponse> {
385
+ // Step 1: Retrieve relevant documents
386
+ const context = await semanticSearch(question, this.config.indexName, {
387
+ namespace: this.config.namespace,
388
+ topK: this.config.topK,
389
+ });
390
+
391
+ if (context.length === 0) {
392
+ return {
393
+ answer: "I couldn't find relevant information to answer your question.",
394
+ sources: [],
395
+ confidence: 0,
396
+ };
397
+ }
398
+
399
+ // Step 2: Build context string
400
+ const contextText = context
401
+ .map((doc, i) => `[${i + 1}] ${doc.content}`)
402
+ .join('\n\n');
403
+
404
+ // Step 3: Generate answer
405
+ const response = await anthropic.messages.create({
406
+ model: this.config.model!,
407
+ max_tokens: 2048,
408
+ system: `${this.config.systemPrompt}
409
+
410
+ Use the following context to answer the user's question. If the answer is not in the context, say so.
411
+
412
+ Context:
413
+ ${contextText}`,
414
+ messages: [{
415
+ role: 'user',
416
+ content: question,
417
+ }],
418
+ });
419
+
420
+ const answer = response.content[0].type === 'text'
421
+ ? response.content[0].text
422
+ : '';
423
+
424
+ return {
425
+ answer,
426
+ sources: context.map(c => ({
427
+ id: c.id,
428
+ content: c.content,
429
+ score: c.score,
430
+ })),
431
+ confidence: Math.max(...context.map(c => c.score)),
432
+ };
433
+ }
434
+
435
+ // Hybrid search (keyword + semantic)
436
+ async hybridQuery(
437
+ question: string,
438
+ keywords?: string[]
439
+ ): Promise<RAGResponse> {
440
+ // Semantic search
441
+ const semanticResults = await semanticSearch(question, this.config.indexName, {
442
+ namespace: this.config.namespace,
443
+ topK: this.config.topK! * 2,
444
+ });
445
+
446
+ // Keyword filter (if provided)
447
+ let results = semanticResults;
448
+ if (keywords && keywords.length > 0) {
449
+ results = semanticResults.filter(r =>
450
+ keywords.some(k =>
451
+ r.content.toLowerCase().includes(k.toLowerCase())
452
+ )
453
+ );
454
+ }
455
+
456
+ // Rerank and take top K
457
+ const topResults = results.slice(0, this.config.topK);
458
+
459
+ // Generate answer using top results
460
+ return this.generateAnswer(question, topResults);
461
+ }
462
+
463
+ private async generateAnswer(
464
+ question: string,
465
+ context: SearchResult[]
466
+ ): Promise<RAGResponse> {
467
+ // ... same generation logic
468
+ }
469
+ }
470
+
471
+ // Usage
472
+ const rag = new RAGSystem({
473
+ indexName: 'knowledge-base',
474
+ topK: 5,
475
+ systemPrompt: 'You are a customer support agent. Be helpful and concise.',
476
+ });
477
+
478
+ const response = await rag.query('How do I reset my password?');
479
+ ```
480
+
481
+ ### 5. Structured Output
482
+
483
+ ```typescript
484
+ import { z } from 'zod';
485
+ import { zodResponseFormat } from 'openai/helpers/zod';
486
+
487
+ // Define schema
488
+ const SentimentSchema = z.object({
489
+ sentiment: z.enum(['positive', 'negative', 'neutral']),
490
+ confidence: z.number().min(0).max(1),
491
+ topics: z.array(z.string()),
492
+ summary: z.string(),
493
+ });
494
+
495
+ type SentimentAnalysis = z.infer<typeof SentimentSchema>;
496
+
497
+ // Get structured output
498
+ async function analyzeSentiment(text: string): Promise<SentimentAnalysis> {
499
+ const response = await openai.beta.chat.completions.parse({
500
+ model: 'gpt-4o',
501
+ messages: [{
502
+ role: 'system',
503
+ content: 'Analyze the sentiment of the provided text.',
504
+ }, {
505
+ role: 'user',
506
+ content: text,
507
+ }],
508
+ response_format: zodResponseFormat(SentimentSchema, 'sentiment_analysis'),
509
+ });
510
+
511
+ return response.choices[0].message.parsed!;
512
+ }
513
+
514
+ // Claude tool use for structured output
515
+ async function extractEntities(text: string): Promise<{
516
+ people: string[];
517
+ organizations: string[];
518
+ locations: string[];
519
+ dates: string[];
520
+ }> {
521
+ const response = await anthropic.messages.create({
522
+ model: 'claude-sonnet-4-20250514',
523
+ max_tokens: 1024,
524
+ tools: [{
525
+ name: 'extract_entities',
526
+ description: 'Extract named entities from text',
527
+ input_schema: {
528
+ type: 'object',
529
+ properties: {
530
+ people: {
531
+ type: 'array',
532
+ items: { type: 'string' },
533
+ description: 'Names of people mentioned',
534
+ },
535
+ organizations: {
536
+ type: 'array',
537
+ items: { type: 'string' },
538
+ description: 'Organization names',
539
+ },
540
+ locations: {
541
+ type: 'array',
542
+ items: { type: 'string' },
543
+ description: 'Location names',
544
+ },
545
+ dates: {
546
+ type: 'array',
547
+ items: { type: 'string' },
548
+ description: 'Dates mentioned',
549
+ },
550
+ },
551
+ required: ['people', 'organizations', 'locations', 'dates'],
552
+ },
553
+ }],
554
+ tool_choice: { type: 'tool', name: 'extract_entities' },
555
+ messages: [{
556
+ role: 'user',
557
+ content: `Extract entities from: ${text}`,
558
+ }],
559
+ });
560
+
561
+ const toolUse = response.content.find(c => c.type === 'tool_use');
562
+ return toolUse?.input as any;
563
+ }
564
+ ```
565
+
566
+ ### 6. Production Patterns
567
+
568
+ ```typescript
569
+ // Rate limiting and retry
570
+ import Bottleneck from 'bottleneck';
571
+
572
+ const limiter = new Bottleneck({
573
+ reservoir: 100, // Initial tokens
574
+ reservoirRefreshAmount: 100,
575
+ reservoirRefreshInterval: 60 * 1000, // Per minute
576
+ maxConcurrent: 10,
577
+ });
578
+
579
+ async function withRateLimit<T>(fn: () => Promise<T>): Promise<T> {
580
+ return limiter.schedule(fn);
581
+ }
582
+
583
+ // Retry with exponential backoff
584
+ async function withRetry<T>(
585
+ fn: () => Promise<T>,
586
+ maxRetries: number = 3,
587
+ baseDelay: number = 1000
588
+ ): Promise<T> {
589
+ let lastError: Error;
590
+
591
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
592
+ try {
593
+ return await fn();
594
+ } catch (error) {
595
+ lastError = error as Error;
596
+
597
+ // Check if retryable
598
+ if (error.status === 429 || error.status >= 500) {
599
+ const delay = baseDelay * Math.pow(2, attempt);
600
+ await new Promise(r => setTimeout(r, delay));
601
+ continue;
602
+ }
603
+
604
+ throw error;
605
+ }
606
+ }
607
+
608
+ throw lastError!;
609
+ }
610
+
611
+ // Caching layer
612
+ const cache = new Map<string, { data: any; expires: number }>();
613
+
614
+ async function cachedEmbedding(
615
+ text: string,
616
+ ttl: number = 3600000 // 1 hour
617
+ ): Promise<number[]> {
618
+ const key = `embedding:${hashString(text)}`;
619
+ const cached = cache.get(key);
620
+
621
+ if (cached && cached.expires > Date.now()) {
622
+ return cached.data;
623
+ }
624
+
625
+ const [embedding] = await generateEmbeddings([text]);
626
+ cache.set(key, { data: embedding, expires: Date.now() + ttl });
627
+
628
+ return embedding;
629
+ }
630
+
631
+ // Cost tracking
632
+ class CostTracker {
633
+ private costs: Map<string, number> = new Map();
634
+
635
+ track(model: string, inputTokens: number, outputTokens: number): void {
636
+ const pricing = MODEL_PRICING[model] || { input: 0, output: 0 };
637
+ const cost = (inputTokens * pricing.input + outputTokens * pricing.output) / 1000;
638
+
639
+ const current = this.costs.get(model) || 0;
640
+ this.costs.set(model, current + cost);
641
+ }
642
+
643
+ getReport(): Record<string, number> {
644
+ return Object.fromEntries(this.costs);
645
+ }
646
+
647
+ getTotalCost(): number {
648
+ return Array.from(this.costs.values()).reduce((a, b) => a + b, 0);
649
+ }
650
+ }
651
+ ```
652
+
653
+ ## Use Cases
654
+
655
+ ### 1. Document Q&A System
656
+
657
+ ```typescript
658
+ // Build document Q&A
659
+ async function buildDocumentQA(documents: string[]): Promise<RAGSystem> {
660
+ // Chunk documents
661
+ const chunks = documents.flatMap((doc, docIndex) =>
662
+ chunkText(doc, 500, 50).map((chunk, chunkIndex) => ({
663
+ id: `doc-${docIndex}-chunk-${chunkIndex}`,
664
+ content: chunk,
665
+ metadata: { documentIndex: docIndex },
666
+ }))
667
+ );
668
+
669
+ // Index chunks
670
+ await indexDocuments(chunks, 'document-qa');
671
+
672
+ // Return RAG system
673
+ return new RAGSystem({
674
+ indexName: 'document-qa',
675
+ topK: 5,
676
+ systemPrompt: 'Answer questions based on the provided documents.',
677
+ });
678
+ }
679
+ ```
680
+
681
+ ### 2. Content Moderation
682
+
683
+ ```typescript
684
+ // Moderate content with AI
685
+ async function moderateContent(content: string): Promise<ModerationResult> {
686
+ const response = await openai.moderations.create({ input: content });
687
+ const result = response.results[0];
688
+
689
+ return {
690
+ flagged: result.flagged,
691
+ categories: Object.entries(result.categories)
692
+ .filter(([_, flagged]) => flagged)
693
+ .map(([category]) => category),
694
+ scores: result.category_scores,
695
+ };
696
+ }
697
+ ```
698
+
699
+ ## Best Practices
700
+
701
+ ### Do's
702
+
703
+ - **Implement rate limiting** - Respect API limits
704
+ - **Cache embeddings** - Avoid redundant API calls
705
+ - **Handle errors gracefully** - Implement retry logic
706
+ - **Monitor costs** - Track token usage
707
+ - **Use streaming** - For better UX with long responses
708
+ - **Chunk appropriately** - Balance context vs. relevance
709
+
710
+ ### Don'ts
711
+
712
+ - Don't expose API keys in frontend code
713
+ - Don't skip input validation
714
+ - Don't ignore rate limit errors
715
+ - Don't cache sensitive data inappropriately
716
+ - Don't use overly large context windows
717
+ - Don't forget fallback strategies
718
+
719
+ ## Related Skills
720
+
721
+ - **api-architecture** - API design patterns
722
+ - **caching-strategies** - Caching for AI responses
723
+ - **backend-development** - Integration patterns
724
+
725
+ ## Reference Resources
726
+
727
+ - [OpenAI API Reference](https://platform.openai.com/docs)
728
+ - [Anthropic API Reference](https://docs.anthropic.com/)
729
+ - [Pinecone Documentation](https://docs.pinecone.io/)
730
+ - [LangChain Documentation](https://js.langchain.com/)