@vistagenic/vista 0.2.16 → 0.3.2

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 (153) hide show
  1. package/bin/vista.js +184 -177
  2. package/dist/ai/agent.d.ts +37 -0
  3. package/dist/ai/agent.js +385 -0
  4. package/dist/ai/embeddings.d.ts +11 -0
  5. package/dist/ai/embeddings.js +71 -0
  6. package/dist/ai/index.d.ts +10 -0
  7. package/dist/ai/index.js +26 -0
  8. package/dist/ai/memory.d.ts +16 -0
  9. package/dist/ai/memory.js +39 -0
  10. package/dist/ai/observability.d.ts +21 -0
  11. package/dist/ai/observability.js +69 -0
  12. package/dist/ai/providers/anthropic.d.ts +2 -0
  13. package/dist/ai/providers/anthropic.js +190 -0
  14. package/dist/ai/providers/base.d.ts +7 -0
  15. package/dist/ai/providers/base.js +85 -0
  16. package/dist/ai/providers/gemini.d.ts +2 -0
  17. package/dist/ai/providers/gemini.js +194 -0
  18. package/dist/ai/providers/index.d.ts +5 -0
  19. package/dist/ai/providers/index.js +21 -0
  20. package/dist/ai/providers/mock.d.ts +8 -0
  21. package/dist/ai/providers/mock.js +77 -0
  22. package/dist/ai/providers/openai.d.ts +2 -0
  23. package/dist/ai/providers/openai.js +211 -0
  24. package/dist/ai/rag.d.ts +35 -0
  25. package/dist/ai/rag.js +110 -0
  26. package/dist/ai/react/index.d.ts +1 -0
  27. package/dist/ai/react/index.js +17 -0
  28. package/dist/ai/react/react-server.d.ts +1 -0
  29. package/dist/ai/react/react-server.js +17 -0
  30. package/dist/ai/react/use-agent.d.ts +23 -0
  31. package/dist/ai/react/use-agent.js +138 -0
  32. package/dist/ai/stream.d.ts +24 -0
  33. package/dist/ai/stream.js +109 -0
  34. package/dist/ai/tool.d.ts +11 -0
  35. package/dist/ai/tool.js +47 -0
  36. package/dist/ai/types.d.ts +117 -0
  37. package/dist/ai/types.js +5 -0
  38. package/dist/auth/core.d.ts +140 -0
  39. package/dist/auth/core.js +165 -0
  40. package/dist/auth/index.d.ts +20 -8
  41. package/dist/auth/index.js +369 -16
  42. package/dist/auth/react-server.d.ts +1 -0
  43. package/dist/auth/react-server.js +10 -0
  44. package/dist/auth/react.d.ts +18 -0
  45. package/dist/auth/react.js +71 -0
  46. package/dist/bin/build-rsc.js +602 -604
  47. package/dist/bin/build.js +389 -388
  48. package/dist/bin/deploy-output.d.ts +2 -7
  49. package/dist/bin/deploy-output.js +3 -76
  50. package/dist/bin/deploy.d.ts +7 -0
  51. package/dist/bin/deploy.js +102 -0
  52. package/dist/bin/dev-error-overlay-snippet.js +778 -552
  53. package/dist/bin/devtools-indicator-snippet.js +387 -387
  54. package/dist/bin/generate.js +510 -248
  55. package/dist/build/manifest.d.ts +169 -139
  56. package/dist/build/manifest.js +423 -367
  57. package/dist/build/rsc/client-manifest.d.ts +62 -52
  58. package/dist/build/rsc/client-manifest.js +295 -193
  59. package/dist/build/rsc/client-reference-plugin.d.ts +37 -37
  60. package/dist/build/rsc/client-reference-plugin.js +160 -160
  61. package/dist/build/rsc/native-scanner.d.ts +135 -123
  62. package/dist/build/rsc/native-scanner.js +203 -170
  63. package/dist/build/rsc/react-client-reference-manifest.d.ts +28 -22
  64. package/dist/build/rsc/react-client-reference-manifest.js +240 -219
  65. package/dist/build/rsc/rsc-renderer.d.ts +99 -99
  66. package/dist/build/rsc/rsc-renderer.js +263 -263
  67. package/dist/build/rsc/server-component-loader.d.ts +19 -19
  68. package/dist/build/rsc/server-component-loader.js +91 -91
  69. package/dist/build/rsc/server-manifest.d.ts +17 -0
  70. package/dist/build/rsc/server-manifest.js +20 -0
  71. package/dist/build/standalone.js +337 -334
  72. package/dist/build/webpack/plugins/vista-flight-plugin.js +5 -5
  73. package/dist/client/dynamic.react-server.d.ts +2 -0
  74. package/dist/client/dynamic.react-server.js +23 -0
  75. package/dist/client/link.react-server.d.ts +2 -0
  76. package/dist/client/link.react-server.js +11 -0
  77. package/dist/client/navigation.react-server.d.ts +1 -0
  78. package/dist/client/navigation.react-server.js +17 -0
  79. package/dist/client/router.react-server.d.ts +1 -0
  80. package/dist/client/router.react-server.js +17 -0
  81. package/dist/client/rsc-router.react-server.d.ts +1 -0
  82. package/dist/client/rsc-router.react-server.js +17 -0
  83. package/dist/client/script.react-server.d.ts +2 -0
  84. package/dist/client/script.react-server.js +23 -0
  85. package/dist/components/client-island.d.ts +34 -34
  86. package/dist/components/client-island.js +75 -75
  87. package/dist/config.d.ts +17 -0
  88. package/dist/config.js +60 -1
  89. package/dist/deploy/adapters/cloudflare.d.ts +2 -0
  90. package/dist/deploy/adapters/cloudflare.js +124 -0
  91. package/dist/deploy/adapters/docker.d.ts +2 -0
  92. package/dist/deploy/adapters/docker.js +112 -0
  93. package/dist/deploy/adapters/index.d.ts +15 -0
  94. package/dist/deploy/adapters/index.js +24 -0
  95. package/dist/deploy/adapters/netlify.d.ts +2 -0
  96. package/dist/deploy/adapters/netlify.js +115 -0
  97. package/dist/deploy/adapters/render.d.ts +2 -0
  98. package/dist/deploy/adapters/render.js +95 -0
  99. package/dist/deploy/adapters/vercel.d.ts +7 -0
  100. package/dist/deploy/adapters/vercel.js +164 -0
  101. package/dist/deploy/cli-runner.d.ts +8 -0
  102. package/dist/deploy/cli-runner.js +58 -0
  103. package/dist/deploy/detect.d.ts +6 -0
  104. package/dist/deploy/detect.js +77 -0
  105. package/dist/deploy/index.d.ts +24 -0
  106. package/dist/deploy/index.js +112 -0
  107. package/dist/deploy/preflight.d.ts +8 -0
  108. package/dist/deploy/preflight.js +80 -0
  109. package/dist/deploy/types.d.ts +48 -0
  110. package/dist/deploy/types.js +2 -0
  111. package/dist/deploy/utils.d.ts +18 -0
  112. package/dist/deploy/utils.js +70 -0
  113. package/dist/dev-error.d.ts +14 -0
  114. package/dist/dev-error.js +1763 -705
  115. package/dist/index.d.ts +23 -21
  116. package/dist/index.js +61 -57
  117. package/dist/server/cookie-parse.d.ts +4 -0
  118. package/dist/server/cookie-parse.js +14 -0
  119. package/dist/server/engine.js +7 -26
  120. package/dist/server/index.d.ts +109 -102
  121. package/dist/server/index.js +315 -286
  122. package/dist/server/middleware-runner.d.ts +125 -57
  123. package/dist/server/middleware-runner.js +615 -218
  124. package/dist/server/middleware-security.d.ts +36 -0
  125. package/dist/server/middleware-security.js +183 -0
  126. package/dist/server/module-compile-hook.js +695 -662
  127. package/dist/server/route-handler-registry.d.ts +65 -0
  128. package/dist/server/route-handler-registry.js +195 -0
  129. package/dist/server/route-patterns.d.ts +67 -0
  130. package/dist/server/route-patterns.js +186 -0
  131. package/dist/server/rsc-engine.js +75 -92
  132. package/dist/server/rsc-module-system.d.ts +33 -33
  133. package/dist/server/rsc-module-system.js +87 -87
  134. package/dist/server/rsc-upstream.js +892 -888
  135. package/dist/server/static-generator.js +10 -10
  136. package/dist/server/typed-api-runtime.d.ts +18 -0
  137. package/dist/server/typed-api-runtime.js +635 -507
  138. package/dist/server/vista-import-map.js +134 -123
  139. package/dist/stack/index.d.ts +34 -32
  140. package/dist/stack/index.js +49 -45
  141. package/dist/stack/server/caller.d.ts +13 -0
  142. package/dist/stack/server/caller.js +42 -0
  143. package/dist/stack/server/executor.d.ts +40 -36
  144. package/dist/stack/server/executor.js +222 -174
  145. package/dist/stack/server/index.d.ts +11 -10
  146. package/dist/stack/server/index.js +24 -23
  147. package/dist/stack/server/procedure.d.ts +20 -18
  148. package/dist/stack/server/procedure.js +66 -58
  149. package/dist/stack/server/types.d.ts +113 -100
  150. package/dist/theme/react-server.d.ts +10 -0
  151. package/dist/theme/react-server.js +16 -0
  152. package/package.json +28 -3
  153. package/LICENSE +0 -21
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAnthropicModel = createAnthropicModel;
4
+ const tool_1 = require("../tool");
5
+ function formatMessagesForAnthropic(messages) {
6
+ const result = [];
7
+ for (const msg of messages) {
8
+ if (msg.role === 'system') {
9
+ // System prompt is handled separately in Anthropic
10
+ continue;
11
+ }
12
+ if (msg.role === 'tool') {
13
+ result.push({
14
+ role: 'user',
15
+ content: [
16
+ {
17
+ type: 'tool_result',
18
+ tool_use_id: msg.toolCallId || 'call_default',
19
+ content: msg.content,
20
+ },
21
+ ],
22
+ });
23
+ }
24
+ else if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {
25
+ const contentBlocks = [];
26
+ if (msg.content) {
27
+ contentBlocks.push({ type: 'text', text: msg.content });
28
+ }
29
+ for (const tc of msg.toolCalls) {
30
+ contentBlocks.push({
31
+ type: 'tool_use',
32
+ id: tc.id,
33
+ name: tc.name,
34
+ input: typeof tc.arguments === 'object' ? tc.arguments : JSON.parse(tc.arguments || '{}'),
35
+ });
36
+ }
37
+ result.push({ role: 'assistant', content: contentBlocks });
38
+ }
39
+ else {
40
+ result.push({
41
+ role: msg.role === 'assistant' ? 'assistant' : 'user',
42
+ content: msg.content,
43
+ });
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+ function createAnthropicModel(options) {
49
+ const baseURL = (options.baseURL ||
50
+ process.env.ANTHROPIC_BASE_URL ||
51
+ 'https://api.anthropic.com/v1').replace(/\/+$/, '');
52
+ const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY || '';
53
+ const modelName = options.model || 'claude-3-5-sonnet-20241022';
54
+ return {
55
+ provider: 'anthropic',
56
+ modelName,
57
+ async generateText(genOptions) {
58
+ const url = `${baseURL}/messages`;
59
+ const messages = formatMessagesForAnthropic(genOptions.messages);
60
+ const body = {
61
+ model: modelName,
62
+ messages,
63
+ max_tokens: genOptions.maxTokens || options.maxTokens || 4096,
64
+ temperature: genOptions.temperature ?? options.temperature ?? 0.7,
65
+ };
66
+ if (genOptions.systemPrompt) {
67
+ body.system = genOptions.systemPrompt;
68
+ }
69
+ if (genOptions.tools && genOptions.tools.length > 0) {
70
+ body.tools = genOptions.tools.map(tool_1.formatToolForAnthropic);
71
+ }
72
+ const headers = {
73
+ 'Content-Type': 'application/json',
74
+ 'x-api-key': apiKey,
75
+ 'anthropic-version': '2023-06-01',
76
+ ...(options.headers || {}),
77
+ };
78
+ const res = await fetch(url, {
79
+ method: 'POST',
80
+ headers,
81
+ body: JSON.stringify(body),
82
+ signal: genOptions.abortSignal,
83
+ });
84
+ if (!res.ok) {
85
+ const errText = await res.text().catch(() => '');
86
+ throw new Error(`Anthropic API request failed [${res.status}]: ${errText}`);
87
+ }
88
+ const data = await res.json();
89
+ let text = '';
90
+ const toolCalls = [];
91
+ if (Array.isArray(data.content)) {
92
+ for (const block of data.content) {
93
+ if (block.type === 'text') {
94
+ text += block.text;
95
+ }
96
+ else if (block.type === 'tool_use') {
97
+ toolCalls.push({
98
+ id: block.id,
99
+ name: block.name,
100
+ arguments: block.input,
101
+ });
102
+ }
103
+ }
104
+ }
105
+ return {
106
+ text,
107
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
108
+ finishReason: data.stop_reason || 'stop',
109
+ usage: data.usage
110
+ ? {
111
+ promptTokens: data.usage.input_tokens || 0,
112
+ completionTokens: data.usage.output_tokens || 0,
113
+ totalTokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
114
+ }
115
+ : undefined,
116
+ raw: data,
117
+ };
118
+ },
119
+ async *streamText(genOptions) {
120
+ const url = `${baseURL}/messages`;
121
+ const messages = formatMessagesForAnthropic(genOptions.messages);
122
+ const body = {
123
+ model: modelName,
124
+ messages,
125
+ max_tokens: genOptions.maxTokens || options.maxTokens || 4096,
126
+ temperature: genOptions.temperature ?? options.temperature ?? 0.7,
127
+ stream: true,
128
+ };
129
+ if (genOptions.systemPrompt) {
130
+ body.system = genOptions.systemPrompt;
131
+ }
132
+ if (genOptions.tools && genOptions.tools.length > 0) {
133
+ body.tools = genOptions.tools.map(tool_1.formatToolForAnthropic);
134
+ }
135
+ const headers = {
136
+ 'Content-Type': 'application/json',
137
+ 'x-api-key': apiKey,
138
+ 'anthropic-version': '2023-06-01',
139
+ ...(options.headers || {}),
140
+ };
141
+ const res = await fetch(url, {
142
+ method: 'POST',
143
+ headers,
144
+ body: JSON.stringify(body),
145
+ signal: genOptions.abortSignal,
146
+ });
147
+ if (!res.ok) {
148
+ const errText = await res.text().catch(() => '');
149
+ throw new Error(`Anthropic stream request failed [${res.status}]: ${errText}`);
150
+ }
151
+ if (!res.body) {
152
+ throw new Error('ReadableStream not supported on fetch response');
153
+ }
154
+ const reader = res.body.getReader();
155
+ const decoder = new TextDecoder();
156
+ let buffer = '';
157
+ try {
158
+ while (true) {
159
+ const { done, value } = await reader.read();
160
+ if (done)
161
+ break;
162
+ buffer += decoder.decode(value, { stream: true });
163
+ const lines = buffer.split('\n');
164
+ buffer = lines.pop() || '';
165
+ for (const line of lines) {
166
+ const trimmed = line.trim();
167
+ if (!trimmed.startsWith('data: '))
168
+ continue;
169
+ const payload = trimmed.slice(6);
170
+ if (payload === '[DONE]')
171
+ break;
172
+ try {
173
+ const event = JSON.parse(payload);
174
+ if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
175
+ yield { type: 'text-delta', textDelta: event.delta.text };
176
+ }
177
+ }
178
+ catch {
179
+ // Ignore partial JSON parse errors
180
+ }
181
+ }
182
+ }
183
+ }
184
+ finally {
185
+ reader.releaseLock();
186
+ }
187
+ yield { type: 'done' };
188
+ },
189
+ };
190
+ }
@@ -0,0 +1,7 @@
1
+ import type { LanguageModel, ModelOptions } from '../types';
2
+ export interface ParsedModel {
3
+ provider: string;
4
+ modelName: string;
5
+ }
6
+ export declare function parseModelIdentifier(model: string): ParsedModel;
7
+ export declare function resolveModel(model: string | LanguageModel, options?: Partial<ModelOptions>): LanguageModel;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseModelIdentifier = parseModelIdentifier;
4
+ exports.resolveModel = resolveModel;
5
+ const openai_1 = require("./openai");
6
+ const anthropic_1 = require("./anthropic");
7
+ const gemini_1 = require("./gemini");
8
+ const mock_1 = require("./mock");
9
+ function parseModelIdentifier(model) {
10
+ const trimmed = model.trim();
11
+ const colonIndex = trimmed.indexOf(':');
12
+ if (colonIndex !== -1) {
13
+ const provider = trimmed.slice(0, colonIndex).toLowerCase();
14
+ const modelName = trimmed.slice(colonIndex + 1);
15
+ return { provider, modelName };
16
+ }
17
+ // Heuristic guessing if prefix omitted
18
+ const lower = trimmed.toLowerCase();
19
+ if (lower.startsWith('gpt-') || lower.startsWith('o1-') || lower.startsWith('o3-')) {
20
+ return { provider: 'openai', modelName: trimmed };
21
+ }
22
+ if (lower.startsWith('claude-')) {
23
+ return { provider: 'anthropic', modelName: trimmed };
24
+ }
25
+ if (lower.startsWith('gemini-')) {
26
+ return { provider: 'gemini', modelName: trimmed };
27
+ }
28
+ if (lower.startsWith('mock')) {
29
+ return { provider: 'mock', modelName: trimmed };
30
+ }
31
+ if (lower.startsWith('llama-') || lower.startsWith('mixtral-') || lower.startsWith('gemma2-')) {
32
+ return { provider: 'groq', modelName: trimmed };
33
+ }
34
+ // Default fallback
35
+ return { provider: 'openai', modelName: trimmed };
36
+ }
37
+ function resolveModel(model, options = {}) {
38
+ if (typeof model === 'object' && model !== null && 'generateText' in model) {
39
+ return model;
40
+ }
41
+ if (typeof model !== 'string') {
42
+ throw new Error('Model must be a model string or a LanguageModel implementation');
43
+ }
44
+ const { provider, modelName } = parseModelIdentifier(model);
45
+ const modelOptions = {
46
+ model: modelName,
47
+ ...options,
48
+ };
49
+ switch (provider) {
50
+ case 'openai':
51
+ return (0, openai_1.createOpenAIModel)(modelOptions);
52
+ case 'anthropic':
53
+ return (0, anthropic_1.createAnthropicModel)(modelOptions);
54
+ case 'gemini':
55
+ return (0, gemini_1.createGeminiModel)(modelOptions);
56
+ case 'ollama':
57
+ return (0, openai_1.createOpenAIModel)({
58
+ ...modelOptions,
59
+ baseURL: options.baseURL || process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
60
+ apiKey: options.apiKey || 'ollama',
61
+ });
62
+ case 'nvidia':
63
+ case 'nim':
64
+ return (0, openai_1.createOpenAIModel)({
65
+ ...modelOptions,
66
+ baseURL: options.baseURL ||
67
+ process.env.NVIDIA_BASE_URL ||
68
+ process.env.NIM_BASE_URL ||
69
+ 'https://integrate.api.nvidia.com/v1',
70
+ apiKey: options.apiKey || process.env.NVIDIA_API_KEY || process.env.NIM_API_KEY || '',
71
+ });
72
+ case 'groq':
73
+ return (0, openai_1.createOpenAIModel)({
74
+ ...modelOptions,
75
+ baseURL: options.baseURL || process.env.GROQ_BASE_URL || 'https://api.groq.com/openai/v1',
76
+ apiKey: options.apiKey || process.env.GROQ_API_KEY || '',
77
+ });
78
+ case 'mock':
79
+ return (0, mock_1.createMockModel)({
80
+ modelName,
81
+ });
82
+ default:
83
+ throw new Error(`Unsupported model provider "${provider}". Supported providers: openai, anthropic, gemini, ollama, nvidia, groq, mock.`);
84
+ }
85
+ }
@@ -0,0 +1,2 @@
1
+ import type { LanguageModel, ModelOptions } from '../types';
2
+ export declare function createGeminiModel(options: ModelOptions): LanguageModel;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGeminiModel = createGeminiModel;
4
+ const tool_1 = require("../tool");
5
+ function formatMessagesForGemini(messages) {
6
+ const contents = [];
7
+ for (const msg of messages) {
8
+ if (msg.role === 'system')
9
+ continue;
10
+ if (msg.role === 'tool') {
11
+ contents.push({
12
+ role: 'user',
13
+ parts: [
14
+ {
15
+ functionResponse: {
16
+ name: msg.name || 'tool_response',
17
+ response: { content: msg.content },
18
+ },
19
+ },
20
+ ],
21
+ });
22
+ }
23
+ else if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {
24
+ const parts = [];
25
+ if (msg.content) {
26
+ parts.push({ text: msg.content });
27
+ }
28
+ for (const tc of msg.toolCalls) {
29
+ parts.push({
30
+ functionCall: {
31
+ name: tc.name,
32
+ args: typeof tc.arguments === 'object' ? tc.arguments : JSON.parse(tc.arguments || '{}'),
33
+ },
34
+ });
35
+ }
36
+ contents.push({ role: 'model', parts });
37
+ }
38
+ else {
39
+ contents.push({
40
+ role: msg.role === 'assistant' ? 'model' : 'user',
41
+ parts: [{ text: msg.content }],
42
+ });
43
+ }
44
+ }
45
+ return contents;
46
+ }
47
+ function createGeminiModel(options) {
48
+ const baseURL = (options.baseURL ||
49
+ process.env.GEMINI_BASE_URL ||
50
+ 'https://generativelanguage.googleapis.com/v1beta').replace(/\/+$/, '');
51
+ const apiKey = options.apiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || '';
52
+ const modelName = options.model || 'gemini-1.5-flash';
53
+ return {
54
+ provider: 'gemini',
55
+ modelName,
56
+ async generateText(genOptions) {
57
+ const url = `${baseURL}/models/${modelName}:generateContent?key=${apiKey}`;
58
+ const contents = formatMessagesForGemini(genOptions.messages);
59
+ const body = {
60
+ contents,
61
+ generationConfig: {
62
+ temperature: genOptions.temperature ?? options.temperature ?? 0.7,
63
+ },
64
+ };
65
+ if (genOptions.systemPrompt) {
66
+ body.systemInstruction = {
67
+ parts: [{ text: genOptions.systemPrompt }],
68
+ };
69
+ }
70
+ if (genOptions.maxTokens || options.maxTokens) {
71
+ body.generationConfig.maxOutputTokens = genOptions.maxTokens || options.maxTokens;
72
+ }
73
+ if (genOptions.tools && genOptions.tools.length > 0) {
74
+ body.tools = [
75
+ {
76
+ functionDeclarations: genOptions.tools.map(tool_1.formatToolForGemini),
77
+ },
78
+ ];
79
+ }
80
+ const res = await fetch(url, {
81
+ method: 'POST',
82
+ headers: { 'Content-Type': 'application/json' },
83
+ body: JSON.stringify(body),
84
+ signal: genOptions.abortSignal,
85
+ });
86
+ if (!res.ok) {
87
+ const errText = await res.text().catch(() => '');
88
+ throw new Error(`Gemini API request failed [${res.status}]: ${errText}`);
89
+ }
90
+ const data = await res.json();
91
+ const candidate = data.candidates?.[0];
92
+ const parts = candidate?.content?.parts || [];
93
+ let text = '';
94
+ const toolCalls = [];
95
+ for (const part of parts) {
96
+ if (part.text) {
97
+ text += part.text;
98
+ }
99
+ else if (part.functionCall) {
100
+ toolCalls.push({
101
+ id: `call_${Date.now()}_${toolCalls.length}`,
102
+ name: part.functionCall.name,
103
+ arguments: part.functionCall.args || {},
104
+ });
105
+ }
106
+ }
107
+ const usageMetadata = data.usageMetadata;
108
+ return {
109
+ text,
110
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
111
+ finishReason: candidate?.finishReason || 'stop',
112
+ usage: usageMetadata
113
+ ? {
114
+ promptTokens: usageMetadata.promptTokenCount || 0,
115
+ completionTokens: usageMetadata.candidatesTokenCount || 0,
116
+ totalTokens: usageMetadata.totalTokenCount || 0,
117
+ }
118
+ : undefined,
119
+ raw: data,
120
+ };
121
+ },
122
+ async *streamText(genOptions) {
123
+ const url = `${baseURL}/models/${modelName}:streamGenerateContent?alt=sse&key=${apiKey}`;
124
+ const contents = formatMessagesForGemini(genOptions.messages);
125
+ const body = {
126
+ contents,
127
+ generationConfig: {
128
+ temperature: genOptions.temperature ?? options.temperature ?? 0.7,
129
+ },
130
+ };
131
+ if (genOptions.systemPrompt) {
132
+ body.systemInstruction = {
133
+ parts: [{ text: genOptions.systemPrompt }],
134
+ };
135
+ }
136
+ if (genOptions.tools && genOptions.tools.length > 0) {
137
+ body.tools = [
138
+ {
139
+ functionDeclarations: genOptions.tools.map(tool_1.formatToolForGemini),
140
+ },
141
+ ];
142
+ }
143
+ const res = await fetch(url, {
144
+ method: 'POST',
145
+ headers: { 'Content-Type': 'application/json' },
146
+ body: JSON.stringify(body),
147
+ signal: genOptions.abortSignal,
148
+ });
149
+ if (!res.ok) {
150
+ const errText = await res.text().catch(() => '');
151
+ throw new Error(`Gemini stream request failed [${res.status}]: ${errText}`);
152
+ }
153
+ if (!res.body) {
154
+ throw new Error('ReadableStream not supported on fetch response');
155
+ }
156
+ const reader = res.body.getReader();
157
+ const decoder = new TextDecoder();
158
+ let buffer = '';
159
+ try {
160
+ while (true) {
161
+ const { done, value } = await reader.read();
162
+ if (done)
163
+ break;
164
+ buffer += decoder.decode(value, { stream: true });
165
+ const lines = buffer.split('\n');
166
+ buffer = lines.pop() || '';
167
+ for (const line of lines) {
168
+ const trimmed = line.trim();
169
+ if (!trimmed.startsWith('data: '))
170
+ continue;
171
+ const payload = trimmed.slice(6);
172
+ try {
173
+ const data = JSON.parse(payload);
174
+ const candidate = data.candidates?.[0];
175
+ const parts = candidate?.content?.parts || [];
176
+ for (const part of parts) {
177
+ if (part.text) {
178
+ yield { type: 'text-delta', textDelta: part.text };
179
+ }
180
+ }
181
+ }
182
+ catch {
183
+ // Ignore partial JSON parse errors
184
+ }
185
+ }
186
+ }
187
+ }
188
+ finally {
189
+ reader.releaseLock();
190
+ }
191
+ yield { type: 'done' };
192
+ },
193
+ };
194
+ }
@@ -0,0 +1,5 @@
1
+ export * from './base';
2
+ export * from './openai';
3
+ export * from './anthropic';
4
+ export * from './gemini';
5
+ export * from './mock';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./base"), exports);
18
+ __exportStar(require("./openai"), exports);
19
+ __exportStar(require("./anthropic"), exports);
20
+ __exportStar(require("./gemini"), exports);
21
+ __exportStar(require("./mock"), exports);
@@ -0,0 +1,8 @@
1
+ import type { LanguageModel, ToolCall } from '../types';
2
+ export interface MockModelOptions {
3
+ modelName?: string;
4
+ defaultResponse?: string;
5
+ cannedResponses?: string[];
6
+ toolCalls?: ToolCall[];
7
+ }
8
+ export declare function createMockModel(options?: MockModelOptions): LanguageModel;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMockModel = createMockModel;
4
+ function createMockModel(options = {}) {
5
+ const modelName = options.modelName || 'mock-model';
6
+ let responseIndex = 0;
7
+ return {
8
+ provider: 'mock',
9
+ modelName,
10
+ async generateText(genOptions) {
11
+ // Check if last user message asks for a tool or if simulated tool calls provided
12
+ const lastMsg = genOptions.messages[genOptions.messages.length - 1];
13
+ const content = lastMsg ? lastMsg.content : '';
14
+ // If simulated tool calls exist and haven't been provided in options yet
15
+ if (options.toolCalls && options.toolCalls.length > 0 && !lastMsg?.toolCallId) {
16
+ return {
17
+ text: '',
18
+ toolCalls: options.toolCalls,
19
+ usage: { promptTokens: 10, completionTokens: 10, totalTokens: 20 },
20
+ finishReason: 'tool-calls',
21
+ };
22
+ }
23
+ // Check if user content triggers tool simulation for tests
24
+ if (genOptions.tools && genOptions.tools.length > 0 && content.includes('CALL_TOOL:')) {
25
+ const match = content.match(/CALL_TOOL:([a-zA-Z0-9_-]+)\((.*?)\)/);
26
+ if (match) {
27
+ const toolName = match[1];
28
+ let args = {};
29
+ try {
30
+ args = JSON.parse(match[2] || '{}');
31
+ }
32
+ catch {
33
+ args = { query: match[2] };
34
+ }
35
+ return {
36
+ text: '',
37
+ toolCalls: [{ id: `call_${Date.now()}`, name: toolName, arguments: args }],
38
+ usage: { promptTokens: 15, completionTokens: 10, totalTokens: 25 },
39
+ finishReason: 'tool-calls',
40
+ };
41
+ }
42
+ }
43
+ let text = options.defaultResponse || `Mock response for: "${content.slice(0, 30)}"`;
44
+ if (options.cannedResponses && options.cannedResponses.length > 0) {
45
+ text = options.cannedResponses[responseIndex % options.cannedResponses.length];
46
+ responseIndex++;
47
+ }
48
+ return {
49
+ text,
50
+ usage: {
51
+ promptTokens: Math.max(1, content.length / 4),
52
+ completionTokens: Math.max(1, text.length / 4),
53
+ totalTokens: Math.max(2, (content.length + text.length) / 4),
54
+ },
55
+ finishReason: 'stop',
56
+ };
57
+ },
58
+ async *streamText(genOptions) {
59
+ const result = await this.generateText(genOptions);
60
+ if (result.toolCalls && result.toolCalls.length > 0) {
61
+ for (const call of result.toolCalls) {
62
+ yield { type: 'tool-call', toolCall: call };
63
+ }
64
+ return;
65
+ }
66
+ const words = result.text.split(' ');
67
+ for (let i = 0; i < words.length; i++) {
68
+ const chunk = (i === 0 ? '' : ' ') + words[i];
69
+ yield { type: 'text-delta', textDelta: chunk };
70
+ }
71
+ yield {
72
+ type: 'done',
73
+ usage: result.usage,
74
+ };
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,2 @@
1
+ import type { LanguageModel, ModelOptions } from '../types';
2
+ export declare function createOpenAIModel(options: ModelOptions): LanguageModel;