diff --git a/src/gateway/chat/tool-scope.ts b/src/gateway/chat/tool-scope.ts index a7efef6..8aedaca 100644 --- a/src/gateway/chat/tool-scope.ts +++ b/src/gateway/chat/tool-scope.ts @@ -39,12 +39,11 @@ export interface ToolScopeInput { */ recentUserText?: string; /** - * The assistant's own previous reply, truncated. Used ONLY by hasStlCadKeyword (2026-09-22): - * a short retry like "다시 시도해봐" carries none of the stl/cad/scad keywords itself, and if - * the original request has already scrolled out of recentUserText's 2-turn window, the tool - * silently vanishes mid-task (실측 — 워크숍 채팅에서 "scad_to_stl 도구를 쓰라고 안내는 받았는데 - * 실제 목록엔 없다"고 보고). The assistant's last turn is a strong same-topic signal here since - * our own tool descriptions inject the tool name into it. + * The assistant's own previous reply, truncated. Added 2026-09-22 for a stl_cad-family retry + * gap (a short "다시 시도해봐" carrying none of the trigger keywords could make a tool vanish + * mid-task once the original request scrolled out of recentUserText's 2-turn window) — that + * specific gate has since moved to isWorkshopAppSession, but this field is kept wired through + * from handle-chat.ts (cheap, already computed) for any future gate that wants the same signal. */ lastAssistantMsg?: string; /** Session id; the wt_/lw_/ac_ prefixes select app-specific tool sets. */ @@ -187,11 +186,8 @@ export function buildSkillToolFilter(input: ToolScopeInput): (toolName: string) // print3d_model — STL 슬라이싱+K2 프린터 업로드. topicText로 검사(prepare→start 확인 // 왕복이 여러 턴 걸치므로 nvr_snapshot과 같은 이유로 최근 대화 전체를 봄). const hasPrint3dKeyword = /3d\s*프린트|3d\s*print|stl|슬라이싱|슬라이서|g-?code|출력해|프린터로|k2\s*(?:콤보|프린터)?/i.test(topicText); - // stl_cad/scad_to_stl — STL 확인/렌더링/구멍뚫기/scad 컴파일(OpenSCAD). print3d와 겹치는 - // "stl" 외에 CAD 편집 관련 어휘도 추가로 매칭. 직전 어시스턴트 답변도 같이 봄(위 - // lastAssistantMsg 주석 참고) — 짧은 "다시 시도해봐" 재시도에 도구가 사라지는 걸 막는다. - const stlCadPattern = /stl|cad|캐드|구멍\s*뚫|렌더링|바운딩박스|openscad|치수\s*확인/i; - const hasStlCadKeyword = stlCadPattern.test(topicText) || stlCadPattern.test(String(input.lastAssistantMsg || '').slice(-800)); + // stl_cad/scad_to_stl/write_scad — 09-22부터 키워드 게이트 대신 isWorkshopAppSession으로 + // 직접 게이트(사용자 요청: "작업실 전용으로 하자"). 아래쪽 게이트 라인 참고. // workshop_project — "작업실"(여러 메이커 프로젝트) 대시보드 부품/작업 편집. "로봇" 단독은 // 로봇청소기(Valetudo) 대화와 겹치므로 프로젝트 고유 어휘로만 매칭한다. 새 프로젝트 종류가 // 늘어날 때마다 이 목록도 넓혀줘야 함(앱 세션 안에서는 아래 isWorkshopAppSession이 대신 @@ -392,7 +388,11 @@ export function buildSkillToolFilter(input: ToolScopeInput): (toolName: string) if ((name === 'eonet_events' || name === 'satellite_snapshot') && !hasSatelliteKeyword) return false; if (name === 'nvr_snapshot' && !hasCctvKeyword) return false; if (name === 'print3d_model' && !hasPrint3dKeyword) return false; - if ((name === 'stl_cad' || name === 'scad_to_stl' || name === 'write_scad') && !hasStlCadKeyword) return false; + // 09-22: 사용자 요청 "작업실 전용으로 하자" — 이 셋 다 워크숍 세션(ws_)에서만 노출. + // 원래 stl_cad는 키워드만 맞으면 메인 채팅/다른 앱에서도 쓰였는데(k2-app.html 웹 UI + // 패널과는 별개 경로라 안 건드려도 됨 — routes-cad.ts 직접 호출, 이 게이트 무관), + // 이제 워크숍 밖에선 안 뜬다. + if ((name === 'stl_cad' || name === 'scad_to_stl' || name === 'write_scad') && !isWorkshopAppSession) return false; if (name === 'workshop_project' && !isWorkshopAppSession && !hasWorkshopKeyword) return false; if (name === 'run_command' && !hasRunCommandKeyword) return false; return true;