chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
+38
-18
@@ -1,14 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { convertMessages } from "../src/api/openai-completions.ts";
|
||||
import { getModel } from "../src/compat.ts";
|
||||
import type {
|
||||
AssistantMessage,
|
||||
Context,
|
||||
Model,
|
||||
OpenAICompletionsCompat,
|
||||
ToolResultMessage,
|
||||
Usage,
|
||||
} from "../src/types.ts";
|
||||
import { getModel, normalizeContext } from "../src/compat.ts";
|
||||
import type { AssistantMessage, Model, OpenAICompletionsCompat, ToolResultMessage, Usage } from "../src/types.ts";
|
||||
|
||||
const emptyUsage: Usage = {
|
||||
input: 0,
|
||||
@@ -19,11 +12,7 @@ const emptyUsage: Usage = {
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
};
|
||||
|
||||
const compat: Omit<
|
||||
Required<OpenAICompletionsCompat>,
|
||||
"deferredToolsMode" | "thinkingTokenBudgetField" | "vllmPriority"
|
||||
> & {
|
||||
deferredToolsMode?: OpenAICompletionsCompat["deferredToolsMode"];
|
||||
const compat: Omit<Required<OpenAICompletionsCompat>, "thinkingTokenBudgetField" | "vllmPriority"> & {
|
||||
thinkingTokenBudgetField?: OpenAICompletionsCompat["thinkingTokenBudgetField"];
|
||||
} = {
|
||||
supportsStore: true,
|
||||
@@ -46,6 +35,8 @@ const compat: Omit<
|
||||
thinkingTokenBudgetField: undefined,
|
||||
supportsStrictMode: true,
|
||||
supportsOpenAIGrammarTools: false,
|
||||
supportsMidConvoSystemMessages: false,
|
||||
supportsMidConvoToolAdditions: false,
|
||||
cacheControlFormat: "anthropic",
|
||||
sendSessionAffinityHeaders: false,
|
||||
sessionAffinityFormat: "openai",
|
||||
@@ -78,6 +69,35 @@ function buildEmptyToolResult(toolCallId: string, timestamp: number): ToolResult
|
||||
}
|
||||
|
||||
describe("openai-completions convertMessages", () => {
|
||||
// Regression test for https://github.com/earendil-works/pi/issues/9797
|
||||
it("omits empty text parts from user messages with images", () => {
|
||||
const { compat: _compat, ...baseModel } = getModel("openai", "gpt-4o-mini");
|
||||
const model: Model<"openai-completions"> = {
|
||||
...baseModel,
|
||||
api: "openai-completions",
|
||||
input: ["text", "image"],
|
||||
};
|
||||
const context = normalizeContext({
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "" },
|
||||
{ type: "image", data: "ZmFrZQ==", mimeType: "image/png" },
|
||||
],
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(convertMessages(model, context, compat)).toEqual([
|
||||
{
|
||||
role: "user",
|
||||
content: [{ type: "image_url", image_url: { url: "data:image/png;base64,ZmFrZQ==" } }],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("batches tool-result images after consecutive tool results", () => {
|
||||
const { compat: _compat, ...baseModel } = getModel("openai", "gpt-4o-mini");
|
||||
const model: Model<"openai-completions"> = {
|
||||
@@ -101,14 +121,14 @@ describe("openai-completions convertMessages", () => {
|
||||
timestamp: now,
|
||||
};
|
||||
|
||||
const context: Context = {
|
||||
const context = normalizeContext({
|
||||
messages: [
|
||||
{ role: "user", content: "Read the images", timestamp: now - 2 },
|
||||
assistantMessage,
|
||||
buildToolResult("tool-1", now + 1),
|
||||
buildToolResult("tool-2", now + 2),
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const messages = convertMessages(model, context, compat);
|
||||
const roles = messages.map((message) => message.role);
|
||||
@@ -144,13 +164,13 @@ describe("openai-completions convertMessages", () => {
|
||||
timestamp: now,
|
||||
};
|
||||
|
||||
const context: Context = {
|
||||
const context = normalizeContext({
|
||||
messages: [
|
||||
{ role: "user", content: "Run the command", timestamp: now - 1 },
|
||||
assistantMessage,
|
||||
buildEmptyToolResult("tool-1", now + 1),
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const messages = convertMessages(model, context, compat);
|
||||
const toolMessage = messages.find((m) => m.role === "tool") as { role: "tool"; content: string } | undefined;
|
||||
|
||||
Reference in new issue
Block a user