@oh-my-pi/pi-ai 7.0.0 → 8.0.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/package.json +6 -4
- package/src/providers/amazon-bedrock.ts +5 -5
- package/src/providers/anthropic.ts +7 -7
- package/src/providers/cursor.ts +5 -5
- package/src/providers/google-gemini-cli-usage.ts +2 -2
- package/src/providers/google-gemini-cli.ts +4 -4
- package/src/providers/google-shared.ts +2 -2
- package/src/providers/google-vertex.ts +5 -5
- package/src/providers/google.ts +6 -6
- package/src/providers/openai-codex-responses.ts +8 -8
- package/src/providers/openai-completions.ts +70 -50
- package/src/providers/openai-responses.ts +26 -9
- package/src/providers/transform-messages.ts +1 -1
- package/src/usage/claude.ts +1 -1
- package/src/usage/github-copilot.ts +1 -1
- package/src/usage/google-antigravity.ts +2 -2
- package/src/usage/openai-codex.ts +2 -2
- package/src/usage/zai.ts +1 -1
- package/src/utils/event-stream.ts +1 -1
- package/src/utils/oauth/github-copilot.ts +1 -1
- package/src/utils/overflow.ts +1 -1
- package/src/utils/validation.ts +1 -1
- package/tsconfig.json +25 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -10,14 +10,16 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"src",
|
|
13
|
-
"README.md"
|
|
13
|
+
"README.md",
|
|
14
|
+
"tsconfig.json"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
17
|
"generate-models": "bun scripts/generate-models.ts",
|
|
17
|
-
"test": "bun test"
|
|
18
|
+
"test": "bun test",
|
|
19
|
+
"prepublishOnly": "cp tsconfig.publish.json tsconfig.json"
|
|
18
20
|
},
|
|
19
21
|
"dependencies": {
|
|
20
|
-
"@oh-my-pi/pi-utils": "
|
|
22
|
+
"@oh-my-pi/pi-utils": "8.0.0",
|
|
21
23
|
"@anthropic-ai/sdk": "0.71.2",
|
|
22
24
|
"@aws-sdk/client-bedrock-runtime": "^3.968.0",
|
|
23
25
|
"@bufbuild/protobuf": "^2.10.2",
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
ToolResultStatus,
|
|
19
19
|
} from "@aws-sdk/client-bedrock-runtime";
|
|
20
20
|
|
|
21
|
-
import { calculateCost } from "
|
|
21
|
+
import { calculateCost } from "$ai/models";
|
|
22
22
|
import type {
|
|
23
23
|
Api,
|
|
24
24
|
AssistantMessage,
|
|
@@ -34,10 +34,10 @@ import type {
|
|
|
34
34
|
Tool,
|
|
35
35
|
ToolCall,
|
|
36
36
|
ToolResultMessage,
|
|
37
|
-
} from "
|
|
38
|
-
import { AssistantMessageEventStream } from "
|
|
39
|
-
import { parseStreamingJson } from "
|
|
40
|
-
import { sanitizeSurrogates } from "
|
|
37
|
+
} from "$ai/types";
|
|
38
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
39
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
40
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
41
41
|
import { transformMessages } from "./transform-messages";
|
|
42
42
|
|
|
43
43
|
export interface BedrockOptions extends StreamOptions {
|
|
@@ -4,8 +4,8 @@ import type {
|
|
|
4
4
|
MessageCreateParamsStreaming,
|
|
5
5
|
MessageParam,
|
|
6
6
|
} from "@anthropic-ai/sdk/resources/messages";
|
|
7
|
-
import { calculateCost } from "
|
|
8
|
-
import { getEnvApiKey, OUTPUT_FALLBACK_BUFFER } from "
|
|
7
|
+
import { calculateCost } from "$ai/models";
|
|
8
|
+
import { getEnvApiKey, OUTPUT_FALLBACK_BUFFER } from "$ai/stream";
|
|
9
9
|
import type {
|
|
10
10
|
Api,
|
|
11
11
|
AssistantMessage,
|
|
@@ -21,11 +21,11 @@ import type {
|
|
|
21
21
|
Tool,
|
|
22
22
|
ToolCall,
|
|
23
23
|
ToolResultMessage,
|
|
24
|
-
} from "
|
|
25
|
-
import { AssistantMessageEventStream } from "
|
|
26
|
-
import { parseStreamingJson } from "
|
|
27
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
28
|
-
import { sanitizeSurrogates } from "
|
|
24
|
+
} from "$ai/types";
|
|
25
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
26
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
27
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
28
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
29
29
|
|
|
30
30
|
import { transformMessages } from "./transform-messages";
|
|
31
31
|
|
package/src/providers/cursor.ts
CHANGED
|
@@ -4,7 +4,7 @@ import http2 from "node:http2";
|
|
|
4
4
|
import { create, fromBinary, fromJson, type JsonValue, toBinary, toJson } from "@bufbuild/protobuf";
|
|
5
5
|
import { ValueSchema } from "@bufbuild/protobuf/wkt";
|
|
6
6
|
import JSON5 from "json5";
|
|
7
|
-
import { calculateCost } from "
|
|
7
|
+
import { calculateCost } from "$ai/models";
|
|
8
8
|
import type {
|
|
9
9
|
Api,
|
|
10
10
|
AssistantMessage,
|
|
@@ -23,10 +23,10 @@ import type {
|
|
|
23
23
|
Tool,
|
|
24
24
|
ToolCall,
|
|
25
25
|
ToolResultMessage,
|
|
26
|
-
} from "
|
|
27
|
-
import { AssistantMessageEventStream } from "
|
|
28
|
-
import { parseStreamingJson } from "
|
|
29
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
26
|
+
} from "$ai/types";
|
|
27
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
28
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
29
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
30
30
|
import type { McpToolDefinition } from "./cursor/gen/agent_pb";
|
|
31
31
|
import {
|
|
32
32
|
AgentClientMessageSchema,
|
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
UsageProvider,
|
|
7
7
|
UsageReport,
|
|
8
8
|
UsageWindow,
|
|
9
|
-
} from "
|
|
10
|
-
import { refreshGoogleCloudToken } from "
|
|
9
|
+
} from "$ai/usage";
|
|
10
|
+
import { refreshGoogleCloudToken } from "$ai/utils/oauth/google-gemini-cli";
|
|
11
11
|
|
|
12
12
|
const DEFAULT_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
13
13
|
const CACHE_TTL_MS = 60_000;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import type { Content, ThinkingConfig } from "@google/genai";
|
|
9
9
|
import { abortableSleep } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import { calculateCost } from "
|
|
10
|
+
import { calculateCost } from "$ai/models";
|
|
11
11
|
import type {
|
|
12
12
|
Api,
|
|
13
13
|
AssistantMessage,
|
|
@@ -18,9 +18,9 @@ import type {
|
|
|
18
18
|
TextContent,
|
|
19
19
|
ThinkingContent,
|
|
20
20
|
ToolCall,
|
|
21
|
-
} from "
|
|
22
|
-
import { AssistantMessageEventStream } from "
|
|
23
|
-
import { sanitizeSurrogates } from "
|
|
21
|
+
} from "$ai/types";
|
|
22
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
23
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
24
24
|
import {
|
|
25
25
|
convertMessages,
|
|
26
26
|
convertTools,
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { type Content, FinishReason, FunctionCallingConfigMode, type Part, type Schema } from "@google/genai";
|
|
6
|
-
import type { Context, ImageContent, Model, StopReason, TextContent, Tool } from "
|
|
7
|
-
import { sanitizeSurrogates } from "
|
|
6
|
+
import type { Context, ImageContent, Model, StopReason, TextContent, Tool } from "$ai/types";
|
|
7
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
8
8
|
import { transformMessages } from "./transform-messages";
|
|
9
9
|
|
|
10
10
|
type GoogleApiType = "google-generative-ai" | "google-gemini-cli" | "google-vertex";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type ThinkingConfig,
|
|
6
6
|
ThinkingLevel,
|
|
7
7
|
} from "@google/genai";
|
|
8
|
-
import { calculateCost } from "
|
|
8
|
+
import { calculateCost } from "$ai/models";
|
|
9
9
|
import type {
|
|
10
10
|
Api,
|
|
11
11
|
AssistantMessage,
|
|
@@ -16,10 +16,10 @@ import type {
|
|
|
16
16
|
TextContent,
|
|
17
17
|
ThinkingContent,
|
|
18
18
|
ToolCall,
|
|
19
|
-
} from "
|
|
20
|
-
import { AssistantMessageEventStream } from "
|
|
21
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
22
|
-
import { sanitizeSurrogates } from "
|
|
19
|
+
} from "$ai/types";
|
|
20
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
21
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
22
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
23
23
|
import type { GoogleThinkingLevel } from "./google-gemini-cli";
|
|
24
24
|
import {
|
|
25
25
|
convertMessages,
|
package/src/providers/google.ts
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
GoogleGenAI,
|
|
5
5
|
type ThinkingConfig,
|
|
6
6
|
} from "@google/genai";
|
|
7
|
-
import { calculateCost } from "
|
|
8
|
-
import { getEnvApiKey } from "
|
|
7
|
+
import { calculateCost } from "$ai/models";
|
|
8
|
+
import { getEnvApiKey } from "$ai/stream";
|
|
9
9
|
import type {
|
|
10
10
|
Api,
|
|
11
11
|
AssistantMessage,
|
|
@@ -16,10 +16,10 @@ import type {
|
|
|
16
16
|
TextContent,
|
|
17
17
|
ThinkingContent,
|
|
18
18
|
ToolCall,
|
|
19
|
-
} from "
|
|
20
|
-
import { AssistantMessageEventStream } from "
|
|
21
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
22
|
-
import { sanitizeSurrogates } from "
|
|
19
|
+
} from "$ai/types";
|
|
20
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
21
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
22
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
23
23
|
import type { GoogleThinkingLevel } from "./google-gemini-cli";
|
|
24
24
|
import {
|
|
25
25
|
convertMessages,
|
|
@@ -9,9 +9,8 @@ import type {
|
|
|
9
9
|
ResponseOutputMessage,
|
|
10
10
|
ResponseReasoningItem,
|
|
11
11
|
} from "openai/resources/responses/responses";
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
import { getEnvApiKey } from "../stream";
|
|
12
|
+
import { calculateCost } from "$ai/models";
|
|
13
|
+
import { getEnvApiKey } from "$ai/stream";
|
|
15
14
|
import type {
|
|
16
15
|
Api,
|
|
17
16
|
AssistantMessage,
|
|
@@ -24,11 +23,12 @@ import type {
|
|
|
24
23
|
ThinkingContent,
|
|
25
24
|
Tool,
|
|
26
25
|
ToolCall,
|
|
27
|
-
} from "
|
|
28
|
-
import { AssistantMessageEventStream } from "
|
|
29
|
-
import { parseStreamingJson } from "
|
|
30
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
31
|
-
import { sanitizeSurrogates } from "
|
|
26
|
+
} from "$ai/types";
|
|
27
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
28
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
29
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
30
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
31
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
32
32
|
import {
|
|
33
33
|
CODEX_BASE_URL,
|
|
34
34
|
JWT_CLAIM_PATH,
|
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
ChatCompletionMessageParam,
|
|
9
9
|
ChatCompletionToolMessageParam,
|
|
10
10
|
} from "openai/resources/chat/completions";
|
|
11
|
-
import { calculateCost } from "
|
|
12
|
-
import { getEnvApiKey } from "
|
|
11
|
+
import { calculateCost } from "$ai/models";
|
|
12
|
+
import { getEnvApiKey } from "$ai/stream";
|
|
13
13
|
import type {
|
|
14
14
|
AssistantMessage,
|
|
15
15
|
Context,
|
|
@@ -23,11 +23,12 @@ import type {
|
|
|
23
23
|
ThinkingContent,
|
|
24
24
|
Tool,
|
|
25
25
|
ToolCall,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
26
|
+
ToolResultMessage,
|
|
27
|
+
} from "$ai/types";
|
|
28
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
29
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
30
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
31
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
31
32
|
import { transformMessages } from "./transform-messages";
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -464,7 +465,7 @@ function maybeAddOpenRouterAnthropicCacheControl(
|
|
|
464
465
|
}
|
|
465
466
|
}
|
|
466
467
|
|
|
467
|
-
function convertMessages(
|
|
468
|
+
export function convertMessages(
|
|
468
469
|
model: Model<"openai-completions">,
|
|
469
470
|
context: Context,
|
|
470
471
|
compat: Required<OpenAICompat>,
|
|
@@ -481,7 +482,8 @@ function convertMessages(
|
|
|
481
482
|
|
|
482
483
|
let lastRole: string | null = null;
|
|
483
484
|
|
|
484
|
-
for (
|
|
485
|
+
for (let i = 0; i < transformedMessages.length; i++) {
|
|
486
|
+
const msg = transformedMessages[i];
|
|
485
487
|
// Some providers (e.g. Mistral/Devstral) don't allow user messages directly after tool results
|
|
486
488
|
// Insert a synthetic assistant message to bridge the gap
|
|
487
489
|
if (compat.requiresAssistantAfterToolResult && lastRole === "toolResult" && msg.role === "user") {
|
|
@@ -605,55 +607,73 @@ function convertMessages(
|
|
|
605
607
|
}
|
|
606
608
|
params.push(assistantMsg);
|
|
607
609
|
} else if (msg.role === "toolResult") {
|
|
608
|
-
//
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
content
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
(
|
|
610
|
+
// Batch consecutive tool results and collect all images
|
|
611
|
+
const imageBlocks: Array<{ type: "image_url"; image_url: { url: string } }> = [];
|
|
612
|
+
let j = i;
|
|
613
|
+
|
|
614
|
+
for (; j < transformedMessages.length && transformedMessages[j].role === "toolResult"; j++) {
|
|
615
|
+
const toolMsg = transformedMessages[j] as ToolResultMessage;
|
|
616
|
+
|
|
617
|
+
// Extract text and image content
|
|
618
|
+
const textResult = toolMsg.content
|
|
619
|
+
.filter((c) => c.type === "text")
|
|
620
|
+
.map((c) => (c as any).text)
|
|
621
|
+
.join("\n");
|
|
622
|
+
const hasImages = toolMsg.content.some((c) => c.type === "image");
|
|
623
|
+
|
|
624
|
+
// Always send tool result with text (or placeholder if only images)
|
|
625
|
+
const hasText = textResult.length > 0;
|
|
626
|
+
// Some providers (e.g. Mistral) require the 'name' field in tool results
|
|
627
|
+
const toolResultMsg: ChatCompletionToolMessageParam = {
|
|
628
|
+
role: "tool",
|
|
629
|
+
content: sanitizeSurrogates(hasText ? textResult : "(see attached image)"),
|
|
630
|
+
tool_call_id: normalizeMistralToolId(toolMsg.toolCallId, compat.requiresMistralToolIds),
|
|
631
|
+
};
|
|
632
|
+
if (compat.requiresToolResultName && toolMsg.toolName) {
|
|
633
|
+
(toolResultMsg as any).name = toolMsg.toolName;
|
|
634
|
+
}
|
|
635
|
+
params.push(toolResultMsg);
|
|
636
|
+
|
|
637
|
+
if (hasImages && model.input.includes("image")) {
|
|
638
|
+
for (const block of toolMsg.content) {
|
|
639
|
+
if (block.type === "image") {
|
|
640
|
+
imageBlocks.push({
|
|
641
|
+
type: "image_url",
|
|
642
|
+
image_url: {
|
|
643
|
+
url: `data:${(block as any).mimeType};base64,${(block as any).data}`,
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
625
649
|
}
|
|
626
|
-
params.push(toolResultMsg);
|
|
627
|
-
|
|
628
|
-
// If there are images and model supports them, send a follow-up user message with images
|
|
629
|
-
if (hasImages && model.input.includes("image")) {
|
|
630
|
-
const contentBlocks: Array<
|
|
631
|
-
{ type: "text"; text: string } | { type: "image_url"; image_url: { url: string } }
|
|
632
|
-
> = [];
|
|
633
|
-
|
|
634
|
-
// Add text prefix
|
|
635
|
-
contentBlocks.push({
|
|
636
|
-
type: "text",
|
|
637
|
-
text: "Attached image(s) from tool result:",
|
|
638
|
-
});
|
|
639
650
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
651
|
+
i = j - 1;
|
|
652
|
+
|
|
653
|
+
// After all consecutive tool results, add a single user message with all images
|
|
654
|
+
if (imageBlocks.length > 0) {
|
|
655
|
+
if (compat.requiresAssistantAfterToolResult) {
|
|
656
|
+
params.push({
|
|
657
|
+
role: "assistant",
|
|
658
|
+
content: "I have processed the tool results.",
|
|
659
|
+
});
|
|
650
660
|
}
|
|
651
661
|
|
|
652
662
|
params.push({
|
|
653
663
|
role: "user",
|
|
654
|
-
content:
|
|
664
|
+
content: [
|
|
665
|
+
{
|
|
666
|
+
type: "text",
|
|
667
|
+
text: "Attached image(s) from tool result:",
|
|
668
|
+
},
|
|
669
|
+
...imageBlocks,
|
|
670
|
+
],
|
|
655
671
|
});
|
|
672
|
+
lastRole = "user";
|
|
673
|
+
} else {
|
|
674
|
+
lastRole = "toolResult";
|
|
656
675
|
}
|
|
676
|
+
continue;
|
|
657
677
|
}
|
|
658
678
|
|
|
659
679
|
lastRole = msg.role;
|
|
@@ -10,8 +10,8 @@ import type {
|
|
|
10
10
|
ResponseOutputMessage,
|
|
11
11
|
ResponseReasoningItem,
|
|
12
12
|
} from "openai/resources/responses/responses";
|
|
13
|
-
import { calculateCost } from "
|
|
14
|
-
import { getEnvApiKey } from "
|
|
13
|
+
import { calculateCost } from "$ai/models";
|
|
14
|
+
import { getEnvApiKey } from "$ai/stream";
|
|
15
15
|
import type {
|
|
16
16
|
Api,
|
|
17
17
|
AssistantMessage,
|
|
@@ -24,11 +24,11 @@ import type {
|
|
|
24
24
|
ThinkingContent,
|
|
25
25
|
Tool,
|
|
26
26
|
ToolCall,
|
|
27
|
-
} from "
|
|
28
|
-
import { AssistantMessageEventStream } from "
|
|
29
|
-
import { parseStreamingJson } from "
|
|
30
|
-
import { formatErrorMessageWithRetryAfter } from "
|
|
31
|
-
import { sanitizeSurrogates } from "
|
|
27
|
+
} from "$ai/types";
|
|
28
|
+
import { AssistantMessageEventStream } from "$ai/utils/event-stream";
|
|
29
|
+
import { parseStreamingJson } from "$ai/utils/json-parse";
|
|
30
|
+
import { formatErrorMessageWithRetryAfter } from "$ai/utils/retry-after";
|
|
31
|
+
import { sanitizeSurrogates } from "$ai/utils/sanitize-unicode";
|
|
32
32
|
import { transformMessages } from "./transform-messages";
|
|
33
33
|
|
|
34
34
|
/** Fast deterministic hash to shorten long strings */
|
|
@@ -507,6 +507,15 @@ function convertMessages(
|
|
|
507
507
|
}
|
|
508
508
|
} else if (msg.role === "assistant") {
|
|
509
509
|
const output: ResponseInput = [];
|
|
510
|
+
const assistantMsg = msg as AssistantMessage;
|
|
511
|
+
|
|
512
|
+
// Check if this message is from a different model (same provider, different model ID).
|
|
513
|
+
// For such messages, tool call IDs with fc_ prefix need to be stripped to avoid
|
|
514
|
+
// OpenAI's reasoning/function_call pairing validation errors.
|
|
515
|
+
const isDifferentModel =
|
|
516
|
+
assistantMsg.model !== model.id &&
|
|
517
|
+
assistantMsg.provider === model.provider &&
|
|
518
|
+
assistantMsg.api === model.api;
|
|
510
519
|
|
|
511
520
|
for (const block of msg.content) {
|
|
512
521
|
// Do not submit thinking blocks if the completion had an error (i.e. abort)
|
|
@@ -535,11 +544,19 @@ function convertMessages(
|
|
|
535
544
|
} else if (block.type === "toolCall" && msg.stopReason !== "error") {
|
|
536
545
|
const toolCall = block as ToolCall;
|
|
537
546
|
const normalized = normalizeResponsesToolCallId(toolCall.id);
|
|
547
|
+
const callId = normalized.callId;
|
|
548
|
+
// For different-model messages, set id to undefined to avoid pairing validation.
|
|
549
|
+
// OpenAI tracks which fc_xxx IDs were paired with rs_xxx reasoning items.
|
|
550
|
+
// By omitting the id, we avoid triggering that validation (like cross-provider does).
|
|
551
|
+
let itemId: string | undefined = normalized.itemId;
|
|
552
|
+
if (isDifferentModel && itemId?.startsWith("fc_")) {
|
|
553
|
+
itemId = undefined;
|
|
554
|
+
}
|
|
538
555
|
knownCallIds.add(normalized.callId);
|
|
539
556
|
output.push({
|
|
540
557
|
type: "function_call",
|
|
541
|
-
id:
|
|
542
|
-
call_id:
|
|
558
|
+
id: itemId,
|
|
559
|
+
call_id: callId,
|
|
543
560
|
name: toolCall.name,
|
|
544
561
|
arguments: JSON.stringify(toolCall.arguments),
|
|
545
562
|
});
|
package/src/usage/claude.ts
CHANGED
|
@@ -7,8 +7,8 @@ import type {
|
|
|
7
7
|
UsageReport,
|
|
8
8
|
UsageStatus,
|
|
9
9
|
UsageWindow,
|
|
10
|
-
} from "
|
|
11
|
-
import { refreshAntigravityToken } from "
|
|
10
|
+
} from "$ai/usage";
|
|
11
|
+
import { refreshAntigravityToken } from "$ai/utils/oauth/google-antigravity";
|
|
12
12
|
|
|
13
13
|
interface AntigravityQuotaInfo {
|
|
14
14
|
remainingFraction?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
-
import { CODEX_BASE_URL } from "
|
|
2
|
+
import { CODEX_BASE_URL } from "$ai/providers/openai-codex/constants";
|
|
3
3
|
import type {
|
|
4
4
|
UsageAmount,
|
|
5
5
|
UsageCache,
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
UsageProvider,
|
|
10
10
|
UsageReport,
|
|
11
11
|
UsageWindow,
|
|
12
|
-
} from "
|
|
12
|
+
} from "$ai/usage";
|
|
13
13
|
|
|
14
14
|
const CODEX_USAGE_PATH = "wham/usage";
|
|
15
15
|
const DEFAULT_CACHE_TTL_MS = 60_000;
|
package/src/usage/zai.ts
CHANGED
package/src/utils/overflow.ts
CHANGED
package/src/utils/validation.ts
CHANGED
|
@@ -5,7 +5,7 @@ import addFormatsModule from "ajv-formats";
|
|
|
5
5
|
const Ajv = (AjvModule as any).default || AjvModule;
|
|
6
6
|
const addFormats = (addFormatsModule as any).default || addFormatsModule;
|
|
7
7
|
|
|
8
|
-
import type { Tool, ToolCall } from "
|
|
8
|
+
import type { Tool, ToolCall } from "$ai/types";
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Type Coercion Utilities
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2024",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2024"],
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"moduleResolution": "Bundler",
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"experimentalDecorators": true,
|
|
14
|
+
"emitDecoratorMetadata": true,
|
|
15
|
+
"useDefineForClassFields": false,
|
|
16
|
+
"types": ["bun", "node"],
|
|
17
|
+
"noEmit": true,
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"paths": {
|
|
20
|
+
"$ai/*": ["./src/*"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"include": ["src/**/*.ts"],
|
|
24
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts", "test/**"]
|
|
25
|
+
}
|