fix: 스킬 컨텍스트가 direct 호출에서 버려지고 8000자에서 잘리던 문제

스킬 프롬프트 전면 점검 중 발견한 버그 2건.

1) callerContext가 'no_preflight' 제어 센티널·BOOT.md 마커·호출자 스킬 텍스트를
   한 필드에 섞어 쓰면서 삼항으로 골랐다 → direct:true와 skillContext를 같이 보내면
   스킬이 조용히 버려짐. pptx-wizard.js의 아웃라인 경로(line 798)가 정확히 그 조합이라
   프레젠터 스킬이 한 번도 전달되지 않았다. 둘 다 싣도록 변경.

2) 캡이 8,000자인데 위저드가 보내는 프레젠터 스킬은 9,861자 → 매 호출 뒤 1,861자 손실.
   잘려나간 것이 [필수] source_files 규칙과 **금지 사항 블록 전체**(파이썬으로 PPTX 직접
   생성 금지, 1회 호출 원칙, 수정은 edit_presentation, spawn_agent 금지)였다. 스킬에서
   가장 값어치 있는 제약들이 모델에 도달한 적이 없다. 캡 12,000으로 올리고 초과 시 경고 로그.

검증: direct 유무 양쪽 경로에서 금지사항·source_files 포함 확인.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XZX9JHFSLZRuK9rR4sCVBs
This commit is contained in:
kim
2026-09-02 15:02:13 +09:00
co-authored by Claude Sonnet 5
parent 99d3d387bc
commit 797de9b03f
+19 -1
View File
@@ -3209,7 +3209,25 @@ app.post('/api/chat', async (req, res) => {
? `${user?.username || 'anon'}@aicoder${_codeAiModelShort ? '-' + _codeAiModelShort : ''}`
: (user?.username ? `${user.username}@${sessionSuffix}` : `(anon)@${sessionSuffix}`);
console.log(`\n[v2] USER [${userTag}]: ${message}`);
const callerCtx = direct ? 'no_preflight' : (skillContext ? String(skillContext).slice(0, 8000) : undefined);
// callerContext carries three unrelated things — the 'no_preflight' control sentinel
// (handle-chat reads it back as isDirectCall), a BOOT.md marker, and the caller-supplied
// skill text. It used to be a ternary, so a request sending BOTH direct:true and
// skillContext silently dropped the skill — which is exactly what pptx-wizard.js does on
// its outline path. Carry both (2026-09-02).
//
// The cap was 8,000 while the presenter skill the wizard sends is 9,861 chars, so every
// call lost the last 1,861 — the [필수] source_files rule and the entire 금지 사항 block
// (never hand-write PPTX python, one call only, edit_presentation for edits, no spawn_agent).
// Those are the highest-value constraints in the skill and they never reached the model.
const SKILL_CTX_MAX = 12000;
const _skillCtx = skillContext ? String(skillContext) : '';
if (_skillCtx.length > SKILL_CTX_MAX) {
console.warn(`[v2] skillContext truncated: ${_skillCtx.length} → ${SKILL_CTX_MAX} chars (tail rules lost)`);
}
const callerCtx = [
direct ? 'no_preflight' : '',
_skillCtx.slice(0, SKILL_CTX_MAX),
].filter(Boolean).join('\n\n') || undefined;
const isCodeEditorSession = /^(code_ai_|proj-plan-|proj-gen-)/.test(String(sessionId));
const histOverride = (isCodeEditorSession && Array.isArray(clientHistory)) ? clientHistory : undefined;
// Code editor chat runs on its own clean tool loop — no multi-agent orchestration.