feat: v2.2.92 → v2.2.158 — god-file 분해 + Stocks feature + 대화 연속성
R56–R59: agent.ts 2731→1529줄 god-file 분해 (25 modules) · attrParsers + LLM 메서드 8개 (callNonStreaming, streamChatOnce 등) · executeActions 415줄 → 8 handler 그룹 (file/run/list/brain/calendar/sheets/tasks) · handlePrompt 1100줄 → 7 phase 모듈 (system prompt + budget + autoContinue 등) R50–R55: extension.ts 1145→349줄 (telegram/settings/provider commands 분리) Stocks feature 신규: /stocks slash command (v2.2.152~158) · .astra/stocks.json 저장소 + Yahoo Finance 현재가 갱신 · 8 키워드 필터 (ROE/성장성/유동성/수익성/영업효율/기술력/안정성/PBR) · Naver 시가총액 페이지 JSON API (m.stock.naver.com) 발굴 · LLM Top 5 매력도 분석 + Telegram 자동 보고서 · KST 09:00/15:00 watcher 자동 모니터링 대화 연속성 (v2.2.150~157): · [PRIOR TURN CONCLUSION] block 으로 직전 결론 anchor · thin follow-up 분류 → boilerplate 헤더 suppression · slash 명령 결과 chatHistory mirror (capture wrapper) · echo/parrot 금지 system prompt rule 기타: /stocks 슬래시 자동완성 dropdown UI, Naver JSON API 전환 (cheerio 제거) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+56
-16
@@ -110,6 +110,22 @@ export interface SectionOutline {
|
||||
scope: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ChunkedWriter 의 4개 persona 를 *외부에서 주입* 가능하게 하는 컨테이너.
|
||||
*
|
||||
* 의도: 사용자가 ChunkedWriter 를 그대로 쓰면서 일부 role 의 톤만 바꾸고 싶을 때
|
||||
* (예: 자기 회사 도메인 어휘로 polish 톤 커스텀, 또는 영어 답변 모드 outline)
|
||||
* 새 클래스 wrap 없이 한 줄로 처리 가능하게.
|
||||
*
|
||||
* 각 필드 미지정 시 기본 persona (`DEFAULT_*_PERSONA`) 사용.
|
||||
*/
|
||||
export interface PersonaOverrides {
|
||||
outline?: string;
|
||||
section?: string;
|
||||
polish?: string;
|
||||
direct?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ChunkedWriter — single-agent replacement for the old 5-stage pipeline.
|
||||
*
|
||||
@@ -137,15 +153,9 @@ export interface SectionOutline {
|
||||
* abstraction loss. The only thing that changes is the per-call system
|
||||
* prompt picked here based on `options.config.role`.
|
||||
*/
|
||||
export class ChunkedWriter extends BaseAgent {
|
||||
/**
|
||||
* Hard ceiling — *사용자 config 가 어떤 값이든 이걸 넘을 수 없다*. 안전망 의미.
|
||||
* 실제 사용 상한은 `getConfig().chunkedMaxSections` (default 3). 사용자가
|
||||
* Astra Settings 에서 1~10 사이 조정 가능, 이 상수가 그 위 절대 한도.
|
||||
*/
|
||||
static readonly MAX_SECTIONS_HARD_CEILING = 10;
|
||||
// ─── Default personas (module-level exports — 외부에서 import / 부분 override 가능) ───
|
||||
|
||||
private readonly outlinePersona = `You are a concise editor planning the structure of a Korean answer.
|
||||
export const DEFAULT_OUTLINE_PERSONA = `You are a concise editor planning the structure of a Korean answer.
|
||||
Decide how many sections the answer needs. The exact upper bound (MAX_N) is given in the user message below — never exceed it. Pick the *smallest* count that still covers the request well — a short factual question should be 0-1 section, a meaty analysis up to MAX_N.
|
||||
|
||||
Output STRICTLY a JSON array of objects: \`[{"heading": "...", "scope": "..."}]\`. No prose, no fences, no leading text.
|
||||
@@ -159,7 +169,7 @@ Output STRICTLY a JSON array of objects: \`[{"heading": "...", "scope": "..."}]\
|
||||
|
||||
If the user attached source content (article/code/log) the sections must cover *that content*, not analysis methodology.`;
|
||||
|
||||
private readonly sectionPersona = `You are writing ONE section of a longer Korean answer. You will be given:
|
||||
export const DEFAULT_SECTION_PERSONA = `You are writing ONE section of a longer Korean answer. You will be given:
|
||||
- the user's original request (possibly with attached content),
|
||||
- this section's heading + scope,
|
||||
- the full outline (for context only — DO NOT write other sections),
|
||||
@@ -173,7 +183,7 @@ Rules:
|
||||
- If the user attached source content, cite from it; do not invent facts.
|
||||
- Do NOT output the heading itself — only the body of this section.`;
|
||||
|
||||
private readonly polishPersona = `You are the final editor producing the user-facing Korean answer from a sectioned draft.
|
||||
export const DEFAULT_POLISH_PERSONA = `You are the final editor producing the user-facing Korean answer from a sectioned draft.
|
||||
|
||||
[Job]
|
||||
1. Fix typos, broken markdown, inconsistent terminology.
|
||||
@@ -215,12 +225,12 @@ B. **짧은 직답 (1~3문장 정도로 충분한 경우)**:
|
||||
- 추론 과정·\`<think>\`·"Thinking Process:" 같은 hidden reasoning 절대 노출 금지.
|
||||
- 본문 분기를 LLM 자신이 판단 — 사용자가 모드 명시 안 함.`;
|
||||
|
||||
/**
|
||||
* Single-pass 직답 persona. 짧은 질문·정의 묻기·간단한 사실 확인처럼
|
||||
* 쪼갤 필요 없는 입력을 1회 호출로 끝낸다. outline → section → polish 의
|
||||
* 3회 LLM 호출을 통째로 우회 → 작은 모델로 즉답 가능.
|
||||
*/
|
||||
private readonly directPersona = `You are answering a Korean user request in one shot. No outline, no drafting — just the final answer.
|
||||
/**
|
||||
* Single-pass 직답 persona. 짧은 질문·정의 묻기·간단한 사실 확인처럼
|
||||
* 쪼갤 필요 없는 입력을 1회 호출로 끝낸다. outline → section → polish 의
|
||||
* 3회 LLM 호출을 통째로 우회 → 작은 모델로 즉답 가능.
|
||||
*/
|
||||
export const DEFAULT_DIRECT_PERSONA = `You are answering a Korean user request in one shot. No outline, no drafting — just the final answer.
|
||||
|
||||
Rules:
|
||||
- 첫 문장이 결론 / 직답이다. "분석해보겠습니다" "좋은 질문입니다" 같은 서문 금지.
|
||||
@@ -231,6 +241,36 @@ Rules:
|
||||
- 사용자가 본문(코드·기사·로그)을 첨부했으면 그 본문에서 인용. 본문에 없는 사실 지어내지 말 것.
|
||||
- 추론 과정·"Thinking:"·<think> 노출 금지.`;
|
||||
|
||||
export class ChunkedWriter extends BaseAgent {
|
||||
/**
|
||||
* Hard ceiling — *사용자 config 가 어떤 값이든 이걸 넘을 수 없다*. 안전망 의미.
|
||||
* 실제 사용 상한은 `getConfig().chunkedMaxSections` (default 3). 사용자가
|
||||
* Astra Settings 에서 1~10 사이 조정 가능, 이 상수가 그 위 절대 한도.
|
||||
*/
|
||||
static readonly MAX_SECTIONS_HARD_CEILING = 10;
|
||||
|
||||
/**
|
||||
* 활성 persona. 기본은 DEFAULT_*_PERSONA, constructor 의 overrides 로 부분 교체.
|
||||
* private 가 아닌 protected 로 둬서 subclass 가 진화시킬 수 있게.
|
||||
*/
|
||||
protected readonly outlinePersona: string;
|
||||
protected readonly sectionPersona: string;
|
||||
protected readonly polishPersona: string;
|
||||
protected readonly directPersona: string;
|
||||
|
||||
/**
|
||||
* @param modelName Ollama / LM Studio 모델 식별자
|
||||
* @param overrides 4개 persona 중 일부만 교체 가능 (미지정 필드는 default 유지).
|
||||
* 외부 plugin / 도메인 특화 사용처에서 톤 조정 시 사용.
|
||||
*/
|
||||
constructor(modelName: string, overrides?: PersonaOverrides) {
|
||||
super(modelName);
|
||||
this.outlinePersona = overrides?.outline ?? DEFAULT_OUTLINE_PERSONA;
|
||||
this.sectionPersona = overrides?.section ?? DEFAULT_SECTION_PERSONA;
|
||||
this.polishPersona = overrides?.polish ?? DEFAULT_POLISH_PERSONA;
|
||||
this.directPersona = overrides?.direct ?? DEFAULT_DIRECT_PERSONA;
|
||||
}
|
||||
|
||||
async execute(input: string, context?: string, signal?: AbortSignal, options?: AgentExecuteOptions): Promise<string> {
|
||||
const role = (options?.config?.role as string | undefined) || 'section';
|
||||
switch (role) {
|
||||
|
||||
Reference in New Issue
Block a user