fix: defer pdf deps and profile flag detection
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { normalizeProfileName } from "./profile-utils.js";
|
import { normalizeProfileName } from "./profile-utils.js";
|
||||||
|
|
||||||
const CLI_PREFIX_RE = /^(?:pnpm|npm|bunx|npx)\s+clawdbot\b|^clawdbot\b/;
|
const CLI_PREFIX_RE = /^(?:pnpm|npm|bunx|npx)\s+clawdbot\b|^clawdbot\b/;
|
||||||
const PROFILE_FLAG_RE = /\b--profile\b/;
|
const PROFILE_FLAG_RE = /(^|\s)--profile(\s|$)/;
|
||||||
const DEV_FLAG_RE = /\b--dev\b/;
|
const DEV_FLAG_RE = /(^|\s)--dev(\s|$)/;
|
||||||
|
|
||||||
export function formatCliCommand(
|
export function formatCliCommand(
|
||||||
command: string,
|
command: string,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { lookup } from "node:dns/promises";
|
import { lookup } from "node:dns/promises";
|
||||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||||
|
|
||||||
import { createCanvas } from "@napi-rs/canvas";
|
|
||||||
import { buildHistoryContextFromEntries, type HistoryEntry } from "../auto-reply/reply/history.js";
|
import { buildHistoryContextFromEntries, type HistoryEntry } from "../auto-reply/reply/history.js";
|
||||||
import { createDefaultDeps } from "../cli/deps.js";
|
import { createDefaultDeps } from "../cli/deps.js";
|
||||||
import { agentCommand } from "../commands/agent.js";
|
import { agentCommand } from "../commands/agent.js";
|
||||||
@@ -32,7 +31,6 @@ import {
|
|||||||
import type { GatewayHttpResponsesConfig } from "../config/types.gateway.js";
|
import type { GatewayHttpResponsesConfig } from "../config/types.gateway.js";
|
||||||
import type { ClientToolDefinition } from "../agents/pi-embedded-runner/run/params.js";
|
import type { ClientToolDefinition } from "../agents/pi-embedded-runner/run/params.js";
|
||||||
import type { ImageContent } from "../commands/agent/types.js";
|
import type { ImageContent } from "../commands/agent/types.js";
|
||||||
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
||||||
|
|
||||||
type OpenResponsesHttpOptions = {
|
type OpenResponsesHttpOptions = {
|
||||||
auth: ResolvedGatewayAuth;
|
auth: ResolvedGatewayAuth;
|
||||||
@@ -40,6 +38,25 @@ type OpenResponsesHttpOptions = {
|
|||||||
config?: GatewayHttpResponsesConfig;
|
config?: GatewayHttpResponsesConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type CanvasModule = typeof import("@napi-rs/canvas");
|
||||||
|
type PdfJsModule = typeof import("pdfjs-dist/legacy/build/pdf.mjs");
|
||||||
|
|
||||||
|
async function loadCanvasModule(): Promise<CanvasModule | null> {
|
||||||
|
try {
|
||||||
|
return await import("@napi-rs/canvas");
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPdfJsModule(): Promise<PdfJsModule | null> {
|
||||||
|
try {
|
||||||
|
return await import("pdfjs-dist/legacy/build/pdf.mjs");
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function sendJson(res: ServerResponse, status: number, body: unknown) {
|
function sendJson(res: ServerResponse, status: number, body: unknown) {
|
||||||
res.statusCode = status;
|
res.statusCode = status;
|
||||||
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||||
@@ -305,9 +322,12 @@ async function extractPdfContent(params: {
|
|||||||
limits: ResolvedResponsesLimits;
|
limits: ResolvedResponsesLimits;
|
||||||
}): Promise<{ text: string; images: ImageContent[] }> {
|
}): Promise<{ text: string; images: ImageContent[] }> {
|
||||||
const { buffer, limits } = params;
|
const { buffer, limits } = params;
|
||||||
const pdf = await getDocument({
|
const pdfjs = await loadPdfJsModule();
|
||||||
|
if (!pdfjs) {
|
||||||
|
throw new Error("PDF parsing requires pdfjs-dist; install it to enable PDF support.");
|
||||||
|
}
|
||||||
|
const pdf = await pdfjs.getDocument({
|
||||||
data: new Uint8Array(buffer),
|
data: new Uint8Array(buffer),
|
||||||
// @ts-expect-error pdfjs-dist legacy option not in current type defs.
|
|
||||||
disableWorker: true,
|
disableWorker: true,
|
||||||
}).promise;
|
}).promise;
|
||||||
const maxPages = Math.min(pdf.numPages, limits.files.pdf.maxPages);
|
const maxPages = Math.min(pdf.numPages, limits.files.pdf.maxPages);
|
||||||
@@ -329,6 +349,10 @@ async function extractPdfContent(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const images: ImageContent[] = [];
|
const images: ImageContent[] = [];
|
||||||
|
const canvasModule = await loadCanvasModule();
|
||||||
|
if (!canvasModule) {
|
||||||
|
throw new Error("PDF image extraction requires @napi-rs/canvas; install it to enable images.");
|
||||||
|
}
|
||||||
for (let pageNum = 1; pageNum <= maxPages; pageNum += 1) {
|
for (let pageNum = 1; pageNum <= maxPages; pageNum += 1) {
|
||||||
const page = await pdf.getPage(pageNum);
|
const page = await pdf.getPage(pageNum);
|
||||||
const viewport = page.getViewport({ scale: 1 });
|
const viewport = page.getViewport({ scale: 1 });
|
||||||
@@ -337,7 +361,7 @@ async function extractPdfContent(params: {
|
|||||||
const pagePixels = viewport.width * viewport.height;
|
const pagePixels = viewport.width * viewport.height;
|
||||||
const scale = Math.min(1, Math.sqrt(pixelBudget / pagePixels));
|
const scale = Math.min(1, Math.sqrt(pixelBudget / pagePixels));
|
||||||
const scaled = page.getViewport({ scale: Math.max(0.1, scale) });
|
const scaled = page.getViewport({ scale: Math.max(0.1, scale) });
|
||||||
const canvas = createCanvas(Math.ceil(scaled.width), Math.ceil(scaled.height));
|
const canvas = canvasModule.createCanvas(Math.ceil(scaled.width), Math.ceil(scaled.height));
|
||||||
await page.render({
|
await page.render({
|
||||||
canvas: canvas as unknown as HTMLCanvasElement,
|
canvas: canvas as unknown as HTMLCanvasElement,
|
||||||
viewport: scaled,
|
viewport: scaled,
|
||||||
|
|||||||
7
src/types/napi-rs-canvas.d.ts
vendored
Normal file
7
src/types/napi-rs-canvas.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
declare module "@napi-rs/canvas" {
|
||||||
|
export type Canvas = {
|
||||||
|
toBuffer(type?: string): Buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createCanvas(width: number, height: number): Canvas;
|
||||||
|
}
|
||||||
34
src/types/pdfjs-dist-legacy.d.ts
vendored
Normal file
34
src/types/pdfjs-dist-legacy.d.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
declare module "pdfjs-dist/legacy/build/pdf.mjs" {
|
||||||
|
export type TextItem = {
|
||||||
|
str: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TextMarkedContent = {
|
||||||
|
type?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TextContent = {
|
||||||
|
items: Array<TextItem | TextMarkedContent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Viewport = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PDFPageProxy = {
|
||||||
|
getTextContent(): Promise<TextContent>;
|
||||||
|
getViewport(params: { scale: number }): Viewport;
|
||||||
|
render(params: { canvas: unknown; viewport: Viewport }): { promise: Promise<void> };
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PDFDocumentProxy = {
|
||||||
|
numPages: number;
|
||||||
|
getPage(pageNumber: number): Promise<PDFPageProxy>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getDocument(params: {
|
||||||
|
data: Uint8Array;
|
||||||
|
disableWorker?: boolean;
|
||||||
|
}): { promise: Promise<PDFDocumentProxy> };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user