fix: pdf_read가 /api/files/ 채팅링크를 경로로 착각해 실패하던 문제

모델이 업로드 링크 URL을 그대로 path로 넘기면 path.isAbsolute()가
true로 판정돼 워크스페이스 상대경로 변환을 안 타고 "path escapes
workspace"로 실패했음. 도구 설명에 부정 예시 명시 + execute()에서
/api/files/ 접두사 자동 제거로 이중 보강.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUjjAwB2Cmjf4YFRZpobec
This commit is contained in:
kim
2026-08-25 11:16:53 +09:00
co-authored by Claude Sonnet 5
parent 7ac143652a
commit c67a23f739
2 changed files with 4 additions and 3 deletions
+1 -1
View File
@@ -1054,7 +1054,7 @@ export function createBuildTools(isOrchestrationSkillEnabled: () => boolean) {
parameters: {
type: 'object', required: ['path'],
properties: {
path: { type: 'string', description: 'Path to the PDF file (relative to workspace or absolute)' },
path: { type: 'string', description: 'Workspace-relative path to the PDF file, e.g. "uploads/파일명.pdf". Do NOT pass the /api/files/... URL shown in chat links — strip that prefix and use the part after "uploads/".' },
page_from: { type: 'number', description: 'First page (1-indexed)' },
page_to: { type: 'number', description: 'Last page (inclusive)' },
max_chars: { type: 'number', description: 'Max chars to return (default: 20000)' },
+3 -2
View File
@@ -292,7 +292,7 @@ export const pdfReadTool = {
name: 'pdf_read',
description: 'Extract text from a PDF file. Returns markdown-formatted text: headings (##/###), bold (**), indentation, and bullet lists. Multi-column academic PDFs are handled correctly. Complex tables are skipped (use pdf_extract_images for table figures). For scanned/image PDFs falls back to Tesseract OCR.',
schema: {
path: 'Path to the PDF file (absolute, or relative to workspace)',
path: 'Workspace-relative path to the PDF file (e.g. "uploads/파일명.pdf"), not the /api/files/... chat link',
page_from: 'First page to extract, 1-indexed (default: 1)',
page_to: 'Last page to extract, inclusive (default: last page)',
max_chars: 'Maximum characters to return (default: 20000, max: 100000)',
@@ -311,8 +311,9 @@ export const pdfReadTool = {
additionalProperties: false,
},
execute: async (args: any): Promise<ToolResult> => {
const filePath = String(args?.path || '').trim();
let filePath = String(args?.path || '').trim();
if (!filePath) return { success: false, error: 'path is required' };
filePath = filePath.replace(/^\/api\/files\//, '');
const workspacePath = getWorkspacePath(args);
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(workspacePath, filePath);