Tested image resizing with large PNG on npm 0.49.0.
ReproduceAnalyzed possible causes for user-reported issue.
UnderstandConfirmed resizing works correctly in tests.
Verifyhttps://github.com/badlogic/pi-mono/issues/824
issue got closed, we just fixed shit for bun. but user reports the last npm release 0.49.0 has this issue. we have an image in /tmp/large_test.png, can you test the last release please?
The user wants me to test an issue from GitHub related to the last npm release (0.49.0). Let me first read the issue to understand what we're testing.
>gh issue view 824 --json title,body,comments,labels,state --repo badlogic/pi-monoNow I understand the issue. It's about large images exceeding Claude's 5MB limit. The user brunohaid reports that even npm 0.49.0 has this issue. The fix was done for Bun, but user says it's still happening with npm version.
Let me test with the released 0.49.0 npm version using the image at /tmp/large_test.png.
First let me check the image exists and its size.
Let me check the image and test with the released npm version:
>ls -lh /tmp/large_test.png && file /tmp/large_test.png>npm show @anthropic-ai/claude-code version 2>/dev/null || echo "checking pi"24MB PNG, 4000x4000 resolution. That's a good test case. Now let me install the released 0.49.0 version of pi and test it. Let me first check what the package is named.
>npm show @anthropic-ai/pi version 2>/dev/null || npm show pi version 2>/dev/null || echo "need to find package name">cat packages/coding-agent/package.json | grep '"name"'So the package is @mariozechner/pi-coding-agent. Let me check the released version and install 0.49.0 to test.
>npm show @mariozechner/pi-coding-agent versions --json | tail -10Good, 0.49.0 is the latest release. Let me install it in a temp location and test the image resizing.
>cd /tmp && rm -rf pi-test-049 && mkdir pi-test-049 && cd pi-test-049 && npm init -y && npm install @mariozechner/pi-coding-agent@0.49.0 2>&1 | tail -10Good, installed. Now let me look at how the image resizing is done in the coding-agent to understand where the issue might be. But first, let me write a simple test script to test if the image processing works correctly.
Let me find where image processing happens and write a test:
>grep -r "photon" packages/coding-agent/src --include="*.ts" -l>grep -r "resizeImage\|processImage\|image.*resize" packages/coding-agent/src --include="*.ts" -l | head -5Let me look at the image-resize.ts to understand what it exports and how it's used.
So the key is loadPhoton() from ./photon.js. Let me check that file.
The code handles loading photon-node. The issue might be in how photon is loaded in the npm version. Let me write a test script to check if loadPhoton() successfully loads in the 0.49.0 release.
Let me write a test script to check if photon loads in 0.49.0:
Let me run this test with the npm version 0.49.0.
>cd /tmp/pi-test-049 && node test-photon.mjs 2>&1The exports don't expose the internal module. Let me check what's exported and write a different test approach. I could test by using pi directly with an image.
Let me check what's exported and find another way to test:
>cat /tmp/pi-test-049/node_modules/@mariozechner/pi-coding-agent/package.json | grep -A 30 '"exports"'Let me write a simpler test that uses require and directly accesses the internal modules. Or I can test by calling pi directly with the image. Let me try calling pi with the image as input.
Let me run this test with the npm version 0.49.0.
>cd /tmp/pi-test-049 && node test-photon.cjs 2>&1Interesting! The resizing works correctly in the npm version when I test the module directly. The image went from 23.55 MB to 0.66 MB. So the issue isn't in the npm package itself.
Wait, the user's screenshot shows the issue happening. Maybe it's about how the image is being read in the tool result context. Let me check where images are processed in tool results.
Let me look at where images are processed when being sent to Claude in tool results or the Read tool.
The resizing works in 0.49.0! The image went from 23.55 MB to 0.66 MB. Let me check if there's a path where images might bypass the resize logic:
The read tool properly uses resizeImage for images. Let me check the file-processor.ts to see if there's another path for images.
Both
continue
The user wants me to continue my investigation. Both the read tool and file-processor properly use resizeImage. Let me check if there's maybe an issue with how images are passed in tool results or user messages. Let me also check what version of photon-node is in 0.49.0 vs current.
>cat /tmp/pi-test-049/node_modules/@mariozechner/pi-coding-agent/node_modules/@silvia-odwyer/photon-node/package.json 2>/dev/null | grep version || cat /tmp/pi-test-049/node_modules/@silvia-odwyer/photon-node/package.json 2>/dev/null | grep version>cat packages/coding-agent/node_modules/@silvia-odwyer/photon-node/package.json 2>/dev/null | grep version || echo "checking root"Both have photon-node 0.3.4. The resizing works fine when I test it directly. Let me check if there's maybe something in the tool result processing that could bypass resizing.
Actually, let me test the full pi CLI with the image to see if something happens there. But that's not easily scriptable.
Wait, the user's screenshot shows they're adding an image via @-file argument. Let me check if maybe there's a different issue. Let me also check if there might be an issue with how the image gets processed when the model makes a read tool call vs when the user provides an image.
Actually, let me re-read the issue comments more carefully. The user brunohaid says it's still happening with npm 0.49.0 and they show a screenshot. The error message shows it's in a tool_result context (messages.169.content.0.tool_result.content.1.image).
So the issue might be in how tool results with images are processed. But I just checked read.ts and it does use resizeImage...
Let me check if there might be cases where resizeImage returns early without actually resizing - like when photon can't load.
Let me check if photon could silently fail to load. Looking at the resize code, when photon is null it returns wasResized: false:
>cd /tmp/pi-test-049 && cat > test-photon-load.cjs << 'EOF'
const path = require("path");
async function main() {
const photonPath = path.join(__dirname, "node_modules/@mariozechner/pi-coding-agent/dist/utils/photon.js");
const { loadPhoton } = await import(photonPath);
const photon = await loadPhoton();
console.log("Photon loaded:", photon !== null);
if (photon) {
console.log("Has PhotonImage:", typeof photon.PhotonImage);
console.log("Has resize:", typeof photon.resize);
}
}
main().catch(console.error);
EOF
node test-photon-load.cjs 2>&1Photon loads fine. Let me check if there could be an issue with the way images are being handled when they come from different sources (like clipboard or screenshots). Let me also check if maybe the user has an older cached version or something, or if there's a race condition.Wait, let me think about this differently. The test I wrote works. The user reports it doesn't work for them. What could be different?
Let me check if there are other places where images might be passed without resizing.
>grep -r "type.*image" packages/coding-agent/src --include="*.ts" | grep -v "resizeImage\|ImageContent\|mimeType\|\.d\.ts" | grep -v test | head -20>grep -r "base64" packages/coding-agent/src --include="*.ts" | grep -v "resizeImage\|\.d\.ts\|test" | head -10I see there's an image-convert.ts. Let me check that file and also see how images flow through the CLI.
This is just for PNG conversion for terminal display, not relevant to the issue.
Let me check if there might be an issue with how images are handled when coming from the clipboard or pasted into the prompt. Let me check the interactive mode's input handling.
>grep -r "resizeImage" packages/coding-agent/src --include="*.ts" -lSo resizeImage is only used in:
But what about images pasted into the chat or from clipboard? Let me check if there's another code path for images that doesn't use resizeImage.
>grep -r "clipboard\|paste" packages/coding-agent/src --include="*.ts" -l | head -5Let me check the clipboard.ts and the interactive-mode.ts to see how clipboard images are handled.
This is just for text clipboard, not images. Let me check clipboard-image.ts
>find packages/coding-agent/src -name "clipboard-image*" -o -name "*image*clipboard*" 2>/dev/nullLet me check this file.
So readClipboardImage returns raw image bytes without resizing. Now let me see where this is used and if the images get resized before being sent to the API.
>grep -r "readClipboardImage" packages/coding-agent/src --include="*.ts" -A5 -B5 | head -60I see that handleClipboardImagePaste reads the image and writes it to a temp file. Let me see what happens after that.
>grep -A50 "handleClipboardImagePaste" packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -60I see! When a clipboard image is pasted, it writes the raw bytes to a temp file and inserts the file path. Then this path gets processed like any other file. Let me see how the editor submission handles files.
>grep -A100 "setupEditorSubmitHandler" packages/coding-agent/src/modes/interactive/interactive-mode.ts | grep -A50 "processInputWithFiles\|processFileArguments" | head -60Let me search for where file processing happens in the interactive mode.
>grep -n "processFileArguments\|processedFiles\|processInput" packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -20Let me search for how the editor submission handles files.
>grep -n "images\|ImageContent\|mimeType" packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -20Let me search for where the prompt is called with files/images.
>grep -n "session.prompt\|sdk.prompt" packages/coding-agent/src/modes/interactive/interactive-mode.tsI see images are passed to session.prompt at line 501, but where does the main submit handler process files? Let me look at how the submitted text with file paths gets processed.
>grep -B5 -A30 'session\.prompt\(text\)' packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -80Let me look for where input is handled and how files are extracted from text.
>grep -n "extractFiles\|parseFiles\|fileProcessor\|@file\|FilePath" packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -10Let me look at the custom-editor component which might handle file references.
The custom editor doesn't handle files directly. Let me look at the session manager to see how prompts are processed.
>grep -n "import.*ImageContent\|images.*ImageContent\|resizeImage" packages/coding-agent/src/core/session-manager.ts | head -10Let me look at the prompt method in the session manager.
>grep -B5 -A50 "async prompt\(" packages/coding-agent/src/core/session-manager.ts | head -80Need to escape the parenthesis.
>grep -B5 -A50 "async prompt" packages/coding-agent/src/core/session-manager.ts | head -80Let me look at session-manager to find where the prompt method is defined.
>grep -n "prompt" packages/coding-agent/src/core/session-manager.ts | head -20Let me check where Session is defined.
>grep -n "class Session\|prompt(" packages/coding-agent/src/core/session-manager.ts | head -20SessionManager, not Session. Let me look at sdk.ts where the main session logic is.
>grep -n "prompt" packages/coding-agent/src/core/sdk.ts | head -20Let me look at how the SDK handles prompts.
>grep -n "prompt\|images" packages/coding-agent/src/core/sdk.ts | head -40Let me check where the images flow from user input to the API. Let me look at the agent-core package which might handle this.
>grep -rn "resizeImage\|autoResize\|ImageContent" packages/agent-core/src --include="*.ts" | head -20Let me check the pi-agent-core package instead.
>ls packages/It's packages/agent not packages/agent-core. Let me check that.
>grep -rn "resizeImage\|autoResize\|ImageContent" packages/agent/src --include="*.ts" | head -20Let me look at the agent.ts prompt method to see how images are handled.
>grep -B5 -A30 "async prompt" packages/agent/src/agent.tsI see. The agent just passes images through without resizing. The resizing is done in the Read tool and file-processor. Let me check where images from CLI @-file arguments get processed and how they flow to the agent.Let me trace the flow from the CLI entry point.
>grep -rn "processFileArguments\|initialImages" packages/coding-agent/src --include="*.ts" | head -20OK so processFileArguments in main.ts does resize images. But looking at the issue again, the user's error shows messages.169.content.0.tool_result, so the issue is when the image comes from a tool result (the Read tool). And the Read tool does resize images...
Wait, let me look at the error message more carefully: messages.169.content.0.tool_result.content.1.image.source.base64. This is a tool result. Let me look at the 0.49.0 read.ts to see if there's a difference.
The read.js code looks fine - it does call resizeImage. Let me write a full test that mimics what the Read tool does to see if the issue is reproducible.
Let me run this test.
>cd /tmp/pi-test-049 && node test-read-tool.cjs 2>&1The Read tool works correctly in 0.49.0. The 24MB image is resized to 0.66MB. So the npm version works fine...The user brunohaid claims npm 0.49.0 doesn't work for them. Let me think about what could be different:
The issue was closed after fixing the Bun binary issue. Looking at the comments again:
Let me check if there's any condition under which photon loading might fail silently. Looking at the code, when photon fails to load, it returns wasResized: false and returns the original image unchanged.
Maybe the user has some issue where photon fails to load but they don't know it? Let me check if there's any way to test this.Actually, let me confirm by checking the screenshot context more carefully. The user's screenshot shows the image being over 5MB. Let me re-read the comments.
In brunohaid's screenshot, it shows an error about the base64 image exceeding the limit. This could happen if:
Looking at the resize code:
if (!photon) { // Photon not available, return original image return { data: img.data, mimeType: img.mimeType, ... wasResized: false, };}So if photon fails to load, the original image is returned.
If photon isn't loading properly, the uncompressed image would exceed the 5MB limit. I need to figure out what could prevent photon from initializing in their npm setup.
The npm version works correctly in my tests. Let me check what could cause photon to fail silently:
Let me run this test.
>cd /tmp/pi-test-049 && node test-photon-fail.cjs 2>&1OK, it works. Let me check different Node.js versions. The user might be on
continue
The user wants me to continue testing. Let me check if there's a Node.js version issue or something else that could cause photon to fail.
>node --version>cd /tmp/pi-test-049 && cat node_modules/@silvia-odwyer/photon-node/package.json | grep -A5 '"engines"'Let me check the photon-node package more carefully.
>cat /tmp/pi-test-049/node_modules/@silvia-odwyer/photon-node/package.jsonLet me look at how photon loads and if there are any edge cases where it might fail silently.
>head -50 /tmp/pi-test-049/node_modules/@silvia-odwyer/photon-node/photon_rs.jsLet me check the end of the file where the WASM loading happens.
>tail -30 /tmp/pi-test-049/node_modules/@silvia-odwyer/photon-node/photon_rs.jsI see. The photon module loads synchronously using fs.readFileSync(path) at the module level. This should work fine with npm install. If the wasm file is missing, it would throw an error.
Let me think about what the user might be experiencing. Looking at the issue again, the user brunohaid says it's still happening with npm 0.49.0. But my tests show it works fine.
Possible scenarios:
Let me check if there's any difference between global and local installs. Also, let me ask the user to provide more details. But wait, I'm just testing, not responding to the user directly.
Actually, looking at the issue more carefully, the issue was closed. The user was told to use npm instead of bun binary. Then they reported it still happens with npm. But the fix mentioned in the last comment was about loading photon wasm in compiled binaries - which wouldn't affect the npm version.
Let me check if there's a scenario where the npm version could fail. Maybe when running with npx?
Let me test with npx which is how users commonly run it:
>cd /tmp && rm -rf pi-npx-test && mkdir pi-npx-test && cd pi-npx-test && npx @mariozechner/pi-coding-agent@0.49.0 --version 2>&1 | head -5Let me write a script that tests the actual pi CLI flow when reading an image.
>cd /tmp/pi-npx-test && cat > test.js << 'EOF'
// Simulate what happens when pi reads an image via the Read tool
const { createReadTool } = require("@mariozechner/pi-coding-agent/dist/core/tools/read.js");
async function test() {
const readTool = createReadTool(process.cwd(), { autoResizeImages: true });
const result = await readTool.execute("test", { path: "/tmp/large_test.png" });
const img = result.content.find(c => c.type === "image");
if (img) {
const size = Buffer.from(img.data, "base64").length;
console.log(`Image size: ${(size / 1024 / 1024).toFixed(2)} MB`);
console.log(`Under 5MB: ${size < 5 * 1024 * 1024}`);
}
}
test().catch(e => console.error(e));
EOF
node test.js 2>&1The npx run doesn't leave the package installed. Let me use the already installed test directory.
Actually, you know what, my tests confirm that 0.49.0 works correctly. The image gets resized from 23.55MB to 0.66MB. The user might have a different issue or might be mistaken about which version they're running.
Let me summarize my findings for the user.
All my tests confirm 0.49.0 works correctly:
Original image size: 23.55 MBWas resized: trueOriginal dimensions: 4000x4000Final dimensions: 2000x2000Final size: 0.66 MBThe Read tool properly resizes the 24MB PNG to 0.66MB JPEG, well under the 5MB limit.
Possible explanations for the user's issue:
resizeImage() returns the original image unchanged with wasResized: falseLet me check one more thing - how clipboard-pasted images flow through:
>grep -A80 "handleClipboardImagePaste" packages/coding-agent/src/modes/interactive/interactive-mode.ts | grep -A60 "insertTextAtCursor"I see - clipboard paste just inserts a file path into the editor. The user would then need to submit that. But how does the submitted text with a file path get processed?
Let me look for where file paths in the editor text get processed.
>grep -n "processInput\|handleSubmit\|parseInput\|extractFile" packages/coding-agent/src/modes/interactive/interactive-mode.ts | head -15if (!photon) { // Photon not available, return original image return { data: img.data, mimeType: img.mimeType, ... wasResized: false, };}Original image size: 23.55 MBWas resized: trueOriginal dimensions: 4000x4000Final dimensions: 2000x2000Final size: 0.66 MB