lazlo-ai 1.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.
Files changed (126) hide show
  1. package/.env.example +9 -0
  2. package/README.md +278 -0
  3. package/dist/cache/semantic.d.ts +39 -0
  4. package/dist/cache/semantic.d.ts.map +1 -0
  5. package/dist/cache/semantic.js +134 -0
  6. package/dist/cache/semantic.js.map +1 -0
  7. package/dist/chains/llmchain.d.ts +65 -0
  8. package/dist/chains/llmchain.d.ts.map +1 -0
  9. package/dist/chains/llmchain.js +137 -0
  10. package/dist/chains/llmchain.js.map +1 -0
  11. package/dist/chains/rag.d.ts +23 -0
  12. package/dist/chains/rag.d.ts.map +1 -0
  13. package/dist/chains/rag.js +47 -0
  14. package/dist/chains/rag.js.map +1 -0
  15. package/dist/core/types.d.ts +130 -0
  16. package/dist/core/types.d.ts.map +1 -0
  17. package/dist/core/types.js +8 -0
  18. package/dist/core/types.js.map +1 -0
  19. package/dist/document_loaders/index.d.ts +61 -0
  20. package/dist/document_loaders/index.d.ts.map +1 -0
  21. package/dist/document_loaders/index.js +183 -0
  22. package/dist/document_loaders/index.js.map +1 -0
  23. package/dist/embeddings/google.d.ts +43 -0
  24. package/dist/embeddings/google.d.ts.map +1 -0
  25. package/dist/embeddings/google.js +90 -0
  26. package/dist/embeddings/google.js.map +1 -0
  27. package/dist/embeddings/local.d.ts +64 -0
  28. package/dist/embeddings/local.d.ts.map +1 -0
  29. package/dist/embeddings/local.js +95 -0
  30. package/dist/embeddings/local.js.map +1 -0
  31. package/dist/evals/judge.d.ts +22 -0
  32. package/dist/evals/judge.d.ts.map +1 -0
  33. package/dist/evals/judge.js +77 -0
  34. package/dist/evals/judge.js.map +1 -0
  35. package/dist/index.d.ts +28 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +84 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/memory/buffer.d.ts +64 -0
  40. package/dist/memory/buffer.d.ts.map +1 -0
  41. package/dist/memory/buffer.js +168 -0
  42. package/dist/memory/buffer.js.map +1 -0
  43. package/dist/parsers/output.d.ts +64 -0
  44. package/dist/parsers/output.d.ts.map +1 -0
  45. package/dist/parsers/output.js +148 -0
  46. package/dist/parsers/output.js.map +1 -0
  47. package/dist/prompts/registry.d.ts +65 -0
  48. package/dist/prompts/registry.d.ts.map +1 -0
  49. package/dist/prompts/registry.js +170 -0
  50. package/dist/prompts/registry.js.map +1 -0
  51. package/dist/providers/ollama.d.ts +30 -0
  52. package/dist/providers/ollama.d.ts.map +1 -0
  53. package/dist/providers/ollama.js +104 -0
  54. package/dist/providers/ollama.js.map +1 -0
  55. package/dist/providers/openai.d.ts +46 -0
  56. package/dist/providers/openai.d.ts.map +1 -0
  57. package/dist/providers/openai.js +228 -0
  58. package/dist/providers/openai.js.map +1 -0
  59. package/dist/retrievers/index.d.ts +71 -0
  60. package/dist/retrievers/index.d.ts.map +1 -0
  61. package/dist/retrievers/index.js +130 -0
  62. package/dist/retrievers/index.js.map +1 -0
  63. package/dist/router/smartrouter.d.ts +36 -0
  64. package/dist/router/smartrouter.d.ts.map +1 -0
  65. package/dist/router/smartrouter.js +132 -0
  66. package/dist/router/smartrouter.js.map +1 -0
  67. package/dist/text_splitters/index.d.ts +28 -0
  68. package/dist/text_splitters/index.d.ts.map +1 -0
  69. package/dist/text_splitters/index.js +109 -0
  70. package/dist/text_splitters/index.js.map +1 -0
  71. package/dist/tools/decorator.d.ts +26 -0
  72. package/dist/tools/decorator.d.ts.map +1 -0
  73. package/dist/tools/decorator.js +102 -0
  74. package/dist/tools/decorator.js.map +1 -0
  75. package/dist/tools/index.d.ts +7 -0
  76. package/dist/tools/index.d.ts.map +1 -0
  77. package/dist/tools/index.js +6 -0
  78. package/dist/tools/index.js.map +1 -0
  79. package/dist/tools/keiro.d.ts +20 -0
  80. package/dist/tools/keiro.d.ts.map +1 -0
  81. package/dist/tools/keiro.js +67 -0
  82. package/dist/tools/keiro.js.map +1 -0
  83. package/dist/tracing/tracer.d.ts +56 -0
  84. package/dist/tracing/tracer.d.ts.map +1 -0
  85. package/dist/tracing/tracer.js +125 -0
  86. package/dist/tracing/tracer.js.map +1 -0
  87. package/dist/utils/logger.d.ts +25 -0
  88. package/dist/utils/logger.d.ts.map +1 -0
  89. package/dist/utils/logger.js +50 -0
  90. package/dist/utils/logger.js.map +1 -0
  91. package/dist/utils/pricing.d.ts +31 -0
  92. package/dist/utils/pricing.d.ts.map +1 -0
  93. package/dist/utils/pricing.js +108 -0
  94. package/dist/utils/pricing.js.map +1 -0
  95. package/dist/vectorstores/index.d.ts +62 -0
  96. package/dist/vectorstores/index.d.ts.map +1 -0
  97. package/dist/vectorstores/index.js +244 -0
  98. package/dist/vectorstores/index.js.map +1 -0
  99. package/package.json +48 -0
  100. package/src/cache/semantic.ts +175 -0
  101. package/src/chains/llmchain.ts +194 -0
  102. package/src/chains/rag.ts +65 -0
  103. package/src/core/types.ts +178 -0
  104. package/src/document_loaders/index.ts +223 -0
  105. package/src/embeddings/google.ts +119 -0
  106. package/src/embeddings/local.ts +118 -0
  107. package/src/evals/judge.ts +99 -0
  108. package/src/index.ts +121 -0
  109. package/src/memory/buffer.ts +222 -0
  110. package/src/parsers/output.ts +195 -0
  111. package/src/prompts/registry.ts +205 -0
  112. package/src/providers/ollama.ts +151 -0
  113. package/src/providers/openai.ts +320 -0
  114. package/src/retrievers/index.ts +182 -0
  115. package/src/router/smartrouter.ts +172 -0
  116. package/src/text_splitters/index.ts +145 -0
  117. package/src/tools/decorator.ts +145 -0
  118. package/src/tools/index.ts +7 -0
  119. package/src/tools/keiro.ts +92 -0
  120. package/src/tracing/tracer.ts +178 -0
  121. package/src/utils/logger.ts +62 -0
  122. package/src/utils/pricing.ts +133 -0
  123. package/src/vectorstores/index.ts +338 -0
  124. package/test-full.mjs +552 -0
  125. package/test.mjs +74 -0
  126. package/tsconfig.json +30 -0
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Semantic Cache - Cache LLM responses with semantic similarity
3
+ */
4
+
5
+ import { logger } from '../utils/logger.js';
6
+
7
+ // Simple in-memory embeddings for cosine similarity
8
+ // In production, you'd use sentence-transformers or an embedding API
9
+ type Embedding = number[];
10
+
11
+ interface CacheEntry {
12
+ prompt: string;
13
+ response: string;
14
+ embedding: Embedding;
15
+ }
16
+
17
+ // ============================================================================
18
+ // Cosine Similarity
19
+ // ============================================================================
20
+
21
+ function cosineSimilarity(v1: Embedding, v2: Embedding): number {
22
+ const dot = v1.reduce((sum, a, i) => sum + a * v2[i], 0);
23
+ const norm1 = Math.sqrt(v1.reduce((sum, a) => sum + a * a, 0));
24
+ const norm2 = Math.sqrt(v2.reduce((sum, b) => sum + b * b, 0));
25
+
26
+ if (norm1 === 0 || norm2 === 0) return 0;
27
+ return dot / (norm1 * norm2);
28
+ }
29
+
30
+ // Simple hash-based embedding (for demo - in production use real embeddings)
31
+ // This creates a deterministic "embedding" from the text
32
+ function simpleEmbedding(text: string): Embedding {
33
+ const hash = new Map<string, number>();
34
+ const words = text.toLowerCase().split(/\s+/);
35
+
36
+ // Create a simple bag-of-words embedding
37
+ for (let i = 0; i < 384; i++) {
38
+ hash.set(String(i), 0);
39
+ }
40
+
41
+ words.forEach((word, idx) => {
42
+ const hash1 = (word.charCodeAt(0) * 31 + idx) % 384;
43
+ const hash2 = (word.length * 17 + idx) % 384;
44
+ hash.set(String(hash1), (hash.get(String(hash1)) ?? 0) + 1);
45
+ hash.set(String(hash2), (hash.get(String(hash2)) ?? 0) + 0.5);
46
+ });
47
+
48
+ // Normalize
49
+ const embedding: Embedding = [];
50
+ let norm = 0;
51
+ for (let i = 0; i < 384; i++) {
52
+ const val = hash.get(String(i)) ?? 0;
53
+ embedding.push(val);
54
+ norm += val * val;
55
+ }
56
+ norm = Math.sqrt(norm);
57
+ return embedding.map(v => v / (norm || 1));
58
+ }
59
+
60
+ // ============================================================================
61
+ // Semantic Cache
62
+ // ============================================================================
63
+
64
+ export interface SemanticCacheOptions {
65
+ threshold?: number; // Cosine similarity threshold (default: 0.92)
66
+ }
67
+
68
+ export class SemanticCache {
69
+ private store: CacheEntry[] = [];
70
+ private threshold: number;
71
+ private hits = 0;
72
+ private misses = 0;
73
+ private tokensSaved = 0;
74
+
75
+ constructor(options: SemanticCacheOptions = {}) {
76
+ this.threshold = options.threshold ?? 0.92;
77
+ logger.info(`SemanticCache ready. Threshold: ${this.threshold}`);
78
+ }
79
+
80
+ /**
81
+ * Look up a cached response
82
+ */
83
+ lookup(prompt: string): string | null {
84
+ if (this.store.length === 0) {
85
+ return null;
86
+ }
87
+
88
+ const queryEmbedding = simpleEmbedding(prompt);
89
+ let bestScore = 0;
90
+ let bestResponse: string | null = null;
91
+
92
+ for (const entry of this.store) {
93
+ const score = cosineSimilarity(queryEmbedding, entry.embedding);
94
+ if (score > bestScore) {
95
+ bestScore = score;
96
+ bestResponse = entry.response;
97
+ }
98
+ }
99
+
100
+ if (bestScore >= this.threshold) {
101
+ logger.info(`[SemanticCache] CACHE HIT (similarity=${bestScore.toFixed(3)}). Skipping LLM call.`);
102
+ this.hits++;
103
+ this.tokensSaved += bestResponse!.length / 4;
104
+ return bestResponse;
105
+ }
106
+
107
+ return null;
108
+ }
109
+
110
+ /**
111
+ * Store a response in the cache
112
+ */
113
+ put(prompt: string, response: string): void {
114
+ const embedding = simpleEmbedding(prompt);
115
+ this.store.push({ prompt, response, embedding });
116
+ logger.debug(`[SemanticCache] Stored response for: ${prompt.slice(0, 50)}...`);
117
+ }
118
+
119
+ /**
120
+ * Wrap an LLM to use caching
121
+ */
122
+ wrap<T extends { invoke(prompt: string): Promise<any> }>(llm: T): T & { invoke(prompt: string): Promise<any> } {
123
+ const cache = this;
124
+
125
+ const cachedInvoke = async function(prompt: string) {
126
+ const cached = cache.lookup(prompt);
127
+ if (cached !== null) {
128
+ return cached;
129
+ }
130
+
131
+ cache.misses++;
132
+ logger.debug('[SemanticCache] CACHE MISS. Calling LLM.');
133
+
134
+ const response = await llm.invoke(prompt);
135
+ const responseStr = typeof response === 'string' ? response : response.content ?? '';
136
+ cache.put(prompt, responseStr);
137
+
138
+ return response;
139
+ };
140
+
141
+ return Object.assign(cachedInvoke, llm);
142
+ }
143
+
144
+ /**
145
+ * Print cache statistics
146
+ */
147
+ printStats(): void {
148
+ const total = this.hits + this.misses;
149
+ const hitRate = total > 0 ? (this.hits / total * 100).toFixed(1) : '0.0';
150
+ const costSaved = (this.tokensSaved / 1000 * 0.002).toFixed(4);
151
+
152
+ console.log(`
153
+ ${'='.repeat(50)}
154
+ Lazlo SemanticCache Stats
155
+ ${'='.repeat(50)}
156
+ Total calls : ${total}
157
+ Cache hits : ${this.hits} (${hitRate}%)
158
+ Cache misses: ${this.misses}
159
+ Est. tokens saved : ~${this.tokensSaved.toLocaleString()}
160
+ Est. cost avoided : ~$${costSaved}
161
+ ${'='.repeat(50)}
162
+ `);
163
+ }
164
+
165
+ /**
166
+ * Clear the cache
167
+ */
168
+ clear(): void {
169
+ this.store = [];
170
+ this.hits = 0;
171
+ this.misses = 0;
172
+ this.tokensSaved = 0;
173
+ logger.info('SemanticCache cleared.');
174
+ }
175
+ }
@@ -0,0 +1,194 @@
1
+ /**
2
+ * LLMChain - Simple prompt chaining
3
+ */
4
+
5
+ import { BaseChatModel, Message, ChainInputs, ChainOutputs, ToolDefinition } from '../core/types.js';
6
+ import { logger } from '../utils/logger.js';
7
+ import { getPricing, estimateTokens, calculateCost } from '../utils/pricing.js';
8
+
9
+ // ============================================================================
10
+ // Prompt Template
11
+ // ============================================================================
12
+
13
+ export class PromptTemplate {
14
+ private template: string;
15
+ private inputVariables: string[];
16
+
17
+ constructor(template: string) {
18
+ this.template = template;
19
+ // Extract variables from {variable} patterns
20
+ const regex = /\{([^}]+)\}/g;
21
+ const matches = template.match(regex);
22
+ this.inputVariables = matches ? matches.map(m => m.slice(1, -1)) : [];
23
+ }
24
+
25
+ format(values: Record<string, unknown>): string {
26
+ // Check for missing variables
27
+ const missing = this.inputVariables.filter(v => !(v in values));
28
+ if (missing.length > 0) {
29
+ throw new Error(`Missing required variables: ${missing.join(', ')}`);
30
+ }
31
+
32
+ let result = this.template;
33
+ for (const [key, value] of Object.entries(values)) {
34
+ result = result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
35
+ }
36
+ return result;
37
+ }
38
+
39
+ get inputVars(): string[] {
40
+ return this.inputVariables;
41
+ }
42
+ }
43
+
44
+ // ============================================================================
45
+ // LLM Chain
46
+ // ============================================================================
47
+
48
+ export interface LLMChainOptions {
49
+ llm: BaseChatModel;
50
+ prompt: PromptTemplate;
51
+ outputKey?: string;
52
+ }
53
+
54
+ export interface CostEstimate {
55
+ estimatedTokensIn: number;
56
+ estimatedTokensOut: number;
57
+ estimatedCostUsd: number;
58
+ estimatedLatencyMs: number;
59
+ model: string;
60
+ pricing: { input: number; output: number };
61
+ }
62
+
63
+ export class LLMChain {
64
+ private llm: BaseChatModel;
65
+ private prompt: PromptTemplate;
66
+ private outputKey: string;
67
+
68
+ constructor(options: LLMChainOptions) {
69
+ this.llm = options.llm;
70
+ this.prompt = options.prompt;
71
+ this.outputKey = options.outputKey ?? 'text';
72
+ }
73
+
74
+ /**
75
+ * Estimate cost before running
76
+ */
77
+ estimateCost(inputs: ChainInputs, model?: string): CostEstimate {
78
+ const modelName = model ?? (this.llm as any).defaultModel ?? 'default';
79
+ const formattedPrompt = this.prompt.format(inputs);
80
+ const estimatedTokensIn = estimateTokens(formattedPrompt);
81
+ const estimatedTokensOut = Math.max(1, Math.floor(estimatedTokensIn / 4));
82
+
83
+ const pricing = getPricing(modelName);
84
+ const estimatedCost =
85
+ (estimatedTokensIn / 1_000_000 * pricing.input) +
86
+ (estimatedTokensOut / 1_000_000 * pricing.output);
87
+
88
+ // Rough latency: 100ms per 1K input + 50ms per 1K output
89
+ const estimatedLatency = Math.floor(estimatedTokensIn * 0.1 + estimatedTokensOut * 0.05);
90
+
91
+ return {
92
+ estimatedTokensIn,
93
+ estimatedTokensOut,
94
+ estimatedCostUsd: Math.round(estimatedCost * 1_000_000) / 1_000_000,
95
+ estimatedLatencyMs: estimatedLatency,
96
+ model: modelName,
97
+ pricing,
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Invoke the chain synchronously
103
+ */
104
+ async invoke(inputs: ChainInputs): Promise<ChainOutputs> {
105
+ const formattedPrompt = this.prompt.format(inputs);
106
+ logger.debug(`[Chain] Prompt: ${formattedPrompt.slice(0, 100)}...`);
107
+
108
+ const messages: Message[] = [{ role: 'user', content: formattedPrompt }];
109
+ const response = await this.llm.invoke(messages);
110
+
111
+ const outputs: ChainOutputs = {
112
+ [this.outputKey]: response.content,
113
+ };
114
+
115
+ // Include usage info if available
116
+ if (response.usage) {
117
+ (outputs as any).usage = response.usage;
118
+ (outputs as any).cost = calculateCost(
119
+ response.model ?? 'default',
120
+ response.usage.prompt_tokens,
121
+ response.usage.completion_tokens
122
+ );
123
+ }
124
+
125
+ return outputs;
126
+ }
127
+
128
+ /**
129
+ * Stream the response
130
+ */
131
+ async *stream(inputs: ChainInputs): AsyncGenerator<string> {
132
+ const formattedPrompt = this.prompt.format(inputs);
133
+ logger.debug(`[Chain Stream] Prompt: ${formattedPrompt.slice(0, 100)}...`);
134
+
135
+ const messages: Message[] = [{ role: 'user', content: formattedPrompt }];
136
+
137
+ for await (const chunk of this.llm.stream?.(messages) ?? []) {
138
+ yield chunk.delta;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Async invoke
144
+ */
145
+ async ainvoke(inputs: ChainInputs): Promise<ChainOutputs> {
146
+ return this.invoke(inputs);
147
+ }
148
+
149
+ /**
150
+ * Async stream
151
+ */
152
+ async *astream(inputs: ChainInputs): AsyncGenerator<string> {
153
+ yield* this.stream(inputs);
154
+ }
155
+ }
156
+
157
+ // ============================================================================
158
+ // Sequential Chain
159
+ // ============================================================================
160
+
161
+ export class SequentialChain {
162
+ private chains: LLMChain[];
163
+ private inputVariables: string[];
164
+ private outputVariables: string[];
165
+
166
+ constructor(options: {
167
+ chains: LLMChain[];
168
+ inputVariables: string[];
169
+ outputVariables: string[];
170
+ }) {
171
+ this.chains = options.chains;
172
+ this.inputVariables = options.inputVariables;
173
+ this.outputVariables = options.outputVariables;
174
+ }
175
+
176
+ async invoke(inputs: ChainInputs): Promise<ChainOutputs> {
177
+ let currentState = { ...inputs };
178
+
179
+ for (let i = 0; i < this.chains.length; i++) {
180
+ logger.debug(`[SequentialChain] Executing Chain ${i + 1}/${this.chains.length}`);
181
+ const chainOutput = await this.chains[i].invoke(currentState);
182
+ currentState = { ...currentState, ...chainOutput };
183
+ }
184
+
185
+ // Return only the requested output variables
186
+ const result: ChainOutputs = {};
187
+ for (const key of this.outputVariables) {
188
+ if (key in currentState) {
189
+ result[key] = currentState[key];
190
+ }
191
+ }
192
+ return result;
193
+ }
194
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * RAG Chain - Retrieval-Augmented Generation
3
+ */
4
+
5
+ import { BaseChatModel, BaseRetriever, Document } from '../core/types.js';
6
+ import { logger } from '../utils/logger.js';
7
+
8
+ const DEFAULT_PROMPT = `You are a helpful assistant. Use the following context to answer the query.
9
+
10
+ Context:
11
+ {context}
12
+
13
+ Query: {query}
14
+
15
+ Answer:`;
16
+
17
+ export class RetrievalQAChain {
18
+ private llm: BaseChatModel;
19
+ private retriever: BaseRetriever;
20
+ private promptTemplate: string;
21
+
22
+ constructor(options: {
23
+ llm: BaseChatModel;
24
+ retriever: BaseRetriever;
25
+ promptTemplate?: string;
26
+ }) {
27
+ this.llm = options.llm;
28
+ this.retriever = options.retriever;
29
+ this.promptTemplate = options.promptTemplate ?? DEFAULT_PROMPT;
30
+ }
31
+
32
+ async invoke(query: string): Promise<{ text: string; documents: Document[] }> {
33
+ const docs = await this.retriever.getRelevantDocuments(query);
34
+
35
+ // Combine documents into context
36
+ const contextParts = docs.map(doc => doc.pageContent);
37
+ const context = contextParts.join('\n\n---\n\n');
38
+
39
+ // Format prompt
40
+ const prompt = this.promptTemplate
41
+ .replace('{context}', context)
42
+ .replace('{query}', query);
43
+
44
+ logger.debug(`[RetrievalQAChain] Retrieved ${docs.length} documents. Invoking LLM.`);
45
+
46
+ const response = await this.llm.invoke([
47
+ { role: 'user', content: prompt }
48
+ ]);
49
+
50
+ return {
51
+ text: response.content,
52
+ documents: docs,
53
+ };
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Factory function for RAG chain
59
+ */
60
+ export function createRetrievalChain(
61
+ llm: BaseChatModel,
62
+ retriever: BaseRetriever
63
+ ): RetrievalQAChain {
64
+ return new RetrievalQAChain({ llm, retriever });
65
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Lazlo Core Types & Protocols
3
+ *
4
+ * The foundation of Lazlo - protocol definitions that any LLM, tool, or memory
5
+ * implementation must satisfy. No massive base classes, just duck typing.
6
+ */
7
+
8
+ // ============================================================================
9
+ // Message Types
10
+ // ============================================================================
11
+
12
+ export interface Message {
13
+ role: 'system' | 'user' | 'assistant' | 'tool';
14
+ content: string;
15
+ name?: string;
16
+ tool_call_id?: string;
17
+ }
18
+
19
+ export interface ToolCall {
20
+ id: string;
21
+ type: 'function';
22
+ function: {
23
+ name: string;
24
+ arguments: string | Record<string, unknown>;
25
+ };
26
+ }
27
+
28
+ export interface ChatResponse {
29
+ content: string;
30
+ tool_calls?: ToolCall[];
31
+ usage?: {
32
+ prompt_tokens: number;
33
+ completion_tokens: number;
34
+ total_tokens: number;
35
+ };
36
+ model?: string;
37
+ finish_reason?: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
38
+ }
39
+
40
+ export interface StreamChunk {
41
+ delta: string;
42
+ finish_reason?: string;
43
+ index?: number;
44
+ }
45
+
46
+ // ============================================================================
47
+ // Protocol Interfaces (Duck Typing Support)
48
+ // ============================================================================
49
+
50
+ export interface BaseLLM {
51
+ invoke(prompt: string, options?: LLMInvokeOptions): Promise<string>;
52
+ ainvoke(prompt: string, options?: LLMInvokeOptions): Promise<string>;
53
+ stream?(prompt: string, options?: LLMInvokeOptions): AsyncGenerator<string>;
54
+ astream?(prompt: string, options?: LLMInvokeOptions): AsyncGenerator<string>;
55
+ }
56
+
57
+ export interface BaseChatModel {
58
+ readonly supportsTools: boolean;
59
+ readonly supportsStructuredOutput: boolean;
60
+
61
+ invoke(messages: Message[], options?: ChatInvokeOptions): Promise<ChatResponse>;
62
+ ainvoke?(messages: Message[], options?: ChatInvokeOptions): Promise<ChatResponse>;
63
+
64
+ stream?(messages: Message[], options?: ChatInvokeOptions): AsyncGenerator<StreamChunk>;
65
+ astream?(messages: Message[], options?: ChatInvokeOptions): AsyncGenerator<StreamChunk>;
66
+ }
67
+
68
+ export interface BaseTool {
69
+ name: string;
70
+ description: string;
71
+ argsSchema?: Record<string, unknown>;
72
+
73
+ invoke(input: string | Record<string, unknown>): Promise<string>;
74
+ ainvoke?(input: string | Record<string, unknown>): Promise<string>;
75
+ }
76
+
77
+ export interface BaseMemory {
78
+ loadMemoryVariables(inputs: Record<string, unknown>): Promise<Record<string, unknown>>;
79
+ saveContext(inputs: Record<string, unknown>, outputs: Record<string, string>): Promise<void>;
80
+ clear(): Promise<void>;
81
+ }
82
+
83
+ export interface BaseRetriever {
84
+ getRelevantDocuments(query: string): Promise<Document[]>;
85
+ }
86
+
87
+ export interface BaseVectorStore {
88
+ addTexts(texts: string[], metadatas?: Record<string, unknown>[]): Promise<string[]>;
89
+ similaritySearch(query: string, k?: number): Promise<Document[]>;
90
+ addDocuments?(documents: Document[]): Promise<string[]>;
91
+ }
92
+
93
+ export interface BaseEmbeddings {
94
+ embedQuery(text: string): Promise<number[]>;
95
+ embedDocuments(texts: string[]): Promise<number[][]>;
96
+ }
97
+
98
+ // ============================================================================
99
+ // Document Types
100
+ // ============================================================================
101
+
102
+ export interface Document {
103
+ pageContent: string;
104
+ metadata: Record<string, unknown>;
105
+ }
106
+
107
+ // ============================================================================
108
+ // Options Types
109
+ // ============================================================================
110
+
111
+ export interface LLMInvokeOptions {
112
+ model?: string;
113
+ temperature?: number;
114
+ maxTokens?: number;
115
+ topP?: number;
116
+ frequencyPenalty?: number;
117
+ presencePenalty?: number;
118
+ stop?: string | string[];
119
+ [key: string]: unknown;
120
+ }
121
+
122
+ export interface ChatInvokeOptions extends LLMInvokeOptions {
123
+ tools?: ToolDefinition[];
124
+ responseFormat?: ResponseFormat;
125
+ }
126
+
127
+ export interface ToolDefinition {
128
+ type: 'function';
129
+ function: {
130
+ name: string;
131
+ description: string;
132
+ parameters: Record<string, unknown>;
133
+ };
134
+ }
135
+
136
+ export interface ResponseFormat {
137
+ type: 'text' | 'json_object' | 'json_schema';
138
+ json_schema?: {
139
+ name: string;
140
+ schema: Record<string, unknown>;
141
+ strict?: boolean;
142
+ };
143
+ }
144
+
145
+ // ============================================================================
146
+ // Chain Types
147
+ // ============================================================================
148
+
149
+ export interface ChainInputs {
150
+ [key: string]: unknown;
151
+ }
152
+
153
+ export interface ChainOutputs {
154
+ [key: string]: unknown;
155
+ }
156
+
157
+ export interface Chain {
158
+ invoke(inputs: ChainInputs): Promise<ChainOutputs>;
159
+ ainvoke?(inputs: ChainInputs): Promise<ChainOutputs>;
160
+ }
161
+
162
+ // ============================================================================
163
+ // Pricing Types
164
+ // ============================================================================
165
+
166
+ export interface ModelPricing {
167
+ input: number; // per 1M tokens
168
+ output: number; // per 1M tokens
169
+ }
170
+
171
+ // ============================================================================
172
+ // Cached Types
173
+ // ============================================================================
174
+
175
+ export type JsonPrimitive = string | number | boolean | null;
176
+ export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
177
+ export interface JsonObject { [key: string]: JsonValue; }
178
+ export interface JsonArray extends Array<JsonValue> {}