mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): ignore Node's own worker messages in image resize
Under `node --watch`, Node 24.19+ and 26.x post `{ "watch:require": [...] }`
on the worker message channel (nodejs/node#65044). The image resize code
treated the first message as the worker's reply, resolved it to `null`, and
dropped the image as "could not be resized below the inline image size limit".
Worker replies now carry a `type` marker, and the main thread ignores any
message without it. The reply type is now either a result or an error.
fixes #10527
This commit is contained in:
parent
7fb59f995b
commit
b30a6dd779
4 changed files with 35 additions and 24 deletions
|
|
@ -23,6 +23,7 @@
|
|||
- Fixed the codemode description not marking `searchTools()`, `describeTool()`, and `describeNamespace()` as async, which led models to serialize the unawaited promise as `{}` ([#10555](https://github.com/earendil-works/pi/issues/10555))
|
||||
- Fixed codemode output items running together, so models could not tell where one `text()` or `console.log()` output ended and the next began. With several text items, each now starts with a `==> text N/M <==` line, and `console` calls follow the other output in one `<console_output>` block with one line per call
|
||||
- Fixed `/mcp` waiting for all servers to connect before opening; the manager now updates live and remains usable while enabling, reconnecting, or disabling servers ([#10562](https://github.com/earendil-works/pi/issues/10562))
|
||||
- Fixed images being dropped as "could not be resized" when running under `node --watch` on Node 24.19+ and 26.x, where Node posts its own messages on the image resize worker channel ([#10527](https://github.com/earendil-works/pi/issues/10527))
|
||||
|
||||
## [1.0.4] - 2026-10-05
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@ export interface ResizedImage {
|
|||
wasResized: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag on image resize worker replies. Node can post its own messages on the worker channel
|
||||
* (for example `{ "watch:require": [...] }` under `node --watch`), so replies must be identifiable.
|
||||
*/
|
||||
export const IMAGE_RESIZE_WORKER_RESPONSE_TYPE = "pi:image-resize-response";
|
||||
|
||||
export type ResizeImageWorkerResponse =
|
||||
| { type: typeof IMAGE_RESIZE_WORKER_RESPONSE_TYPE; result: ResizedImage | null }
|
||||
| { type: typeof IMAGE_RESIZE_WORKER_RESPONSE_TYPE; error: string };
|
||||
|
||||
// 4.5MB of base64 payload. Provides headroom below Anthropic's 5MB limit.
|
||||
const DEFAULT_MAX_BYTES = 4.5 * 1024 * 1024;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { parentPort } from "node:worker_threads";
|
||||
import { type ImageResizeOptions, type ResizedImage, resizeImageInProcess } from "./image-resize-core.ts";
|
||||
import {
|
||||
IMAGE_RESIZE_WORKER_RESPONSE_TYPE,
|
||||
type ImageResizeOptions,
|
||||
type ResizeImageWorkerResponse,
|
||||
resizeImageInProcess,
|
||||
} from "./image-resize-core.ts";
|
||||
|
||||
interface ResizeImageWorkerRequest {
|
||||
inputBytes: Uint8Array;
|
||||
|
|
@ -7,11 +12,6 @@ interface ResizeImageWorkerRequest {
|
|||
options?: ImageResizeOptions;
|
||||
}
|
||||
|
||||
interface ResizeImageWorkerResponse {
|
||||
result?: ResizedImage | null;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
function isResizeImageWorkerRequest(value: unknown): value is ResizeImageWorkerRequest {
|
||||
if (!value || typeof value !== "object") return false;
|
||||
const record = value as Record<string, unknown>;
|
||||
|
|
@ -30,10 +30,11 @@ port.once("message", (message: unknown) => {
|
|||
throw new Error("Invalid image resize worker request");
|
||||
}
|
||||
const result = await resizeImageInProcess(message.inputBytes, message.mimeType, message.options);
|
||||
const response: ResizeImageWorkerResponse = { result };
|
||||
const response: ResizeImageWorkerResponse = { type: IMAGE_RESIZE_WORKER_RESPONSE_TYPE, result };
|
||||
port.postMessage(response);
|
||||
} catch (error) {
|
||||
const response: ResizeImageWorkerResponse = {
|
||||
type: IMAGE_RESIZE_WORKER_RESPONSE_TYPE,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
port.postMessage(response);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Worker } from "node:worker_threads";
|
||||
import { type ImageResizeOptions, type ResizedImage, resizeImageInProcess } from "./image-resize-core.ts";
|
||||
import {
|
||||
IMAGE_RESIZE_WORKER_RESPONSE_TYPE,
|
||||
type ImageResizeOptions,
|
||||
type ResizedImage,
|
||||
type ResizeImageWorkerResponse,
|
||||
resizeImageInProcess,
|
||||
} from "./image-resize-core.ts";
|
||||
|
||||
export type { ImageResizeOptions, ResizedImage } from "./image-resize-core.ts";
|
||||
|
||||
interface ResizeImageWorkerResponse {
|
||||
result?: ResizedImage | null;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
function toTransferableBytes(input: Uint8Array): Uint8Array<ArrayBuffer> {
|
||||
// Transfer detaches the buffer, so transfer a worker-owned copy and leave the
|
||||
// caller's bytes intact.
|
||||
|
|
@ -15,7 +16,9 @@ function toTransferableBytes(input: Uint8Array): Uint8Array<ArrayBuffer> {
|
|||
}
|
||||
|
||||
function isResizeImageWorkerResponse(value: unknown): value is ResizeImageWorkerResponse {
|
||||
return value !== null && typeof value === "object";
|
||||
return (
|
||||
value !== null && typeof value === "object" && "type" in value && value.type === IMAGE_RESIZE_WORKER_RESPONSE_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
function createResizeWorker(workerSpecifier: string | URL): Worker {
|
||||
|
|
@ -44,16 +47,12 @@ async function resizeImageInWorker(
|
|||
reject(error);
|
||||
};
|
||||
|
||||
worker.once("message", (message: unknown) => {
|
||||
if (!isResizeImageWorkerResponse(message)) {
|
||||
fail(new Error("Invalid image resize worker response"));
|
||||
return;
|
||||
}
|
||||
if (message.error) {
|
||||
fail(new Error(message.error));
|
||||
return;
|
||||
}
|
||||
settle(message.result ?? null);
|
||||
worker.on("message", (message: unknown) => {
|
||||
// Ignore messages Node posts on the worker channel itself, such as
|
||||
// `{ "watch:require": [...] }` under `node --watch` (nodejs/node#65044).
|
||||
if (!isResizeImageWorkerResponse(message)) return;
|
||||
if ("error" in message) fail(new Error(message.error));
|
||||
else settle(message.result);
|
||||
});
|
||||
worker.once("error", fail);
|
||||
worker.once("exit", (code) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue