





















@@ -36,6 +36,7 @@ async function loadCreatePdfTool() {
36363737const ANTHROPIC_PDF_MODEL = "anthropic/claude-opus-4-6";
3838const OPENAI_PDF_MODEL = "openai/gpt-5.4-mini";
39+const CODEX_PDF_MODEL = "openai-codex/gpt-5.4";
3940const FAKE_PDF_MEDIA = {
4041kind: "document",
4142buffer: Buffer.from("%PDF-1.4 fake"),
@@ -85,6 +86,7 @@ async function stubPdfToolInfra(
8586mockLoad?: boolean;
8687provider?: string;
8788input?: string[];
89+api?: string;
8890modelFound?: boolean;
8991},
9092) {
@@ -102,6 +104,13 @@ async function stubPdfToolInfra(
102104 : () =>
103105({
104106provider: params?.provider ?? "anthropic",
107+api:
108+params?.api ??
109+(params?.provider === "openai-codex"
110+ ? "openai-codex-responses"
111+ : params?.provider === "openai"
112+ ? "openai-responses"
113+ : "anthropic-messages"),
105114maxTokens: 8192,
106115input: params?.input ?? ["text", "document"],
107116}) as never;
@@ -469,6 +478,82 @@ describe("createPdfTool", () => {
469478content: [{ type: "text", text: "fallback summary" }],
470479details: { native: false, model: OPENAI_PDF_MODEL },
471480});
481+const [, context] = completeMock.mock.calls[0] ?? [];
482+expect(context?.systemPrompt).toBeUndefined();
483+});
484+});
485+486+it("adds Codex instructions for PDF extraction fallback requests", async () => {
487+await withTempPdfAgentDir(async (agentDir) => {
488+await stubPdfToolInfra(agentDir, {
489+provider: "openai-codex",
490+api: "openai-codex-responses",
491+input: ["text", "image"],
492+});
493+494+vi.spyOn(pdfExtractModule, "extractPdfContent").mockResolvedValue({
495+text: "Extracted content",
496+images: [],
497+});
498+499+completeMock.mockResolvedValue({
500+role: "assistant",
501+stopReason: "stop",
502+content: [{ type: "text", text: "codex summary" }],
503+} as never);
504+505+const cfg = withPdfModel(CODEX_PDF_MODEL);
506+const tool = requirePdfTool((await loadCreatePdfTool())({ config: cfg, agentDir }));
507+508+const result = await tool.execute("t1", {
509+prompt: "summarize",
510+pdf: "/tmp/doc.pdf",
511+});
512+513+expect(result).toMatchObject({
514+content: [{ type: "text", text: "codex summary" }],
515+details: { native: false, model: CODEX_PDF_MODEL },
516+});
517+expect(completeMock).toHaveBeenCalledTimes(1);
518+const [, context] = completeMock.mock.calls[0] ?? [];
519+expect(context?.systemPrompt).toContain("Analyze the provided PDF content");
520+});
521+});
522+523+it("adds Codex instructions when extraction has images but the model only accepts text", async () => {
524+await withTempPdfAgentDir(async (agentDir) => {
525+await stubPdfToolInfra(agentDir, {
526+provider: "openai-codex",
527+api: "openai-codex-responses",
528+input: ["text"],
529+});
530+531+vi.spyOn(pdfExtractModule, "extractPdfContent").mockResolvedValue({
532+text: "Extracted content",
533+images: [{ type: "image", data: "base64img", mimeType: "image/png" }],
534+});
535+536+completeMock.mockResolvedValue({
537+role: "assistant",
538+stopReason: "stop",
539+content: [{ type: "text", text: "codex summary" }],
540+} as never);
541+542+const cfg = withPdfModel(CODEX_PDF_MODEL);
543+const tool = requirePdfTool((await loadCreatePdfTool())({ config: cfg, agentDir }));
544+545+const result = await tool.execute("t1", {
546+prompt: "summarize",
547+pdf: "/tmp/doc.pdf",
548+});
549+550+expect(result).toMatchObject({
551+content: [{ type: "text", text: "codex summary" }],
552+details: { native: false, model: CODEX_PDF_MODEL },
553+});
554+expect(completeMock).toHaveBeenCalledTimes(1);
555+const [, context] = completeMock.mock.calls[0] ?? [];
556+expect(context?.systemPrompt).toContain("Analyze the provided PDF content");
472557});
473558});
474559此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。