feat: v2.2.83 → v2.2.91 — info prompt 강화 + 사용자 노출 설정 + 답변 포맷 정리

[v2.2.83] /youtube info 프롬프트 강화
- 비유 방향 보존 룰 (Hugging Face=자료실 같은 짝 뒤집기 방지)
- 신뢰도 라벨 4종 ([근거 명시] / [화자 주장] / [가정] / [정리자 추론])
- 타임스탬프 fail 룰 (인용·구간 요약 모두 mm:ss 필수)
- "정리자 노트" 별도 섹션으로 추론 격리

[v2.2.85] polishPersona self-check 5가지
- 정리·리뷰·요약 답변 출력 직전 머릿속 체크:
  (1) 사실 오류  (2) 없는 내용 추가  (3) 뉘앙스 유지
  (4) 중요도 비례  (5) 중복 제거

[v2.2.86] chunkedSwitchTokens 절대 임계값 게이트
- 입력 < 50k 토큰이면 키워드·길이 트리거 무시하고 단일 호출
- 큰 컨텍스트 모델(131k+)에서 chunked 과잉 발동 방지

[v2.2.87] MAX_SECTIONS 5→3 cap
- 총 호출 7회 → 5회 (outline + 3 section + polish)
- 사용자 피드백 "6+회는 과하다"

[v2.2.88] 이모지 사용 금지 룰
- polishPersona / directPersona / sectionPersona 모두 적용
- 사용자 피드백 "이모지는 시각 노이즈"

[v2.2.89] 사용자 노출 설정 두 항목
- chunkedMaxSections config 신규 (default 3, 1~10 clamp)
- MAX_SECTIONS_HARD_CEILING (10) 으로 안전망 격상
- Astra Settings 패널 "고급" 섹션에 두 슬라이더 노출

[v2.2.90] 가이드 문구 단순화
- "작은 모델은 낮추라" 문구 빼고 일관되게 50000 권장으로

[v2.2.91] 답변 포맷 가독성 fix
- persona 의 "TL;DR" 표현 전부 "한 줄 요약" 으로 단일화
- stripMarkdownFormatting 에 헤더 후 빈 줄 강제 삽입
  (marked.parse 가 라벨·본문을 별도 단락으로 인식 → 시각 분리)

[테스트] 400/400 통과 (resilience_stress + chunked flow + MAX_SECTIONS cap 등)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
g1nation
2026-05-24 14:12:56 +09:00
parent ded3eea7ce
commit 4153f640c2
22 changed files with 425 additions and 204 deletions
+12 -4
View File
@@ -250,11 +250,15 @@ describe('AgentEngine — chunked flow', () => {
expect(roles.filter(r => r === 'section')).toHaveLength(3);
});
test('outline MAX_SECTIONS 초과 응답은 5개로 cap 된다', async () => {
// 7개를 줘도 5개로 잘려야 함
test('outline 가 config 의 chunkedMaxSections 보다 많이 반환해도 그 값으로 cap', async () => {
// 사용자 config 의 chunkedMaxSections (default 3) 가 실제 상한.
// outline LLM 이 더 많이 반환해도 parseOutline 에서 cap.
const { getConfig } = require('../src/config') as typeof import('../src/config');
const expectedCap = getConfig().chunkedMaxSections;
const overshoot = expectedCap + 4;
const writer = new MockChunkedWriter(
JSON.stringify(
Array.from({ length: 7 }, (_, i) => ({ heading: `H${i}`, scope: `s${i}` }))
Array.from({ length: overshoot }, (_, i) => ({ heading: `H${i}`, scope: `s${i}` }))
)
);
const engine = new AgentEngine(writer);
@@ -262,7 +266,11 @@ describe('AgentEngine — chunked flow', () => {
'chunked_cap', CHUNKED_PROMPT, 'ctx', createAbortSignal(), noopProgress,
);
const sectionCount = writer.calls.filter(c => c.role === 'section').length;
expect(sectionCount).toBe(AgentEngine.MAX_SECTIONS);
expect(sectionCount).toBe(expectedCap);
});
test('Hard ceiling (10) 은 config 한도 위 보호 안전망 — 절대 초과 금지', () => {
expect(AgentEngine.MAX_SECTIONS_HARD_CEILING).toBe(10);
});
test('outline JSON 파싱 실패 시 단일 "본문" 섹션으로 폴백', async () => {