@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.
- package/bin/vista.js +184 -177
- package/dist/ai/agent.d.ts +37 -0
- package/dist/ai/agent.js +385 -0
- package/dist/ai/embeddings.d.ts +11 -0
- package/dist/ai/embeddings.js +71 -0
- package/dist/ai/index.d.ts +10 -0
- package/dist/ai/index.js +26 -0
- package/dist/ai/memory.d.ts +16 -0
- package/dist/ai/memory.js +39 -0
- package/dist/ai/observability.d.ts +21 -0
- package/dist/ai/observability.js +69 -0
- package/dist/ai/providers/anthropic.d.ts +2 -0
- package/dist/ai/providers/anthropic.js +190 -0
- package/dist/ai/providers/base.d.ts +7 -0
- package/dist/ai/providers/base.js +85 -0
- package/dist/ai/providers/gemini.d.ts +2 -0
- package/dist/ai/providers/gemini.js +194 -0
- package/dist/ai/providers/index.d.ts +5 -0
- package/dist/ai/providers/index.js +21 -0
- package/dist/ai/providers/mock.d.ts +8 -0
- package/dist/ai/providers/mock.js +77 -0
- package/dist/ai/providers/openai.d.ts +2 -0
- package/dist/ai/providers/openai.js +211 -0
- package/dist/ai/rag.d.ts +35 -0
- package/dist/ai/rag.js +110 -0
- package/dist/ai/react/index.d.ts +1 -0
- package/dist/ai/react/index.js +17 -0
- package/dist/ai/react/react-server.d.ts +1 -0
- package/dist/ai/react/react-server.js +17 -0
- package/dist/ai/react/use-agent.d.ts +23 -0
- package/dist/ai/react/use-agent.js +138 -0
- package/dist/ai/stream.d.ts +24 -0
- package/dist/ai/stream.js +109 -0
- package/dist/ai/tool.d.ts +11 -0
- package/dist/ai/tool.js +47 -0
- package/dist/ai/types.d.ts +117 -0
- package/dist/ai/types.js +5 -0
- package/dist/auth/core.d.ts +140 -0
- package/dist/auth/core.js +165 -0
- package/dist/auth/index.d.ts +20 -8
- package/dist/auth/index.js +369 -16
- package/dist/auth/react-server.d.ts +1 -0
- package/dist/auth/react-server.js +10 -0
- package/dist/auth/react.d.ts +18 -0
- package/dist/auth/react.js +71 -0
- package/dist/bin/build-rsc.js +602 -604
- package/dist/bin/build.js +389 -388
- package/dist/bin/deploy-output.d.ts +2 -7
- package/dist/bin/deploy-output.js +3 -76
- package/dist/bin/deploy.d.ts +7 -0
- package/dist/bin/deploy.js +102 -0
- package/dist/bin/dev-error-overlay-snippet.js +778 -552
- package/dist/bin/devtools-indicator-snippet.js +387 -387
- package/dist/bin/generate.js +510 -248
- package/dist/build/manifest.d.ts +169 -139
- package/dist/build/manifest.js +423 -367
- package/dist/build/rsc/client-manifest.d.ts +62 -52
- package/dist/build/rsc/client-manifest.js +295 -193
- package/dist/build/rsc/client-reference-plugin.d.ts +37 -37
- package/dist/build/rsc/client-reference-plugin.js +160 -160
- package/dist/build/rsc/native-scanner.d.ts +135 -123
- package/dist/build/rsc/native-scanner.js +203 -170
- package/dist/build/rsc/react-client-reference-manifest.d.ts +28 -22
- package/dist/build/rsc/react-client-reference-manifest.js +240 -219
- package/dist/build/rsc/rsc-renderer.d.ts +99 -99
- package/dist/build/rsc/rsc-renderer.js +263 -263
- package/dist/build/rsc/server-component-loader.d.ts +19 -19
- package/dist/build/rsc/server-component-loader.js +91 -91
- package/dist/build/rsc/server-manifest.d.ts +17 -0
- package/dist/build/rsc/server-manifest.js +20 -0
- package/dist/build/standalone.js +337 -334
- package/dist/build/webpack/plugins/vista-flight-plugin.js +5 -5
- package/dist/client/dynamic.react-server.d.ts +2 -0
- package/dist/client/dynamic.react-server.js +23 -0
- package/dist/client/link.react-server.d.ts +2 -0
- package/dist/client/link.react-server.js +11 -0
- package/dist/client/navigation.react-server.d.ts +1 -0
- package/dist/client/navigation.react-server.js +17 -0
- package/dist/client/router.react-server.d.ts +1 -0
- package/dist/client/router.react-server.js +17 -0
- package/dist/client/rsc-router.react-server.d.ts +1 -0
- package/dist/client/rsc-router.react-server.js +17 -0
- package/dist/client/script.react-server.d.ts +2 -0
- package/dist/client/script.react-server.js +23 -0
- package/dist/components/client-island.d.ts +34 -34
- package/dist/components/client-island.js +75 -75
- package/dist/config.d.ts +17 -0
- package/dist/config.js +60 -1
- package/dist/deploy/adapters/cloudflare.d.ts +2 -0
- package/dist/deploy/adapters/cloudflare.js +124 -0
- package/dist/deploy/adapters/docker.d.ts +2 -0
- package/dist/deploy/adapters/docker.js +112 -0
- package/dist/deploy/adapters/index.d.ts +15 -0
- package/dist/deploy/adapters/index.js +24 -0
- package/dist/deploy/adapters/netlify.d.ts +2 -0
- package/dist/deploy/adapters/netlify.js +115 -0
- package/dist/deploy/adapters/render.d.ts +2 -0
- package/dist/deploy/adapters/render.js +95 -0
- package/dist/deploy/adapters/vercel.d.ts +7 -0
- package/dist/deploy/adapters/vercel.js +164 -0
- package/dist/deploy/cli-runner.d.ts +8 -0
- package/dist/deploy/cli-runner.js +58 -0
- package/dist/deploy/detect.d.ts +6 -0
- package/dist/deploy/detect.js +77 -0
- package/dist/deploy/index.d.ts +24 -0
- package/dist/deploy/index.js +112 -0
- package/dist/deploy/preflight.d.ts +8 -0
- package/dist/deploy/preflight.js +80 -0
- package/dist/deploy/types.d.ts +48 -0
- package/dist/deploy/types.js +2 -0
- package/dist/deploy/utils.d.ts +18 -0
- package/dist/deploy/utils.js +70 -0
- package/dist/dev-error.d.ts +14 -0
- package/dist/dev-error.js +1763 -705
- package/dist/index.d.ts +23 -21
- package/dist/index.js +61 -57
- package/dist/server/cookie-parse.d.ts +4 -0
- package/dist/server/cookie-parse.js +14 -0
- package/dist/server/engine.js +7 -26
- package/dist/server/index.d.ts +109 -102
- package/dist/server/index.js +315 -286
- package/dist/server/middleware-runner.d.ts +125 -57
- package/dist/server/middleware-runner.js +615 -218
- package/dist/server/middleware-security.d.ts +36 -0
- package/dist/server/middleware-security.js +183 -0
- package/dist/server/module-compile-hook.js +695 -662
- package/dist/server/route-handler-registry.d.ts +65 -0
- package/dist/server/route-handler-registry.js +195 -0
- package/dist/server/route-patterns.d.ts +67 -0
- package/dist/server/route-patterns.js +186 -0
- package/dist/server/rsc-engine.js +75 -92
- package/dist/server/rsc-module-system.d.ts +33 -33
- package/dist/server/rsc-module-system.js +87 -87
- package/dist/server/rsc-upstream.js +892 -888
- package/dist/server/static-generator.js +10 -10
- package/dist/server/typed-api-runtime.d.ts +18 -0
- package/dist/server/typed-api-runtime.js +635 -507
- package/dist/server/vista-import-map.js +134 -123
- package/dist/stack/index.d.ts +34 -32
- package/dist/stack/index.js +49 -45
- package/dist/stack/server/caller.d.ts +13 -0
- package/dist/stack/server/caller.js +42 -0
- package/dist/stack/server/executor.d.ts +40 -36
- package/dist/stack/server/executor.js +222 -174
- package/dist/stack/server/index.d.ts +11 -10
- package/dist/stack/server/index.js +24 -23
- package/dist/stack/server/procedure.d.ts +20 -18
- package/dist/stack/server/procedure.js +66 -58
- package/dist/stack/server/types.d.ts +113 -100
- package/dist/theme/react-server.d.ts +10 -0
- package/dist/theme/react-server.js +16 -0
- package/package.json +28 -3
- 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,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,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
|
+
}
|