From 88662663b14ba63be15a1765ff7fc574ef3e7d9b Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 22 Sep 2026 15:45:19 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=9E=91=EC=97=85=EC=8B=A4=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=EC=97=90=20=ED=98=84=EC=9E=AC=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EC=A0=9D=ED=8A=B8=20=EC=BB=A8=ED=85=8D=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ws_ 세션(작업실 앱 전용 채팅)이 "지금 어떤 프로젝트를 보고 있는지" 정보를 시스템 프롬프트에 전혀 못 받고 있었음 — tool-scope.ts의 isWorkshopAppSession은 "작업실 세션이다"만 판별하지 활성 프로젝트 ID는 안 넘김. 그 결과 모델이 STL/scad 파일을 찾을 때 워크스페이스 전체를 뒤져서 다른 프로젝트 파일까지 후보로 내놓는 혼동이 있었음(예: proj_scan_dental_diy 채팅에서 STL 요청했는데 proj_scan_dental 쪽 scad까지 같이 나열). workshop.json의 activeProjectId를 읽어 "지금 프로젝트는 이거고 파일은 workshop// 아래만 볼 것"을 callerContext에 주입하도록 수정. 실제 ws_ 세션으로 테스트해 크로스 프로젝트 혼동 없어진 것 확인. Co-Authored-By: Claude Code --- src/gateway/chat/handle-chat.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/gateway/chat/handle-chat.ts b/src/gateway/chat/handle-chat.ts index 2a44e85..cd649b6 100644 --- a/src/gateway/chat/handle-chat.ts +++ b/src/gateway/chat/handle-chat.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import path from 'path'; import { getConfig, getUserWorkspace } from '../../config/config'; +import { loadWorkshop } from '../routes/workshop-storage'; import { getModelForRole } from '../../providers/factory'; import { getOllamaClient } from '../../agents/ollama-client'; import { getSession, addMessage, getHistoryForApiCall, getWorkspace, setWorkspace } from '../session'; @@ -245,6 +246,27 @@ async function handleChat( const isCodeAiSession = String(sessionId || '').startsWith('code_ai_'); const isTranslateSession = String(sessionId || '').startsWith('translate-'); const isProjSession = String(sessionId || '').startsWith('proj-'); + // 작업실 앱(workshop-app.html) 전용 채팅 패널 세션('ws_' 접두어) — tool-scope.ts의 + // isWorkshopAppSession과 같은 판별이지만 여기선 "지금 보고 있는 프로젝트가 뭔지"를 시스템 + // 프롬프트에 심어주는 데 쓴다. 이게 없으면 모델이 워크스페이스 전체를 뒤져서 다른 프로젝트 + // 파일(예: proj_scan_dental)까지 후보로 내놓는 혼동이 생긴다(2026-09-22 사용자 지적 — DIY + // 스캐너 프로젝트 채팅에서 STL 만들어달라 했는데 임상급 프로젝트 scad까지 같이 나열함). + const isWorkshopAppSession = /^ws_/.test(String(sessionId || '')); + const workshopProjectCtx = (() => { + if (!isWorkshopAppSession || !workspacePath) return ''; + try { + const wd = loadWorkshop(workspacePath); + const proj = wd.projects.find(p => p.id === wd.activeProjectId); + if (!proj) return ''; + return `[작업실(workshop) 세션 — 지금 사용자가 보고 있는 프로젝트: "${proj.name}" (id: ${proj.id}). ` + + `이 프로젝트의 파일(STL/scad/사진 등)은 워크스페이스 기준 workshop/${proj.id}/ 아래에만 있다. ` + + `파일을 찾거나 만들 때 이 프로젝트 폴더만 보고, 다른 프로젝트 폴더(workshop/<다른id>/)는 ` + + `사용자가 명시적으로 그 프로젝트를 언급하지 않는 한 후보로 내놓지 말 것.]`; + } catch { return ''; } + })(); + const callerContextWithWorkshop = workshopProjectCtx + ? `${callerContext || ''}${callerContext ? '\n\n' : ''}${workshopProjectCtx}` + : callerContext; // 도구 선택 로직은 tool-scope.ts로 분리됨(2026-07-29) — handleChat 안의 클로저라 테스트가 // 불가능했고, 게이트 하나가 조용히 어긋나도 아무 에러 없이 프롬프트만 뚱뚱해지던 구간. const tools = selectToolsForTurn(buildTools(), @@ -708,7 +730,7 @@ async function handleChat( isTranslateSession, isProjSession, modelProfileBlock: getModelProfileExtraPrompt(getModelForRole('executor')), - callerContext, + callerContext: callerContextWithWorkshop, browserStateCtx, personalityCtx, skillsCtx: skillsManager.buildPromptContextForUser(username ? getUserWorkspace(username) : null, 16000, message),