fix: stl_cad/scad_to_stl/write_scad를 작업실 세션 전용으로 제한

사용자 요청 "작업실 전용으로 하자" — 지금까지 이 셋은 키워드 게이트
(hasStlCadKeyword)라 메인 채팅이든 다른 앱이든 메시지에 "stl"/"cad" 등만
있으면 어디서든 호출 가능했음. isWorkshopAppSession(ws_ 세션) 게이트로
교체 — 이제 워크숍 세션에서만 뜨고, 메인 채팅에선 같은 키워드를 써도 안 뜸.
k2-app.html의 "🔧 STL 확인" 웹 UI 패널은 routes-cad.ts 직접 호출이라 이
게이트와 무관, 영향 없음.

더는 안 쓰는 hasStlCadKeyword/stlCadPattern 정리. lastAssistantMsg 필드는
남겨둠(다른 재시도-유지 게이트가 필요해지면 재사용 가능, 비용 없음).

실측: 메인채팅 세션은 "scad를 stl로" 요청해도 세 도구 다 false, 워크숍
세션은 키워드 없는 "안녕"에도 세 도구 다 true 확인.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
kim
2026-09-22 17:21:22 +09:00
co-authored by Claude Code
parent bb6a64bff4
commit 703ea0f671
+12 -12
View File
@@ -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;