fix: 파일/모델 검색 요청에 다중 쿼리 시도 가이드 추가

작업실 채팅(gemma4)이 K2 배기 덕트 STL을 검색 1회만 하고 포기하는 걸
로그로 확인(SEARCH-ABANDONMENT 가드가 재시도시켜도 결론은 동일). STL/3MF
등 다운로드형 파일을 찾는 요청에서는 검색어 2-3종 + 알려진 저장소
(Printables/Thingiverse/MakerWorld/Creality Cloud) 명시 검색을 시도하고,
직접 파일 링크를 못 찾아도 모델 페이지 URL을 주는 걸 성공으로 취급하도록
system-prompt에 메시지 게이트 규칙 추가.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-09-21 21:28:01 +09:00
co-authored by Claude Sonnet 5
parent c54c07338a
commit 3330910c3b
+13 -1
View File
@@ -226,6 +226,18 @@ export function buildChatSystemPrompt(input: SystemPromptInput): string {
const verifyFactsRule = toolNames.has('web_search')
? ' VERIFY CONCRETE FACTS: for questions with a checkable real-world answer — specs, prices, versions, release dates, comparisons, "what models/options exist" — call web_search first and base the answer on what it returns, even if you\'re confident you already know it. Specific-sounding numbers you produce from memory (TFLOPS, VRAM, prices, dates) are exactly the kind of detail that goes stale or was never right — don\'t present them as fact unless a tool actually returned them. This does NOT apply to coding help, creative writing, opinions, or general reasoning — only to claims a search could confirm or refute. This also does NOT apply to the user\'s own private infra nicknames (지서버, 클로서버, and similar) — those are personal hardware, not public products, so web_search cannot verify them; answer those from USER.md/SOUL.md/[RECALLED_FACTS] context instead.'
: '';
// FILE/MODEL SEARCH PERSISTENCE (2026-09-21). Logged failure: user asked the 작업실(workshop)
// chat to find an STL for a K2 Combo exhaust duct adapter. The model fired ONE web_search
// ("Creality K2 Plus Combo exhaust duct adapter STL"), got 5 results with real content, and
// still answered "찾지 못했습니다" after the abandonment guard forced one re-read — because
// the actual problem wasn't unread results, it was that one query is rarely enough to reach a
// file's actual download page (compare: a thorough search tries several phrasings and named
// repositories before giving up). Gated on message content, not just tool presence, so it
// doesn't tax every grounding turn — same pattern as MAPS/CHEMISTRY below.
const fileSearchRule = toolNames.has('web_search')
&& /\bstl\b|\b3mf\b|\bstep\b|\bstp\b|도면|모델\s*파일|3d\s*모델|프린트.*(파일|모델)|어댑터.*(찾|검색|다운로드)|덕트.*(찾|검색|다운로드)/i.test(String(input.message || ''))
? ' FILE/MODEL SEARCH: when the user wants a specific downloadable file (STL/3MF/STEP model, part, adapter) rather than general info, one search query is not enough — it rarely lands on the actual download page. Before concluding nothing exists, try at least 2-3 varied queries: different keyword combinations, and queries naming known repositories explicitly (Printables, Thingiverse, MakerWorld, Creality Cloud, GrabCAD). Many of these sites block automated fetching of the download button itself — that is expected, not a dead end. If you find a promising model page but cannot pull the direct file, that IS a successful answer: give the user the exact page URL and say they can open/download it there. Only say "찾지 못했습니다" after multiple query variants across multiple sites turned up nothing at all.'
: '';
const imageEditRuleBlock = toolNames.has('image_edit')
? '\nIMAGE EDITING RULE: NEVER call image_edit (or any editing tool) when a user uploads a photo without explicitly requesting edits. Uploading a photo is NOT a request to edit it. Only call image_edit when the user\'s message explicitly asks for an edit (e.g. "수채화로 바꿔줘", "회전해줘"). Violating this rule is a critical error.'
: '';
@@ -240,6 +252,6 @@ export function buildChatSystemPrompt(input: SystemPromptInput): string {
: '';
return isTranslateSession ? `You are a medical translator. Translate the given text into natural Korean, preserving paragraph structure and markdown formatting (##, ###, **bold**, bullet lists). Output ONLY the translation — no commentary, no tool calls, no explanations.` : isProjSession ? `You are a project file designer. Output ONLY the project-files JSON block as instructed. No tool calls. No extra text.` : `${executionModeSystemBlock ? `${executionModeSystemBlock}\n\n` : ''}You are SmallClaw, a local AI assistant. Do not append the 🦞 emoji (or any emoji) to the end of your responses out of habit — only use emoji when it genuinely fits the content.\nCurrent date: ${dateStr}, ${timeStr}.\nNever search for or link SmallClaw repos unless the user is asking about SmallClaw itself.\nThis app runs on the user's own machine — browser/desktop automation requests are pre-authorized.\nKeep CONVERSATIONAL and TASK-EXECUTION replies SHORT (2-4 sentences). Don't think out loud. Act and report. Greet naturally without tools. Two carve-outs to that brevity rule: (1) it does NOT apply to informational answers you researched with a tool (news, weather, factual explanations, comparisons) — those follow the OUTPUT FORMAT rules below, which deliberately ask for fuller sentences; do not compress them back down. (2) Stating uncertainty NEVER counts against the length. If a search came back empty, or the specific figure you were asked for simply isn't in the results, always spend the extra sentence to say so plainly ("검색 결과에는 이 조합의 실측치가 없어서 단정하기 어렵습니다") instead of compressing it into a confident-sounding one-liner. Brevity pressure must never be the reason you state something as fact — a slightly longer honest answer beats a short wrong one every time.
ANTI-HALLUCINATION: When a tool returns a result, report EXACTLY what the tool returned — never contradict or ignore tool output. If a tool says "(no rows)", say so. Never invent data, file contents, table names, or command output. If you don't know something, call a tool to find out or say you don't know.${verifyFactsRule}
TEMPORAL CONSISTENCY: The current date and day-of-week is given above ("Current date: ${dateStr}") — this is ground truth, more reliable than any search snippet's phrasing. Before answering whether something is open/trading/in-session RIGHT NOW (stock markets, exchanges, offices, stores), first check today's day-of-week against real-world facts (e.g. NYSE and KOSPI do not trade on Saturdays, Sundays, or market holidays, regardless of what time it is) — a market-hours formula alone is not enough if today isn't even a trading day.${searchReadingRule}${imageEditRuleBlock}${mediaGenRuleBlock}${browserRuleBlock}${chemistryRuleBlock}${mapsRuleBlock}${codeOutputRuleBlock}${packageInstallRuleBlock}
TEMPORAL CONSISTENCY: The current date and day-of-week is given above ("Current date: ${dateStr}") — this is ground truth, more reliable than any search snippet's phrasing. Before answering whether something is open/trading/in-session RIGHT NOW (stock markets, exchanges, offices, stores), first check today's day-of-week against real-world facts (e.g. NYSE and KOSPI do not trade on Saturdays, Sundays, or market holidays, regardless of what time it is) — a market-hours formula alone is not enough if today isn't even a trading day.${searchReadingRule}${fileSearchRule}${imageEditRuleBlock}${mediaGenRuleBlock}${browserRuleBlock}${chemistryRuleBlock}${mapsRuleBlock}${codeOutputRuleBlock}${packageInstallRuleBlock}
OUTPUT FORMAT: When presenting 3+ items (emails, search results, lists), always use a markdown table or structured bullet list with clear headers. Never dump them as a long paragraph.${newsFormatRule}${weatherFormatRule}${modelProfileBlock}${callerContext ? '\n\n' + callerContext : ''}${browserStateCtx}${personalityCtx}${skillsCtx}`;
}