@f5-sales-demo/pi-ai 21.50.0 → 22.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.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-ai",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "22.0.0",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@anthropic-ai/sdk": "0.123.0",
|
|
47
47
|
"@aws-sdk/client-bedrock-runtime": "3.1126.0",
|
|
48
48
|
"@bufbuild/protobuf": "2.14.1",
|
|
49
|
-
"@f5-sales-demo/pi-utils": "
|
|
49
|
+
"@f5-sales-demo/pi-utils": "22.0.0",
|
|
50
50
|
"@google/genai": "2.21.0",
|
|
51
51
|
"@sinclair/typebox": "0.34.52",
|
|
52
52
|
"@smithy/node-http-handler": "4.12.1",
|
package/src/providers/cursor.ts
CHANGED
|
@@ -11,8 +11,8 @@ import type {
|
|
|
11
11
|
Context,
|
|
12
12
|
CursorExecHandlerResult,
|
|
13
13
|
CursorExecHandlers,
|
|
14
|
-
CursorMcpCall,
|
|
15
14
|
CursorShellStreamCallbacks,
|
|
15
|
+
CursorToolCall,
|
|
16
16
|
CursorToolResultHandler,
|
|
17
17
|
ImageContent,
|
|
18
18
|
Message,
|
|
@@ -225,7 +225,7 @@ function extractLogBytes(value: unknown): Uint8Array | null {
|
|
|
225
225
|
return null;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
function
|
|
228
|
+
function decodeToolArgsForLog(args?: Record<string, unknown>): Record<string, unknown> | undefined {
|
|
229
229
|
if (!args) {
|
|
230
230
|
return undefined;
|
|
231
231
|
}
|
|
@@ -234,7 +234,7 @@ function decodeMcpArgsForLog(args?: Record<string, unknown>): Record<string, unk
|
|
|
234
234
|
for (const [key, value] of Object.entries(args)) {
|
|
235
235
|
const bytes = extractLogBytes(value);
|
|
236
236
|
if (bytes) {
|
|
237
|
-
decoded[key] =
|
|
237
|
+
decoded[key] = decodeToolArgValue(bytes);
|
|
238
238
|
mutated = true;
|
|
239
239
|
continue;
|
|
240
240
|
}
|
|
@@ -259,13 +259,13 @@ function decodeLogData(value: unknown): unknown {
|
|
|
259
259
|
const stripTypeName = typeof typeName === "string" && typeName.startsWith("agent.v1.");
|
|
260
260
|
|
|
261
261
|
if (typeName === "agent.v1.McpArgs") {
|
|
262
|
-
const decodedArgs =
|
|
262
|
+
const decodedArgs = decodeToolArgsForLog(record.args as Record<string, unknown> | undefined);
|
|
263
263
|
const base = stripTypeName ? omitTypeName(record) : record;
|
|
264
264
|
return decodedArgs ? { ...base, args: decodedArgs } : base;
|
|
265
265
|
}
|
|
266
266
|
if (typeName === "agent.v1.McpToolCall") {
|
|
267
267
|
const argsRecord = record.args as Record<string, unknown> | undefined;
|
|
268
|
-
const decodedArgs =
|
|
268
|
+
const decodedArgs = decodeToolArgsForLog(argsRecord?.args as Record<string, unknown> | undefined);
|
|
269
269
|
const base = stripTypeName ? omitTypeName(record) : record;
|
|
270
270
|
if (decodedArgs && argsRecord) {
|
|
271
271
|
return { ...base, args: { ...argsRecord, args: decodedArgs } };
|
|
@@ -363,7 +363,7 @@ export const streamCursor: StreamFunction<"cursor-agent"> = (
|
|
|
363
363
|
conversationState: cachedState,
|
|
364
364
|
});
|
|
365
365
|
conversationStateCache.set(conversationId, conversationState);
|
|
366
|
-
const requestContextTools =
|
|
366
|
+
const requestContextTools = buildCursorToolDefinitions(context.tools);
|
|
367
367
|
|
|
368
368
|
const baseUrl = model.baseUrl || CURSOR_API_URL;
|
|
369
369
|
h2Client = http2.connect(baseUrl);
|
|
@@ -569,7 +569,7 @@ export const streamCursor: StreamFunction<"cursor-agent"> = (
|
|
|
569
569
|
return stream;
|
|
570
570
|
};
|
|
571
571
|
|
|
572
|
-
type ToolCallState = ToolCall & { index: number; partialJson?: string; kind: "
|
|
572
|
+
type ToolCallState = ToolCall & { index: number; partialJson?: string; kind: "tool" | "todo_write" };
|
|
573
573
|
|
|
574
574
|
interface BlockState {
|
|
575
575
|
currentTextBlock: (TextContent & { index: number }) | null;
|
|
@@ -1042,14 +1042,14 @@ async function handleExecServerMessage(
|
|
|
1042
1042
|
}
|
|
1043
1043
|
case "mcpArgs": {
|
|
1044
1044
|
const args = execMsg.message.value;
|
|
1045
|
-
const
|
|
1045
|
+
const toolCall = decodeCursorToolCall(args);
|
|
1046
1046
|
const { execResult } = await resolveExecHandler(
|
|
1047
|
-
|
|
1048
|
-
execHandlers?.
|
|
1047
|
+
toolCall,
|
|
1048
|
+
execHandlers?.tool?.bind(execHandlers),
|
|
1049
1049
|
onToolResult,
|
|
1050
|
-
toolResult =>
|
|
1051
|
-
_reason =>
|
|
1052
|
-
error =>
|
|
1050
|
+
toolResult => buildCursorToolResult(toolResult),
|
|
1051
|
+
_reason => buildCursorToolNotFoundResult(toolCall),
|
|
1052
|
+
error => buildCursorToolErrorResult(error),
|
|
1053
1053
|
);
|
|
1054
1054
|
sendExecClientMessage(h2Request, execMsg, "mcpResult", execResult);
|
|
1055
1055
|
return;
|
|
@@ -1652,7 +1652,7 @@ function parseToolArgsJson(text: string): unknown {
|
|
|
1652
1652
|
return text;
|
|
1653
1653
|
}
|
|
1654
1654
|
|
|
1655
|
-
function
|
|
1655
|
+
function decodeToolArgValue(value: Uint8Array): unknown {
|
|
1656
1656
|
try {
|
|
1657
1657
|
const parsedValue = fromBinary(ValueSchema, value);
|
|
1658
1658
|
const jsonValue = toJson(ValueSchema, parsedValue) as JsonValue;
|
|
@@ -1665,27 +1665,27 @@ function decodeMcpArgValue(value: Uint8Array): unknown {
|
|
|
1665
1665
|
return parseToolArgsJson(text);
|
|
1666
1666
|
}
|
|
1667
1667
|
|
|
1668
|
-
function
|
|
1668
|
+
function decodeToolArgsMap(args?: Record<string, Uint8Array>): Record<string, unknown> | undefined {
|
|
1669
1669
|
if (!args) {
|
|
1670
1670
|
return undefined;
|
|
1671
1671
|
}
|
|
1672
1672
|
const decoded: Record<string, unknown> = {};
|
|
1673
1673
|
for (const [key, value] of Object.entries(args)) {
|
|
1674
|
-
decoded[key] =
|
|
1674
|
+
decoded[key] = decodeToolArgValue(value);
|
|
1675
1675
|
}
|
|
1676
1676
|
return decoded;
|
|
1677
1677
|
}
|
|
1678
1678
|
|
|
1679
|
-
function
|
|
1679
|
+
function decodeCursorToolCall(args: {
|
|
1680
1680
|
name: string;
|
|
1681
1681
|
args: Record<string, Uint8Array>;
|
|
1682
1682
|
toolCallId: string;
|
|
1683
1683
|
providerIdentifier: string;
|
|
1684
1684
|
toolName: string;
|
|
1685
|
-
}):
|
|
1685
|
+
}): CursorToolCall {
|
|
1686
1686
|
const decodedArgs: Record<string, unknown> = {};
|
|
1687
1687
|
for (const [key, value] of Object.entries(args.args ?? {})) {
|
|
1688
|
-
decodedArgs[key] =
|
|
1688
|
+
decodedArgs[key] = decodeToolArgValue(value);
|
|
1689
1689
|
}
|
|
1690
1690
|
return {
|
|
1691
1691
|
name: args.name,
|
|
@@ -1733,9 +1733,9 @@ function buildTodoWriteArgs(toolCall: CursorUpdateTodosToolCall): {
|
|
|
1733
1733
|
};
|
|
1734
1734
|
}
|
|
1735
1735
|
|
|
1736
|
-
function
|
|
1736
|
+
function buildCursorToolResult(toolResult: ToolResultMessage) {
|
|
1737
1737
|
if (toolResult.isError) {
|
|
1738
|
-
return
|
|
1738
|
+
return buildCursorToolErrorResult(toolResultToText(toolResult) || "Tool failed");
|
|
1739
1739
|
}
|
|
1740
1740
|
const content = toolResult.content.map(item => {
|
|
1741
1741
|
if (item.type === "image") {
|
|
@@ -1768,16 +1768,16 @@ function buildMcpResultFromToolResult(_mcpCall: CursorMcpCall, toolResult: ToolR
|
|
|
1768
1768
|
});
|
|
1769
1769
|
}
|
|
1770
1770
|
|
|
1771
|
-
function
|
|
1771
|
+
function buildCursorToolNotFoundResult(toolCall: CursorToolCall) {
|
|
1772
1772
|
return create(McpResultSchema, {
|
|
1773
1773
|
result: {
|
|
1774
1774
|
case: "toolNotFound",
|
|
1775
|
-
value: create(McpToolNotFoundSchema, { name:
|
|
1775
|
+
value: create(McpToolNotFoundSchema, { name: toolCall.toolName, availableTools: [] }),
|
|
1776
1776
|
},
|
|
1777
1777
|
});
|
|
1778
1778
|
}
|
|
1779
1779
|
|
|
1780
|
-
function
|
|
1780
|
+
function buildCursorToolErrorResult(error: string) {
|
|
1781
1781
|
return create(McpResultSchema, {
|
|
1782
1782
|
result: {
|
|
1783
1783
|
case: "error",
|
|
@@ -1854,7 +1854,7 @@ function processInteractionUpdate(
|
|
|
1854
1854
|
arguments: {},
|
|
1855
1855
|
index: output.content.length,
|
|
1856
1856
|
partialJson: "",
|
|
1857
|
-
kind: "
|
|
1857
|
+
kind: "tool",
|
|
1858
1858
|
};
|
|
1859
1859
|
output.content.push(block);
|
|
1860
1860
|
state.setToolCall(block);
|
|
@@ -1879,7 +1879,7 @@ function processInteractionUpdate(
|
|
|
1879
1879
|
}
|
|
1880
1880
|
}
|
|
1881
1881
|
} else if (updateCase === "toolCallDelta" || updateCase === "partialToolCall") {
|
|
1882
|
-
if (state.currentToolCall?.kind === "
|
|
1882
|
+
if (state.currentToolCall?.kind === "tool") {
|
|
1883
1883
|
const delta = update.message.value.argsTextDelta || "";
|
|
1884
1884
|
state.currentToolCall.partialJson = `${state.currentToolCall.partialJson ?? ""}${delta}`;
|
|
1885
1885
|
state.currentToolCall.arguments = parseStreamingJson(state.currentToolCall.partialJson ?? "");
|
|
@@ -1889,8 +1889,8 @@ function processInteractionUpdate(
|
|
|
1889
1889
|
} else if (updateCase === "toolCallCompleted") {
|
|
1890
1890
|
if (state.currentToolCall) {
|
|
1891
1891
|
const toolCall = update.message.value.toolCall;
|
|
1892
|
-
if (state.currentToolCall.kind === "
|
|
1893
|
-
const decodedArgs =
|
|
1892
|
+
if (state.currentToolCall.kind === "tool") {
|
|
1893
|
+
const decodedArgs = decodeToolArgsMap(toolCall?.mcpToolCall?.args?.args);
|
|
1894
1894
|
if (decodedArgs) {
|
|
1895
1895
|
state.currentToolCall.arguments = decodedArgs;
|
|
1896
1896
|
}
|
|
@@ -1943,7 +1943,7 @@ function createBlobId(data: Uint8Array): Uint8Array {
|
|
|
1943
1943
|
|
|
1944
1944
|
const CURSOR_NATIVE_TOOL_NAMES = new Set(["bash", "read", "write", "delete", "ls", "grep", "lsp", "todo_write"]);
|
|
1945
1945
|
|
|
1946
|
-
function
|
|
1946
|
+
function buildCursorToolDefinitions(tools: Tool[] | undefined): McpToolDefinition[] {
|
|
1947
1947
|
if (!tools || tools.length === 0) {
|
|
1948
1948
|
return [];
|
|
1949
1949
|
}
|
package/src/types.ts
CHANGED
|
@@ -12,7 +12,6 @@ import type {
|
|
|
12
12
|
GrepResult,
|
|
13
13
|
LsArgs,
|
|
14
14
|
LsResult,
|
|
15
|
-
McpResult,
|
|
16
15
|
ReadArgs,
|
|
17
16
|
ReadResult,
|
|
18
17
|
ShellArgs,
|
|
@@ -222,7 +221,7 @@ export interface StreamOptions {
|
|
|
222
221
|
* Set to 0 to disable the first-event watchdog for this request.
|
|
223
222
|
*/
|
|
224
223
|
streamFirstEventTimeoutMs?: number;
|
|
225
|
-
/** Cursor
|
|
224
|
+
/** Cursor generic execution handlers (cursor-agent only). */
|
|
226
225
|
execHandlers?: CursorExecHandlers;
|
|
227
226
|
}
|
|
228
227
|
|
|
@@ -428,7 +427,8 @@ export type CursorToolResultHandler = (
|
|
|
428
427
|
result: ToolResultMessage,
|
|
429
428
|
) => ToolResultMessage | undefined | Promise<ToolResultMessage | undefined>;
|
|
430
429
|
|
|
431
|
-
|
|
430
|
+
/** A generic tool request transported by the Cursor agent protocol. */
|
|
431
|
+
export interface CursorToolCall {
|
|
432
432
|
name: string;
|
|
433
433
|
providerIdentifier: string;
|
|
434
434
|
toolName: string;
|
|
@@ -454,7 +454,7 @@ export interface CursorExecHandlers {
|
|
|
454
454
|
callbacks: CursorShellStreamCallbacks,
|
|
455
455
|
) => Promise<CursorExecHandlerResult<ShellResult>>;
|
|
456
456
|
diagnostics?: (args: DiagnosticsArgs) => Promise<CursorExecHandlerResult<DiagnosticsResult>>;
|
|
457
|
-
|
|
457
|
+
tool?: (call: CursorToolCall) => Promise<CursorExecHandlerResult<unknown>>;
|
|
458
458
|
onToolResult?: CursorToolResultHandler;
|
|
459
459
|
}
|
|
460
460
|
|
|
@@ -181,14 +181,14 @@ export function sanitizeSchemaForCCA(value: unknown): unknown {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
|
-
* Fields stripped for
|
|
184
|
+
* Fields stripped for AJV compatibility.
|
|
185
185
|
* Only `$schema` — AJV throws on unrecognised meta-schema URIs
|
|
186
186
|
* (e.g. draft 2020-12 emitted by schemars 1.x / rmcp 0.15+).
|
|
187
187
|
*/
|
|
188
|
-
const
|
|
188
|
+
const AJV_UNSUPPORTED_SCHEMA_FIELDS = new Set(["$schema"]);
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
* Sanitize a JSON Schema for
|
|
191
|
+
* Sanitize a JSON Schema for tool parameter validation (AJV compatibility).
|
|
192
192
|
*
|
|
193
193
|
* Strips only the minimal set of fields that cause AJV validation errors:
|
|
194
194
|
* - `$schema`: AJV throws on unknown meta-schema URIs.
|
|
@@ -198,7 +198,7 @@ const MCP_UNSUPPORTED_SCHEMA_FIELDS = new Set(["$schema"]);
|
|
|
198
198
|
* (`pattern`, `format`, `additionalProperties`, etc.) and `$ref`/`$defs`.
|
|
199
199
|
*/
|
|
200
200
|
export function sanitizeSchemaForMCP(value: unknown): unknown {
|
|
201
|
-
// Dereference $ref/$defs first
|
|
201
|
+
// Dereference $ref/$defs first because providers emit standard JSON Schema.
|
|
202
202
|
// with $defs, but providers (Anthropic, Google) only forward `properties`
|
|
203
203
|
// and `required`, dropping $defs and leaving dangling $ref pointers.
|
|
204
204
|
const dereferenced = dereferenceJsonSchema(value);
|
|
@@ -206,7 +206,7 @@ export function sanitizeSchemaForMCP(value: unknown): unknown {
|
|
|
206
206
|
insideProperties: false,
|
|
207
207
|
normalizeTypeArrayToNullable: false,
|
|
208
208
|
stripNullableKeyword: true,
|
|
209
|
-
unsupportedFields:
|
|
209
|
+
unsupportedFields: AJV_UNSUPPORTED_SCHEMA_FIELDS,
|
|
210
210
|
seen: new WeakSet(),
|
|
211
211
|
});
|
|
212
212
|
}
|
package/src/utils/validation.ts
CHANGED
|
@@ -513,7 +513,7 @@ function coerceArgsFromErrors(
|
|
|
513
513
|
// Create a singleton AJV instance with formats (only if not in browser extension)
|
|
514
514
|
// AJV requires 'unsafe-eval' CSP which is not allowed in Manifest V3
|
|
515
515
|
//
|
|
516
|
-
// Silent logger:
|
|
516
|
+
// Silent logger: external tool schemas may declare non-standard format keywords (e.g. "uint").
|
|
517
517
|
// which cause Ajv to emit console.warn() with strict:false — corrupting TUI output.
|
|
518
518
|
const ajv = new Ajv({
|
|
519
519
|
allErrors: false,
|