@oh-my-pi/pi-ai 4.3.2 → 4.4.6
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/package.json
CHANGED
package/src/providers/cursor.ts
CHANGED
|
@@ -356,7 +356,7 @@ export const streamCursor: StreamFunction<"cursor-agent"> = (
|
|
|
356
356
|
let endStreamError: Error | null = null;
|
|
357
357
|
let currentTextBlock: (TextContent & { index: number }) | null = null;
|
|
358
358
|
let currentThinkingBlock: (ThinkingContent & { index: number }) | null = null;
|
|
359
|
-
let currentToolCall:
|
|
359
|
+
let currentToolCall: ToolCallState | null = null;
|
|
360
360
|
const usageState: UsageState = { sawTokenDelta: false };
|
|
361
361
|
|
|
362
362
|
const state: BlockState = {
|
|
@@ -526,13 +526,15 @@ export const streamCursor: StreamFunction<"cursor-agent"> = (
|
|
|
526
526
|
return stream;
|
|
527
527
|
};
|
|
528
528
|
|
|
529
|
+
type ToolCallState = ToolCall & { index: number; partialJson?: string; kind: "mcp" | "todo_write" };
|
|
530
|
+
|
|
529
531
|
interface BlockState {
|
|
530
532
|
currentTextBlock: (TextContent & { index: number }) | null;
|
|
531
533
|
currentThinkingBlock: (ThinkingContent & { index: number }) | null;
|
|
532
|
-
currentToolCall:
|
|
534
|
+
currentToolCall: ToolCallState | null;
|
|
533
535
|
setTextBlock: (b: (TextContent & { index: number }) | null) => void;
|
|
534
536
|
setThinkingBlock: (b: (ThinkingContent & { index: number }) | null) => void;
|
|
535
|
-
setToolCall: (t:
|
|
537
|
+
setToolCall: (t: ToolCallState | null) => void;
|
|
536
538
|
}
|
|
537
539
|
|
|
538
540
|
interface UsageState {
|
|
@@ -1542,6 +1544,42 @@ function decodeMcpCall(args: {
|
|
|
1542
1544
|
};
|
|
1543
1545
|
}
|
|
1544
1546
|
|
|
1547
|
+
function mapTodoStatusValue(status?: number): "pending" | "in_progress" | "completed" {
|
|
1548
|
+
switch (status) {
|
|
1549
|
+
case 2:
|
|
1550
|
+
return "in_progress";
|
|
1551
|
+
case 3:
|
|
1552
|
+
return "completed";
|
|
1553
|
+
default:
|
|
1554
|
+
return "pending";
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
interface CursorTodoItem {
|
|
1559
|
+
id?: string;
|
|
1560
|
+
content?: string;
|
|
1561
|
+
status?: number;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
interface CursorUpdateTodosToolCall {
|
|
1565
|
+
updateTodosToolCall?: { args?: { todos?: CursorTodoItem[] } };
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function buildTodoWriteArgs(toolCall: CursorUpdateTodosToolCall): {
|
|
1569
|
+
todos: Array<{ id?: string; content: string; activeForm: string; status: "pending" | "in_progress" | "completed" }>;
|
|
1570
|
+
} | null {
|
|
1571
|
+
const todos = toolCall.updateTodosToolCall?.args?.todos;
|
|
1572
|
+
if (!todos) return null;
|
|
1573
|
+
return {
|
|
1574
|
+
todos: todos.map((todo) => ({
|
|
1575
|
+
id: typeof todo.id === "string" && todo.id.length > 0 ? todo.id : undefined,
|
|
1576
|
+
content: typeof todo.content === "string" ? todo.content : "",
|
|
1577
|
+
activeForm: typeof todo.content === "string" ? todo.content : "",
|
|
1578
|
+
status: mapTodoStatusValue(typeof todo.status === "number" ? todo.status : undefined),
|
|
1579
|
+
})),
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1545
1583
|
function buildMcpResultFromToolResult(_mcpCall: CursorMcpCall, toolResult: ToolResultMessage) {
|
|
1546
1584
|
if (toolResult.isError) {
|
|
1547
1585
|
return buildMcpErrorResult(toolResultToText(toolResult) || "MCP tool failed");
|
|
@@ -1654,13 +1692,31 @@ function processInteractionUpdate(
|
|
|
1654
1692
|
const mcpCall = toolCall.mcpToolCall;
|
|
1655
1693
|
if (mcpCall) {
|
|
1656
1694
|
const args = mcpCall.args || {};
|
|
1657
|
-
const block:
|
|
1695
|
+
const block: ToolCallState = {
|
|
1658
1696
|
type: "toolCall",
|
|
1659
1697
|
id: args.toolCallId || crypto.randomUUID(),
|
|
1660
1698
|
name: args.name || args.toolName || "",
|
|
1661
1699
|
arguments: {},
|
|
1662
1700
|
index: output.content.length,
|
|
1663
1701
|
partialJson: "",
|
|
1702
|
+
kind: "mcp",
|
|
1703
|
+
};
|
|
1704
|
+
output.content.push(block);
|
|
1705
|
+
state.setToolCall(block);
|
|
1706
|
+
stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
|
|
1707
|
+
return;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const todoArgs = buildTodoWriteArgs(toolCall);
|
|
1711
|
+
if (todoArgs) {
|
|
1712
|
+
const callId = update.message.value.callId || crypto.randomUUID();
|
|
1713
|
+
const block: ToolCallState = {
|
|
1714
|
+
type: "toolCall",
|
|
1715
|
+
id: callId,
|
|
1716
|
+
name: "todo_write",
|
|
1717
|
+
arguments: todoArgs,
|
|
1718
|
+
index: output.content.length,
|
|
1719
|
+
kind: "todo_write",
|
|
1664
1720
|
};
|
|
1665
1721
|
output.content.push(block);
|
|
1666
1722
|
state.setToolCall(block);
|
|
@@ -1668,23 +1724,31 @@ function processInteractionUpdate(
|
|
|
1668
1724
|
}
|
|
1669
1725
|
}
|
|
1670
1726
|
} else if (updateCase === "toolCallDelta" || updateCase === "partialToolCall") {
|
|
1671
|
-
if (state.currentToolCall) {
|
|
1727
|
+
if (state.currentToolCall?.kind === "mcp") {
|
|
1672
1728
|
const delta = update.message.value.argsTextDelta || "";
|
|
1673
|
-
state.currentToolCall.partialJson
|
|
1674
|
-
state.currentToolCall.arguments = parseStreamingJson(state.currentToolCall.partialJson);
|
|
1729
|
+
state.currentToolCall.partialJson = `${state.currentToolCall.partialJson ?? ""}${delta}`;
|
|
1730
|
+
state.currentToolCall.arguments = parseStreamingJson(state.currentToolCall.partialJson ?? "");
|
|
1675
1731
|
const idx = output.content.indexOf(state.currentToolCall);
|
|
1676
1732
|
stream.push({ type: "toolcall_delta", contentIndex: idx, delta, partial: output });
|
|
1677
1733
|
}
|
|
1678
1734
|
} else if (updateCase === "toolCallCompleted") {
|
|
1679
1735
|
if (state.currentToolCall) {
|
|
1680
1736
|
const toolCall = update.message.value.toolCall;
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1737
|
+
if (state.currentToolCall.kind === "mcp") {
|
|
1738
|
+
const decodedArgs = decodeMcpArgsMap(toolCall?.mcpToolCall?.args?.args);
|
|
1739
|
+
if (decodedArgs) {
|
|
1740
|
+
state.currentToolCall.arguments = decodedArgs;
|
|
1741
|
+
}
|
|
1742
|
+
} else if (state.currentToolCall.kind === "todo_write" && toolCall) {
|
|
1743
|
+
const todoArgs = buildTodoWriteArgs(toolCall);
|
|
1744
|
+
if (todoArgs) {
|
|
1745
|
+
state.currentToolCall.arguments = todoArgs;
|
|
1746
|
+
}
|
|
1684
1747
|
}
|
|
1685
1748
|
const idx = output.content.indexOf(state.currentToolCall);
|
|
1686
1749
|
delete (state.currentToolCall as any).partialJson;
|
|
1687
1750
|
delete (state.currentToolCall as any).index;
|
|
1751
|
+
delete (state.currentToolCall as any).kind;
|
|
1688
1752
|
stream.push({ type: "toolcall_end", contentIndex: idx, toolCall: state.currentToolCall, partial: output });
|
|
1689
1753
|
state.setToolCall(null);
|
|
1690
1754
|
}
|
|
@@ -1722,7 +1786,7 @@ function createBlobId(data: Uint8Array): Uint8Array {
|
|
|
1722
1786
|
return new Uint8Array(createHash("sha256").update(data).digest());
|
|
1723
1787
|
}
|
|
1724
1788
|
|
|
1725
|
-
const CURSOR_NATIVE_TOOL_NAMES = new Set(["bash", "read", "write", "delete", "ls", "grep", "lsp"]);
|
|
1789
|
+
const CURSOR_NATIVE_TOOL_NAMES = new Set(["bash", "read", "write", "delete", "ls", "grep", "lsp", "todo_write"]);
|
|
1726
1790
|
|
|
1727
1791
|
function buildMcpToolDefinitions(tools: Tool[] | undefined): McpToolDefinition[] {
|
|
1728
1792
|
if (!tools || tools.length === 0) {
|
|
@@ -695,7 +695,7 @@ function buildRequest(
|
|
|
695
695
|
}
|
|
696
696
|
|
|
697
697
|
if (context.tools && context.tools.length > 0) {
|
|
698
|
-
request.tools = convertTools(context.tools);
|
|
698
|
+
request.tools = convertTools(context.tools, model);
|
|
699
699
|
if (options.toolChoice) {
|
|
700
700
|
request.toolConfig = {
|
|
701
701
|
functionCallingConfig: {
|
|
@@ -189,7 +189,20 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
|
|
|
189
189
|
return contents;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
const UNSUPPORTED_SCHEMA_FIELDS = new Set([
|
|
193
|
+
"$schema",
|
|
194
|
+
"$ref",
|
|
195
|
+
"$defs",
|
|
196
|
+
"$dynamicRef",
|
|
197
|
+
"$dynamicAnchor",
|
|
198
|
+
"format",
|
|
199
|
+
"examples",
|
|
200
|
+
"prefixItems",
|
|
201
|
+
"unevaluatedProperties",
|
|
202
|
+
"unevaluatedItems",
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
export function sanitizeSchemaForGoogle(value: unknown): unknown {
|
|
193
206
|
if (Array.isArray(value)) {
|
|
194
207
|
return value.map((entry) => sanitizeSchemaForGoogle(entry));
|
|
195
208
|
}
|
|
@@ -202,10 +215,16 @@ function sanitizeSchemaForGoogle(value: unknown): unknown {
|
|
|
202
215
|
let constValue: unknown | undefined;
|
|
203
216
|
|
|
204
217
|
for (const [key, entry] of Object.entries(value)) {
|
|
218
|
+
if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
205
221
|
if (key === "const") {
|
|
206
222
|
constValue = entry;
|
|
207
223
|
continue;
|
|
208
224
|
}
|
|
225
|
+
if (key === "additionalProperties" && entry === false) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
209
228
|
result[key] = sanitizeSchemaForGoogle(entry);
|
|
210
229
|
}
|
|
211
230
|
|
|
@@ -221,22 +240,31 @@ function sanitizeSchemaForGoogle(value: unknown): unknown {
|
|
|
221
240
|
return result;
|
|
222
241
|
}
|
|
223
242
|
|
|
243
|
+
function sanitizeToolNoop(tool: Tool): Tool {
|
|
244
|
+
return {
|
|
245
|
+
name: tool.name,
|
|
246
|
+
description: tool.description,
|
|
247
|
+
parameters: structuredClone(tool.parameters),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function sanitizeToolGoogle(tool: Tool): Tool {
|
|
251
|
+
return {
|
|
252
|
+
name: tool.name,
|
|
253
|
+
description: tool.description,
|
|
254
|
+
parameters: sanitizeSchemaForGoogle(tool.parameters) as any,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
224
258
|
/**
|
|
225
259
|
* Convert tools to Gemini function declarations format.
|
|
226
260
|
*/
|
|
227
261
|
export function convertTools(
|
|
228
262
|
tools: Tool[],
|
|
263
|
+
model: Model<"google-generative-ai" | "google-gemini-cli" | "google-vertex">,
|
|
229
264
|
): { functionDeclarations: { name: string; description?: string; parameters: Schema }[] }[] | undefined {
|
|
230
265
|
if (tools.length === 0) return undefined;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
functionDeclarations: tools.map((tool) => ({
|
|
234
|
-
name: tool.name,
|
|
235
|
-
description: tool.description,
|
|
236
|
-
parameters: sanitizeSchemaForGoogle(tool.parameters) as Schema,
|
|
237
|
-
})),
|
|
238
|
-
},
|
|
239
|
-
];
|
|
266
|
+
const toolSanitizer = model?.id.startsWith("gemini-") ? sanitizeToolGoogle : sanitizeToolNoop;
|
|
267
|
+
return [{ functionDeclarations: tools.map(toolSanitizer) }];
|
|
240
268
|
}
|
|
241
269
|
|
|
242
270
|
/**
|
|
@@ -326,7 +326,7 @@ function buildParams(
|
|
|
326
326
|
const config: GenerateContentConfig = {
|
|
327
327
|
...(Object.keys(generationConfig).length > 0 && generationConfig),
|
|
328
328
|
...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),
|
|
329
|
-
...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),
|
|
329
|
+
...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools, model) }),
|
|
330
330
|
};
|
|
331
331
|
|
|
332
332
|
if (context.tools && context.tools.length > 0 && options.toolChoice) {
|
package/src/providers/google.ts
CHANGED
|
@@ -28,8 +28,11 @@ import {
|
|
|
28
28
|
mapStopReason,
|
|
29
29
|
mapToolChoice,
|
|
30
30
|
retainThoughtSignature,
|
|
31
|
+
sanitizeSchemaForGoogle,
|
|
31
32
|
} from "./google-shared";
|
|
32
33
|
|
|
34
|
+
export { sanitizeSchemaForGoogle };
|
|
35
|
+
|
|
33
36
|
export interface GoogleOptions extends StreamOptions {
|
|
34
37
|
toolChoice?: "auto" | "none" | "any";
|
|
35
38
|
thinking?: {
|
|
@@ -294,7 +297,7 @@ function buildParams(
|
|
|
294
297
|
const config: GenerateContentConfig = {
|
|
295
298
|
...(Object.keys(generationConfig).length > 0 && generationConfig),
|
|
296
299
|
...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),
|
|
297
|
-
...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),
|
|
300
|
+
...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools, model) }),
|
|
298
301
|
};
|
|
299
302
|
|
|
300
303
|
if (context.tools && context.tools.length > 0 && options.toolChoice) {
|