@ssweens/pi-vertex 1.0.1 → 1.1.1
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/README.md +16 -20
- package/models/claude.ts +19 -73
- package/models/gemini.ts +55 -28
- package/models/index.ts +1 -1
- package/models/maas.ts +39 -76
- package/package.json +1 -1
- package/streaming/gemini.ts +198 -89
- package/streaming/maas.ts +22 -29
- package/types.ts +24 -35
- package/utils.ts +163 -58
package/streaming/gemini.ts
CHANGED
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gemini streaming handler using @google/genai SDK
|
|
3
|
+
*
|
|
4
|
+
* Aligned with pi-mono's google-vertex.ts for consistent handling of:
|
|
5
|
+
* - Thinking content (thought blocks with signatures)
|
|
6
|
+
* - Tool calls with unique IDs and deduplication
|
|
7
|
+
* - Thinking configuration (levels for Gemini 3, budgets for Gemini 2.5)
|
|
8
|
+
* - Usage tracking including thinking tokens
|
|
3
9
|
*/
|
|
4
10
|
|
|
5
|
-
import { GoogleGenAI } from "@google/genai";
|
|
6
|
-
import type { VertexModelConfig, Context, StreamOptions } from "../types.js";
|
|
11
|
+
import { GoogleGenAI, FinishReason, ThinkingLevel } from "@google/genai";
|
|
12
|
+
import type { VertexModelConfig, Context, StreamOptions, AssistantMessage } from "../types.js";
|
|
7
13
|
import { getAuthConfig, resolveLocation } from "../auth.js";
|
|
8
|
-
import { sanitizeText, convertToGeminiMessages, calculateCost } from "../utils.js";
|
|
9
|
-
import { createAssistantMessageEventStream, type AssistantMessageEventStream
|
|
14
|
+
import { sanitizeText, convertToGeminiMessages, convertToolsForGemini, retainThoughtSignature, calculateCost } from "../utils.js";
|
|
15
|
+
import { createAssistantMessageEventStream, type AssistantMessageEventStream } from "@mariozechner/pi-ai";
|
|
16
|
+
|
|
17
|
+
// Module-level counter for generating unique tool call IDs (matches pi-mono pattern)
|
|
18
|
+
let toolCallCounter = 0;
|
|
19
|
+
|
|
20
|
+
const THINKING_LEVEL_MAP: Record<string, ThinkingLevel> = {
|
|
21
|
+
minimal: ThinkingLevel.MINIMAL,
|
|
22
|
+
low: ThinkingLevel.LOW,
|
|
23
|
+
medium: ThinkingLevel.MEDIUM,
|
|
24
|
+
high: ThinkingLevel.HIGH,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function mapGeminiStopReason(reason: string): "stop" | "length" | "toolUse" | "error" {
|
|
28
|
+
switch (reason) {
|
|
29
|
+
case FinishReason.STOP:
|
|
30
|
+
return "stop";
|
|
31
|
+
case FinishReason.MAX_TOKENS:
|
|
32
|
+
return "length";
|
|
33
|
+
case FinishReason.SAFETY:
|
|
34
|
+
case FinishReason.RECITATION:
|
|
35
|
+
default:
|
|
36
|
+
return "error";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
10
39
|
|
|
11
40
|
export function streamGemini(
|
|
12
41
|
model: VertexModelConfig,
|
|
13
42
|
context: Context,
|
|
14
|
-
options?: StreamOptions
|
|
43
|
+
options?: StreamOptions,
|
|
15
44
|
): AssistantMessageEventStream {
|
|
16
45
|
const stream = createAssistantMessageEventStream();
|
|
17
|
-
|
|
46
|
+
|
|
18
47
|
(async () => {
|
|
19
48
|
const output: AssistantMessage = {
|
|
20
49
|
role: "assistant",
|
|
@@ -33,123 +62,203 @@ export function streamGemini(
|
|
|
33
62
|
stopReason: "stop",
|
|
34
63
|
timestamp: Date.now(),
|
|
35
64
|
};
|
|
36
|
-
|
|
65
|
+
|
|
37
66
|
try {
|
|
38
67
|
// Priority: config file > env var > model region > default
|
|
39
68
|
const location = resolveLocation(model.region);
|
|
40
69
|
const auth = getAuthConfig(location);
|
|
41
70
|
|
|
42
|
-
// Create client
|
|
71
|
+
// Create client with explicit API version (matches pi-mono)
|
|
43
72
|
const client = new GoogleGenAI({
|
|
44
73
|
vertexai: true,
|
|
45
74
|
project: auth.projectId,
|
|
46
75
|
location: auth.location,
|
|
76
|
+
apiVersion: "v1",
|
|
47
77
|
});
|
|
48
|
-
|
|
49
|
-
// Convert messages
|
|
50
|
-
const contents = convertToGeminiMessages(context.messages);
|
|
51
|
-
|
|
52
|
-
// Build config
|
|
78
|
+
|
|
79
|
+
// Convert messages with model ID for proper thinking/tool handling
|
|
80
|
+
const contents = convertToGeminiMessages(context.messages, model.apiId);
|
|
81
|
+
|
|
82
|
+
// Build config — only set temperature when explicitly provided
|
|
53
83
|
const config: any = {
|
|
54
84
|
maxOutputTokens: options?.maxTokens || Math.floor(model.maxTokens / 2),
|
|
55
|
-
temperature: options
|
|
85
|
+
...(options?.temperature !== undefined && { temperature: options.temperature }),
|
|
56
86
|
};
|
|
57
|
-
|
|
87
|
+
|
|
58
88
|
// Add system prompt if present
|
|
59
89
|
if (context.systemPrompt) {
|
|
60
90
|
config.systemInstruction = sanitizeText(context.systemPrompt);
|
|
61
91
|
}
|
|
62
|
-
|
|
63
|
-
// Add tools if present
|
|
92
|
+
|
|
93
|
+
// Add tools if present (using parametersJsonSchema for full JSON Schema support)
|
|
64
94
|
if (context.tools && context.tools.length > 0) {
|
|
65
|
-
config.tools =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
95
|
+
config.tools = convertToolsForGemini(context.tools);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Add thinking configuration (matches pi-mono's buildParams logic)
|
|
99
|
+
if (model.reasoning && options?.reasoning) {
|
|
100
|
+
const effort = options.reasoning === "xhigh" ? "high" : options.reasoning;
|
|
101
|
+
const isGemini3 = model.apiId.startsWith("gemini-3");
|
|
102
|
+
|
|
103
|
+
const thinkingConfig: any = { includeThoughts: true };
|
|
104
|
+
|
|
105
|
+
if (isGemini3) {
|
|
106
|
+
// Gemini 3 models use thinking levels (MINIMAL/LOW/MEDIUM/HIGH)
|
|
107
|
+
thinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[effort];
|
|
108
|
+
} else {
|
|
109
|
+
// Gemini 2.5 models use thinking budgets (token counts)
|
|
110
|
+
const budgets: Record<string, number> = {
|
|
111
|
+
minimal: 128,
|
|
112
|
+
low: 2048,
|
|
113
|
+
medium: 8192,
|
|
114
|
+
high: model.apiId.includes("2.5-pro") ? 32768 : 24576,
|
|
115
|
+
};
|
|
116
|
+
thinkingConfig.thinkingBudget = budgets[effort] ?? 8192;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
config.thinkingConfig = thinkingConfig;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Pass abort signal to SDK for in-flight cancellation
|
|
123
|
+
if (options?.signal) {
|
|
124
|
+
if (options.signal.aborted) {
|
|
125
|
+
throw new Error("Request aborted");
|
|
126
|
+
}
|
|
127
|
+
config.abortSignal = options.signal;
|
|
74
128
|
}
|
|
75
|
-
|
|
129
|
+
|
|
76
130
|
stream.push({ type: "start", partial: output });
|
|
77
|
-
|
|
131
|
+
|
|
78
132
|
// Start streaming
|
|
79
133
|
const response = await client.models.generateContentStream({
|
|
80
134
|
model: model.apiId,
|
|
81
135
|
contents,
|
|
82
136
|
config,
|
|
83
137
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let
|
|
87
|
-
|
|
138
|
+
|
|
139
|
+
// Track current content block for thinking/text transitions
|
|
140
|
+
let currentBlock: any = null;
|
|
141
|
+
let currentBlockType: "text" | "thinking" | null = null;
|
|
142
|
+
|
|
88
143
|
for await (const chunk of response) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
const candidate = chunk.candidates?.[0];
|
|
145
|
+
|
|
146
|
+
// Process individual parts (handles thinking vs text detection)
|
|
147
|
+
if (candidate?.content?.parts) {
|
|
148
|
+
for (const part of candidate.content.parts) {
|
|
149
|
+
if (part.text !== undefined) {
|
|
150
|
+
const isThinking = part.thought === true;
|
|
151
|
+
const targetType = isThinking ? "thinking" : "text";
|
|
152
|
+
|
|
153
|
+
// Check if we need to transition to a new block
|
|
154
|
+
if (currentBlockType !== targetType) {
|
|
155
|
+
// End previous block
|
|
156
|
+
if (currentBlock && currentBlockType) {
|
|
157
|
+
if (currentBlockType === "text") {
|
|
158
|
+
stream.push({ type: "text_end", contentIndex: output.content.length - 1, content: currentBlock.text, partial: output });
|
|
159
|
+
} else {
|
|
160
|
+
stream.push({ type: "thinking_end", contentIndex: output.content.length - 1, content: currentBlock.thinking, partial: output });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Start new block
|
|
165
|
+
if (isThinking) {
|
|
166
|
+
currentBlock = { type: "thinking", thinking: "", thinkingSignature: undefined };
|
|
167
|
+
output.content.push(currentBlock);
|
|
168
|
+
stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
|
|
169
|
+
} else {
|
|
170
|
+
currentBlock = { type: "text", text: "", textSignature: undefined };
|
|
171
|
+
output.content.push(currentBlock);
|
|
172
|
+
stream.push({ type: "text_start", contentIndex: output.content.length - 1, partial: output });
|
|
173
|
+
}
|
|
174
|
+
currentBlockType = targetType;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Accumulate content
|
|
178
|
+
if (currentBlockType === "thinking") {
|
|
179
|
+
currentBlock.thinking += part.text;
|
|
180
|
+
currentBlock.thinkingSignature = retainThoughtSignature(currentBlock.thinkingSignature, part.thoughtSignature);
|
|
181
|
+
stream.push({ type: "thinking_delta", contentIndex: output.content.length - 1, delta: part.text, partial: output });
|
|
182
|
+
} else {
|
|
183
|
+
currentBlock.text += part.text;
|
|
184
|
+
currentBlock.textSignature = retainThoughtSignature(currentBlock.textSignature, part.thoughtSignature);
|
|
185
|
+
stream.push({ type: "text_delta", contentIndex: output.content.length - 1, delta: part.text, partial: output });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (part.functionCall) {
|
|
190
|
+
// End current text/thinking block before tool call
|
|
191
|
+
if (currentBlock && currentBlockType) {
|
|
192
|
+
if (currentBlockType === "text") {
|
|
193
|
+
stream.push({ type: "text_end", contentIndex: output.content.length - 1, content: currentBlock.text, partial: output });
|
|
194
|
+
} else {
|
|
195
|
+
stream.push({ type: "thinking_end", contentIndex: output.content.length - 1, content: currentBlock.thinking, partial: output });
|
|
196
|
+
}
|
|
197
|
+
currentBlock = null;
|
|
198
|
+
currentBlockType = null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Generate unique tool call ID with dedup (matches pi-mono pattern)
|
|
202
|
+
const providedId = part.functionCall.id;
|
|
203
|
+
const needsNewId =
|
|
204
|
+
!providedId || output.content.some((b: any) => b.type === "toolCall" && b.id === providedId);
|
|
205
|
+
const toolCallId = needsNewId
|
|
206
|
+
? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}`
|
|
207
|
+
: providedId;
|
|
208
|
+
|
|
209
|
+
const toolCall = {
|
|
210
|
+
type: "toolCall" as const,
|
|
211
|
+
id: toolCallId,
|
|
212
|
+
name: part.functionCall.name || "",
|
|
213
|
+
arguments: (part.functionCall.args as Record<string, any>) ?? {},
|
|
214
|
+
...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
output.content.push(toolCall);
|
|
218
|
+
const idx = output.content.length - 1;
|
|
219
|
+
stream.push({ type: "toolcall_start", contentIndex: idx, partial: output });
|
|
220
|
+
stream.push({ type: "toolcall_delta", contentIndex: idx, delta: JSON.stringify(toolCall.arguments), partial: output });
|
|
221
|
+
stream.push({ type: "toolcall_end", contentIndex: idx, toolCall, partial: output });
|
|
222
|
+
}
|
|
131
223
|
}
|
|
132
224
|
}
|
|
133
|
-
|
|
225
|
+
|
|
134
226
|
// Handle finish reason
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
output.stopReason = "stop";
|
|
139
|
-
} else if (reason === "MAX_TOKENS") {
|
|
140
|
-
output.stopReason = "length";
|
|
141
|
-
} else if (reason === "SAFETY") {
|
|
142
|
-
output.stopReason = "error";
|
|
227
|
+
if (candidate?.finishReason) {
|
|
228
|
+
output.stopReason = mapGeminiStopReason(candidate.finishReason);
|
|
229
|
+
if (candidate.finishReason === FinishReason.SAFETY) {
|
|
143
230
|
output.errorMessage = "Content blocked by safety filters";
|
|
144
231
|
}
|
|
232
|
+
// Override to toolUse if any tool calls are present (matches pi-mono)
|
|
233
|
+
if (output.content.some((b: any) => b.type === "toolCall")) {
|
|
234
|
+
output.stopReason = "toolUse";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Update usage — include thoughtsTokenCount in output (matches pi-mono)
|
|
239
|
+
if (chunk.usageMetadata) {
|
|
240
|
+
const meta = chunk.usageMetadata as any;
|
|
241
|
+
output.usage = {
|
|
242
|
+
input: meta.promptTokenCount || 0,
|
|
243
|
+
output: (meta.candidatesTokenCount || 0) + (meta.thoughtsTokenCount || 0),
|
|
244
|
+
cacheRead: meta.cachedContentTokenCount || 0,
|
|
245
|
+
cacheWrite: 0,
|
|
246
|
+
totalTokens: meta.totalTokenCount || 0,
|
|
247
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
248
|
+
};
|
|
249
|
+
calculateCost(model.cost.input, model.cost.output, model.cost.cacheRead, model.cost.cacheWrite, output.usage);
|
|
145
250
|
}
|
|
146
251
|
}
|
|
147
|
-
|
|
148
|
-
// End
|
|
149
|
-
if (
|
|
150
|
-
|
|
252
|
+
|
|
253
|
+
// End final block
|
|
254
|
+
if (currentBlock && currentBlockType) {
|
|
255
|
+
if (currentBlockType === "text") {
|
|
256
|
+
stream.push({ type: "text_end", contentIndex: output.content.length - 1, content: currentBlock.text, partial: output });
|
|
257
|
+
} else {
|
|
258
|
+
stream.push({ type: "thinking_end", contentIndex: output.content.length - 1, content: currentBlock.thinking, partial: output });
|
|
259
|
+
}
|
|
151
260
|
}
|
|
152
|
-
|
|
261
|
+
|
|
153
262
|
stream.push({ type: "done", reason: output.stopReason as any, message: output });
|
|
154
263
|
stream.end();
|
|
155
264
|
} catch (error) {
|
|
@@ -159,6 +268,6 @@ export function streamGemini(
|
|
|
159
268
|
stream.end();
|
|
160
269
|
}
|
|
161
270
|
})();
|
|
162
|
-
|
|
271
|
+
|
|
163
272
|
return stream;
|
|
164
273
|
}
|
package/streaming/maas.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MaaS streaming handler for Claude and all other models
|
|
3
3
|
* Uses OpenAI-compatible Chat Completions endpoint
|
|
4
|
-
*
|
|
5
|
-
* Delegates to pi-ai's built-in OpenAI streaming implementation
|
|
4
|
+
*
|
|
5
|
+
* Delegates to pi-ai's built-in OpenAI streaming implementation.
|
|
6
|
+
* Uses model.apiId directly in the request (no global fetch interceptor)
|
|
7
|
+
* and patches the model ID back to the friendly name in response events.
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import type { VertexModelConfig, Context, StreamOptions } from "../types.js";
|
|
@@ -12,12 +14,11 @@ import { createAssistantMessageEventStream, type AssistantMessageEventStream, ty
|
|
|
12
14
|
export function streamMaaS(
|
|
13
15
|
model: VertexModelConfig,
|
|
14
16
|
context: Context,
|
|
15
|
-
options?: StreamOptions
|
|
17
|
+
options?: StreamOptions,
|
|
16
18
|
): AssistantMessageEventStream {
|
|
17
19
|
const stream = createAssistantMessageEventStream();
|
|
18
20
|
|
|
19
21
|
(async () => {
|
|
20
|
-
const originalFetch = globalThis.fetch;
|
|
21
22
|
try {
|
|
22
23
|
// Priority: config file > env var > model region > default
|
|
23
24
|
const location = resolveLocation(model.region);
|
|
@@ -26,12 +27,12 @@ export function streamMaaS(
|
|
|
26
27
|
|
|
27
28
|
const baseUrl = buildBaseUrl(auth.projectId, auth.location);
|
|
28
29
|
const endpoint = `${baseUrl}/endpoints/openapi`;
|
|
30
|
+
|
|
29
31
|
// Create a model object compatible with pi-ai's OpenAI streaming.
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
// The actual API model name (apiId like "zai-org/glm-5-maas") is injected via fetch interceptor below.
|
|
32
|
+
// Use model.apiId directly so the correct model name goes in the request body.
|
|
33
|
+
// The friendly model.id is patched back into response events below for session persistence.
|
|
33
34
|
const modelForPi: Model<"openai-completions"> = {
|
|
34
|
-
id: model.
|
|
35
|
+
id: model.apiId,
|
|
35
36
|
name: model.name,
|
|
36
37
|
api: "openai-completions",
|
|
37
38
|
provider: "vertex",
|
|
@@ -51,21 +52,6 @@ export function streamMaaS(
|
|
|
51
52
|
},
|
|
52
53
|
};
|
|
53
54
|
|
|
54
|
-
// Intercept fetch to replace model.id with the actual API model name (apiId)
|
|
55
|
-
// pi-ai's streaming uses model.id in the request body, but Vertex MaaS needs the full publisher-prefixed name
|
|
56
|
-
globalThis.fetch = async (input: any, init?: any) => {
|
|
57
|
-
if (init?.body && typeof init.body === "string") {
|
|
58
|
-
try {
|
|
59
|
-
const body = JSON.parse(init.body);
|
|
60
|
-
if (body.model === model.id) {
|
|
61
|
-
body.model = model.apiId;
|
|
62
|
-
init = { ...init, body: JSON.stringify(body) };
|
|
63
|
-
}
|
|
64
|
-
} catch {}
|
|
65
|
-
}
|
|
66
|
-
return originalFetch(input, init);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
55
|
// Delegate to pi-ai's built-in OpenAI streaming
|
|
70
56
|
const innerStream = streamSimpleOpenAICompletions(
|
|
71
57
|
modelForPi,
|
|
@@ -74,19 +60,26 @@ export function streamMaaS(
|
|
|
74
60
|
...options,
|
|
75
61
|
apiKey: accessToken,
|
|
76
62
|
maxTokens: options?.maxTokens || Math.floor(model.maxTokens / 2),
|
|
77
|
-
temperature: options?.temperature
|
|
78
|
-
}
|
|
63
|
+
temperature: options?.temperature,
|
|
64
|
+
},
|
|
79
65
|
);
|
|
80
66
|
|
|
81
|
-
// Forward all events
|
|
67
|
+
// Forward all events, patching model ID back to the friendly name
|
|
68
|
+
// so pi-coding-agent can restore sessions correctly.
|
|
82
69
|
for await (const event of innerStream) {
|
|
70
|
+
if ("partial" in event && event.partial) {
|
|
71
|
+
event.partial.model = model.id;
|
|
72
|
+
}
|
|
73
|
+
if ("message" in event && event.message) {
|
|
74
|
+
event.message.model = model.id;
|
|
75
|
+
}
|
|
76
|
+
if ("error" in event && event.error && typeof event.error === "object") {
|
|
77
|
+
(event.error as any).model = model.id;
|
|
78
|
+
}
|
|
83
79
|
stream.push(event);
|
|
84
80
|
}
|
|
85
|
-
globalThis.fetch = originalFetch;
|
|
86
81
|
stream.end();
|
|
87
|
-
|
|
88
82
|
} catch (error) {
|
|
89
|
-
globalThis.fetch = originalFetch;
|
|
90
83
|
stream.push({
|
|
91
84
|
type: "error",
|
|
92
85
|
reason: options?.signal?.aborted ? "aborted" : "error",
|
package/types.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type definitions for pi-vertex extension
|
|
3
|
+
*
|
|
4
|
+
* Core message/content types are re-exported from pi-ai to ensure pi-vertex
|
|
5
|
+
* handles the full message structure (thinking blocks, tool calls, tool results)
|
|
6
|
+
* that pi-coding-agent passes through the streamSimple callback.
|
|
3
7
|
*/
|
|
4
8
|
|
|
9
|
+
// Re-export core types from pi-ai
|
|
10
|
+
export type {
|
|
11
|
+
AssistantMessage,
|
|
12
|
+
AssistantMessageEvent,
|
|
13
|
+
AssistantMessageEventStream,
|
|
14
|
+
Context,
|
|
15
|
+
ImageContent,
|
|
16
|
+
Message,
|
|
17
|
+
StopReason,
|
|
18
|
+
TextContent,
|
|
19
|
+
ThinkingContent,
|
|
20
|
+
Tool,
|
|
21
|
+
ToolCall,
|
|
22
|
+
ToolResultMessage,
|
|
23
|
+
Usage,
|
|
24
|
+
UserMessage,
|
|
25
|
+
} from "@mariozechner/pi-ai";
|
|
26
|
+
|
|
27
|
+
// Vertex-specific types
|
|
28
|
+
|
|
5
29
|
export type ModelInputType = "text" | "image";
|
|
6
30
|
export type EndpointType = "gemini" | "maas";
|
|
7
31
|
|
|
@@ -33,44 +57,9 @@ export interface AuthConfig {
|
|
|
33
57
|
credentials?: string;
|
|
34
58
|
}
|
|
35
59
|
|
|
36
|
-
export type MessageRole = "user" | "assistant" | "system";
|
|
37
|
-
|
|
38
|
-
export interface TextContent {
|
|
39
|
-
type: "text";
|
|
40
|
-
text: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ImageContent {
|
|
44
|
-
type: "image";
|
|
45
|
-
mimeType: string;
|
|
46
|
-
data: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export type MessageContent = TextContent | ImageContent;
|
|
50
|
-
|
|
51
|
-
export interface Message {
|
|
52
|
-
role: MessageRole;
|
|
53
|
-
content: string | MessageContent[];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface Tool {
|
|
57
|
-
name: string;
|
|
58
|
-
description: string;
|
|
59
|
-
parameters: Record<string, unknown>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface Context {
|
|
63
|
-
systemPrompt?: string;
|
|
64
|
-
messages: Message[];
|
|
65
|
-
tools?: Tool[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
60
|
export interface StreamOptions {
|
|
69
61
|
maxTokens?: number;
|
|
70
62
|
temperature?: number;
|
|
71
63
|
reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
72
64
|
signal?: AbortSignal;
|
|
73
65
|
}
|
|
74
|
-
|
|
75
|
-
// Re-export types from pi-ai for convenience
|
|
76
|
-
export type { AssistantMessage, AssistantMessageEvent, AssistantMessageEventStream } from "@mariozechner/pi-ai";
|