release: v2.58.0
This commit is contained in:
+307
-4
@@ -53,6 +53,7 @@ type HistoryChangeListener = (history: ChatMessage[]) => void | Promise<void>;
|
||||
|
||||
// --- Agent Roles & Workflows ---
|
||||
export type AgentRole = 'planner' | 'researcher' | 'writer';
|
||||
type LocalProjectIntent = 'review-evaluation' | 'knowledge-creation' | 'implementation' | 'documentation' | 'thinking' | 'general';
|
||||
|
||||
const AGENT_PROMPTS: Record<AgentRole, string> = {
|
||||
planner: `You are the [Planner Agent]. Your goal is to analyze the user's request and create a detailed execution plan.
|
||||
@@ -351,12 +352,15 @@ export class AgentExecutor {
|
||||
const thinkingPartnerCtx = prompt && this.isThinkingPartnerRequest(prompt)
|
||||
? `\n\n[JARVIS THINKING PARTNER MODE]\nThe user is using this tool to clarify project direction, not just to receive generic advice. Give a clear opinionated verdict first. Then separate confirmed facts, inferences, concerns, decision forks, and the next small action. Do not merely say the direction is good. If evidence is thin, say exactly what is missing and what file or record should be checked next.`
|
||||
: '';
|
||||
const astraStanceCtx = prompt
|
||||
? `\n\n${this.buildAstraStanceContext(prompt, localPathContext)}`
|
||||
: '';
|
||||
const secondBrainTraceCtx = secondBrainTrace
|
||||
? `\n\n${renderSecondBrainTraceContext(secondBrainTrace)}`
|
||||
: '';
|
||||
const memoryCtx = this.buildMemoryContext(prompt || '', activeBrain);
|
||||
|
||||
const fullSystemPrompt = `${agentSkillCtx}\n\n${systemPrompt}${internetCtx}${memoryCtx}${designerCtx}${localProjectKnowledgeCtx}${thinkingPartnerCtx}${secondBrainTraceCtx}\n\n[CONTEXT]\n${brainContext}${brainInventoryCtx}\n${contextBlock}${negativeCtx}`;
|
||||
const fullSystemPrompt = `${agentSkillCtx}\n\n${systemPrompt}${internetCtx}${memoryCtx}${designerCtx}${localProjectKnowledgeCtx}${thinkingPartnerCtx}${astraStanceCtx}${secondBrainTraceCtx}\n\n[CONTEXT]\n${brainContext}${brainInventoryCtx}\n${contextBlock}${negativeCtx}`;
|
||||
const messagesForRequest: ChatMessage[] = [
|
||||
{ role: 'system', content: fullSystemPrompt, internal: true },
|
||||
...reqMessages
|
||||
@@ -451,6 +455,12 @@ export class AgentExecutor {
|
||||
if (prompt && this.isSecondBrainInventoryRequest(prompt) && brainFiles.length > 0 && this.isNoBrainDataRefusal(assistantContent)) {
|
||||
assistantContent = this.buildSecondBrainInventoryFallbackAnswer(activeBrain, brainFiles, secondBrainTrace);
|
||||
}
|
||||
if (prompt && localPathContext && this.isProjectReviewEvaluationRequest(prompt) && this.isMisroutedProjectKnowledgeAnswer(assistantContent)) {
|
||||
assistantContent = this.buildProjectReviewFallbackAnswer(localPathContext);
|
||||
}
|
||||
if (prompt && localPathContext && this.isProjectReviewEvaluationRequest(prompt) && this.isShallowProjectReviewAnswer(assistantContent)) {
|
||||
assistantContent = this.buildProjectReviewFallbackAnswer(localPathContext);
|
||||
}
|
||||
if (prompt && localPathContext && this.isProjectKnowledgeCreationRequest(prompt)) {
|
||||
const record = this.writeProjectKnowledgeRecord(localPathContext);
|
||||
if (this.isBlockingProjectKnowledgeAnswer(assistantContent)) {
|
||||
@@ -470,6 +480,9 @@ export class AgentExecutor {
|
||||
if (prompt && localPathContext) {
|
||||
assistantContent = this.ensureLocalProjectPathEvidence(assistantContent, localPathContext);
|
||||
}
|
||||
if (prompt) {
|
||||
assistantContent = this.applyAstraQualityGate(assistantContent, prompt, localPathContext);
|
||||
}
|
||||
const traceMarkdown = secondBrainTrace
|
||||
? renderSecondBrainTraceMarkdown(secondBrainTrace, !!options.secondBrainTraceDebug)
|
||||
: '';
|
||||
@@ -762,12 +775,18 @@ export class AgentExecutor {
|
||||
return '';
|
||||
}
|
||||
|
||||
const intent = this.classifyLocalProjectIntent(prompt);
|
||||
const sections: string[] = [
|
||||
'[LOCAL PROJECT PATH PREFLIGHT]',
|
||||
`Local project intent: ${intent}`,
|
||||
this.buildLocalProjectIntentGuidance(intent),
|
||||
'The user provided a local project path for review, analysis, documentation, or knowledge creation. Use this inspected context before asking for uploads.',
|
||||
'If access failed, explain the concrete failure. If access succeeded, proceed with code review from the scanned files.',
|
||||
'If access succeeded and priority file previews are present, do not say that code was not provided.',
|
||||
'For knowledge creation requests, answer that the project can be summarized from the inspected local path and propose or execute a project knowledge note based on the previews.'
|
||||
'Treat the Local project intent line as the routing decision for this response.',
|
||||
'If intent is review-evaluation, do not create a project knowledge note. Review the inspected project as the primary task: strengths, weaknesses, risks, and extensibility.',
|
||||
'If intent is knowledge-creation, answer that the project can be summarized from the inspected local path and propose or execute a project knowledge note based on the previews.',
|
||||
'If intent is thinking, act as a project thinking partner and give a clear verdict grounded in the inspected files.'
|
||||
];
|
||||
|
||||
for (const candidate of candidates.slice(0, 2)) {
|
||||
@@ -777,14 +796,235 @@ export class AgentExecutor {
|
||||
return sections.join('\n');
|
||||
}
|
||||
|
||||
private buildLocalProjectIntentGuidance(intent: LocalProjectIntent): string {
|
||||
switch (intent) {
|
||||
case 'review-evaluation':
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Review the project as a working product, not as a note to be generated.',
|
||||
'- Start with a sharp verdict: usable now, promising but risky, or not ready.',
|
||||
'- Use these review lenses in order: 1. purpose fit, 2. architecture shape, 3. data/control flow, 4. failure recovery, 5. operability/observability, 6. extensibility.',
|
||||
'- For each major claim, tie it to an observed file, folder, or missing evidence.',
|
||||
'- Name the strongest leverage point and the most dangerous blind spot.',
|
||||
'- End with a prioritized roadmap: stabilize first, then improve quality, then expand.'
|
||||
].join('\n');
|
||||
case 'knowledge-creation':
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Create a reusable project knowledge note from inspected evidence.',
|
||||
'- Do not ask for scope if the path is accessible; choose a small MVP overview by default.',
|
||||
'- Separate confirmed structure from inferred purpose and next deep-dive targets.'
|
||||
].join('\n');
|
||||
case 'implementation':
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Treat this as a change request, not advice.',
|
||||
'- Inspect the relevant files, make the smallest safe implementation, and verify it.',
|
||||
'- Preserve unrelated user changes.'
|
||||
].join('\n');
|
||||
case 'documentation':
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Produce or update documentation from inspected evidence.',
|
||||
'- Separate user-facing usage docs from internal architecture notes.',
|
||||
'- Avoid claiming behavior that is not visible in code or existing docs.'
|
||||
].join('\n');
|
||||
case 'thinking':
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Act as a thinking partner.',
|
||||
'- Give a direct opinion, then split confirmed facts, inferences, risks, decision forks, and one next move.',
|
||||
'- Avoid generic encouragement.'
|
||||
].join('\n');
|
||||
default:
|
||||
return [
|
||||
'Intent operating contract:',
|
||||
'- Use the inspected local files as grounding.',
|
||||
'- If the user request is ambiguous, answer the most likely project-oriented task and state the assumption.'
|
||||
].join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
private buildAstraStanceContext(prompt: string, localPathContext: string): string {
|
||||
const intent = localPathContext ? this.classifyLocalProjectIntent(prompt) : 'general';
|
||||
const wantsThinkingPartner = this.isThinkingPartnerRequest(prompt) || intent === 'review-evaluation' || intent === 'thinking';
|
||||
|
||||
const lines = [
|
||||
'[ASTRA STANCE LAYER]',
|
||||
'Use this to make the response feel like Astra thinking with the user, not a template being filled.',
|
||||
'',
|
||||
'Voice:',
|
||||
'- Warm, direct, and grounded. Do not over-explain the framework.',
|
||||
'- Prefer sentences that sound like a senior collaborator: "나는 여기서 X를 먼저 볼 것 같아요" / "이건 좋아요, 그런데 위험은 Y예요."',
|
||||
'- Avoid sterile balance like "장단점이 있습니다" unless you immediately make a call.',
|
||||
'',
|
||||
'Judgment habits:',
|
||||
'- State the real bet you think the user is making.',
|
||||
'- Name one thing to keep, one thing to cut, and one thing to verify next when relevant.',
|
||||
'- Use the user’s own goal as the yardstick, not generic best practice.',
|
||||
'- If there are many possible improvements, choose the one that compounds the project fastest.',
|
||||
'',
|
||||
wantsThinkingPartner
|
||||
? 'For this request, be especially opinionated. Give a clear personal verdict before structure.'
|
||||
: 'For this request, keep the persona light but still make concrete choices.',
|
||||
intent !== 'general' ? `Local project intent for tone: ${intent}` : ''
|
||||
];
|
||||
|
||||
if (intent === 'review-evaluation') {
|
||||
lines.push(
|
||||
'',
|
||||
'Review stance:',
|
||||
'- Do not merely list strengths and weaknesses. Say whether you would rely on this project today and under what constraint.',
|
||||
'- Prefer the product-owner question: "What has to become boring and reliable before this deserves expansion?"',
|
||||
'- If evidence is shallow, say which file would change your opinion most.'
|
||||
);
|
||||
}
|
||||
|
||||
if (intent === 'thinking') {
|
||||
lines.push(
|
||||
'',
|
||||
'Thinking stance:',
|
||||
'- Do not solve every branch. Reduce the user’s uncertainty to the next decision.',
|
||||
'- A useful answer may say: "I would not expand yet" or "This deserves a spike, not a feature."'
|
||||
);
|
||||
}
|
||||
|
||||
return lines.filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
private evaluateAstraAnswerQuality(content: string, prompt: string, localPathContext: string): {
|
||||
needsGate: boolean;
|
||||
hasVerdict: boolean;
|
||||
hasRisk: boolean;
|
||||
hasNextMove: boolean;
|
||||
templateSmell: boolean;
|
||||
} {
|
||||
const intent = localPathContext ? this.classifyLocalProjectIntent(prompt) : 'general';
|
||||
const needsGate = intent === 'review-evaluation' || intent === 'thinking' || this.isThinkingPartnerRequest(prompt);
|
||||
if (!needsGate) {
|
||||
return { needsGate: false, hasVerdict: true, hasRisk: true, hasNextMove: true, templateSmell: false };
|
||||
}
|
||||
|
||||
const hasVerdict = /(Astra 판단|제 판단|내 판단|결론|나는 .{0,20}(?:볼|생각|추천)|먼저 .{0,20}(?:해야|보는)|핵심은|verdict|my take)/i.test(content);
|
||||
const hasRisk = /(위험|리스크|걱정|우려|blind spot|risk|concern|주의)/i.test(content);
|
||||
const hasNextMove = /(다음 한 수|다음 행동|다음 단계|우선순위|먼저 .{0,20}(?:보|하|확인)|next move|next step)/i.test(content);
|
||||
const templateHeadingHits = [
|
||||
/##\s*요청 요약/i,
|
||||
/##\s*(추론된|인지된|inferred)\s*사용자\s*의도/i,
|
||||
/##\s*프로젝트 기록/i,
|
||||
/Candidate records for this discussion/i,
|
||||
/2nd Brain Trace/i
|
||||
].filter((pattern) => pattern.test(content)).length;
|
||||
const templateSmell = templateHeadingHits >= 2 && !/Astra 판단|제 판단|내 판단/i.test(content);
|
||||
|
||||
return { needsGate, hasVerdict, hasRisk, hasNextMove, templateSmell };
|
||||
}
|
||||
|
||||
private applyAstraQualityGate(content: string, prompt: string, localPathContext: string): string {
|
||||
const quality = this.evaluateAstraAnswerQuality(content, prompt, localPathContext);
|
||||
if (!quality.needsGate || (!quality.templateSmell && quality.hasVerdict && quality.hasRisk && quality.hasNextMove)) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const intent = localPathContext ? this.classifyLocalProjectIntent(prompt) : 'general';
|
||||
const additions: string[] = [];
|
||||
if ((!quality.hasVerdict || quality.templateSmell) && !/##\s*Astra 판단/i.test(content)) {
|
||||
additions.push([
|
||||
'## Astra 판단',
|
||||
this.buildAstraVerdict(prompt, localPathContext, intent)
|
||||
].join('\n'));
|
||||
}
|
||||
if (!quality.hasRisk && !/(##\s*(리스크|우려|위험)|blind spot)/i.test(content)) {
|
||||
additions.push([
|
||||
'## 내가 보는 위험',
|
||||
this.buildAstraRisk(prompt, localPathContext, intent)
|
||||
].join('\n'));
|
||||
}
|
||||
if (!quality.hasNextMove && !/##\s*다음 한 수/i.test(content)) {
|
||||
additions.push([
|
||||
'## 다음 한 수',
|
||||
this.buildAstraNextMove(prompt, localPathContext, intent)
|
||||
].join('\n'));
|
||||
}
|
||||
|
||||
return additions.length
|
||||
? [additions.join('\n\n'), '', content.trim()].join('\n')
|
||||
: content;
|
||||
}
|
||||
|
||||
private buildAstraVerdict(prompt: string, localPathContext: string, intent: LocalProjectIntent): string {
|
||||
if (intent === 'review-evaluation') {
|
||||
const projectPath = localPathContext.match(/Path:\s*(.+)/)?.[1]?.trim() || '이 프로젝트';
|
||||
return `나는 이 요청을 “좋은 말 해주는 평가”가 아니라 실제로 의존해도 되는 도구인지 보는 리뷰로 볼게요. \`${projectPath}\`는 먼저 목적에 맞는 수집 루프가 안정적인지, 끊겼을 때 이어지는지, 결과가 재검증 가능한지를 기준으로 판단하는 게 맞습니다. 기능 확장은 그 다음입니다.`;
|
||||
}
|
||||
if (intent === 'thinking') {
|
||||
return '내 판단은 방향을 넓히기 전에 지금 헷갈리는 선택지를 줄이는 게 먼저라는 쪽입니다. 이 답변은 가능한 모든 선택지를 펼치기보다, 지금 결정하면 다음 작업이 쉬워지는 갈림길을 잡는 데 초점을 둡니다.';
|
||||
}
|
||||
return '내 판단은 템플릿보다 지금 사용자가 실제로 줄이려는 불확실성을 먼저 잡아야 한다는 쪽입니다. 그래서 답변은 정보 나열보다 선택과 다음 행동 중심으로 봅니다.';
|
||||
}
|
||||
|
||||
private buildAstraRisk(prompt: string, localPathContext: string, intent: LocalProjectIntent): string {
|
||||
if (intent === 'review-evaluation') {
|
||||
return '가장 큰 위험은 구조가 좋아 보이는 것과 운영에서 믿을 수 있는 것이 다르다는 점입니다. 특히 수집 도구는 실패 복구, 중복 제거, 상태 저장, 진단 로그가 약하면 기능이 많아져도 실제 사용감은 계속 흔들립니다.';
|
||||
}
|
||||
return '가장 큰 위험은 선택지를 넓히는 동안 실제 다음 행동이 흐려지는 것입니다. 지금은 더 많은 가능성보다 판단 기준 하나를 세우는 편이 낫습니다.';
|
||||
}
|
||||
|
||||
private buildAstraNextMove(prompt: string, localPathContext: string, intent: LocalProjectIntent): string {
|
||||
if (intent === 'review-evaluation') {
|
||||
return '다음은 확장 아이디어를 붙이기보다 핵심 루프 하나를 추적하는 겁니다. `engine`이 작업 단위, 재시도, 실패 기록, 결과 저장을 어디서 책임지는지 먼저 확인하고, 그 다음 `diagnostics`가 실제 운영 판단에 충분한 정보를 주는지 보면 됩니다.';
|
||||
}
|
||||
if (intent === 'thinking') {
|
||||
return '다음 한 수는 “지금 당장 유지할 원칙 1개”와 “아직 확장하지 않을 것 1개”를 정하는 겁니다. 그 두 개가 정해지면 설계가 훨씬 덜 흔들립니다.';
|
||||
}
|
||||
return '다음 한 수는 답변을 더 길게 만드는 것이 아니라, 지금 결정해야 하는 기준 하나를 명확히 하는 것입니다.';
|
||||
}
|
||||
|
||||
private shouldPreflightLocalProjectPath(prompt: string): boolean {
|
||||
return /(검토|리뷰|분석|확인|봐줘|고쳐|개선|디버그|지식|문서화|문서|정리|기록|위키|저장|만들|생성|설계|아키텍처|구조|방향|의견|생각|판단|어떤\s*거?\s*같|어때|knowledge|document|documentation|wiki|summari[sz]e|review|analy[sz]e|inspect|debug|fix|improve|architecture|design|structure|opinion|think|judge)/i.test(prompt)
|
||||
&& /\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/i.test(prompt);
|
||||
}
|
||||
|
||||
private isProjectKnowledgeCreationRequest(prompt: string): boolean {
|
||||
return /(지식|문서화|문서|정리|기록|위키|저장|만들|생성|knowledge|document|documentation|wiki|summari[sz]e)/i.test(prompt)
|
||||
&& /\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/i.test(prompt);
|
||||
return this.classifyLocalProjectIntent(prompt) === 'knowledge-creation';
|
||||
}
|
||||
|
||||
private isProjectReviewEvaluationRequest(prompt: string): boolean {
|
||||
return this.classifyLocalProjectIntent(prompt) === 'review-evaluation';
|
||||
}
|
||||
|
||||
private classifyLocalProjectIntent(prompt: string): LocalProjectIntent {
|
||||
if (!/\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+/i.test(prompt)) {
|
||||
return 'general';
|
||||
}
|
||||
|
||||
const normalized = prompt.replace(/\s+/g, ' ').trim();
|
||||
const asksReview = /(코드\s*리뷰|코드리뷰|리뷰|검토|평가|봐줘|장점|단점|약점|강점|확장성|문제점|리스크|개선점|의견|판단|괜찮|어때|어떤\s*거?\s*같|review|evaluate|assessment|strength|weakness|pros?\s*and\s*cons?|extensibility|scalability|risk|issue)/i.test(normalized);
|
||||
if (asksReview) {
|
||||
return 'review-evaluation';
|
||||
}
|
||||
|
||||
const asksImplementation = /(고쳐|수정|개선해|구현|추가|삭제|리팩토링|디버그|fix|implement|add|remove|refactor|debug)/i.test(normalized);
|
||||
if (asksImplementation) {
|
||||
return 'implementation';
|
||||
}
|
||||
|
||||
const explicitKnowledgeCreation = /((?:이|그|현재|해당)?\s*(?:프로젝트|프로그램|코드베이스).{0,20}(?:대한|기반|관련).{0,20}지식.{0,12}(?:만들|생성|정리|문서화|기록|저장))|(지식.{0,12}(?:만들|생성|정리|문서화|기록|저장).{0,20}(?:프로젝트|프로그램|코드베이스))|(project\s+knowledge.{0,20}(?:create|generate|record|document|overview))|((?:create|generate|record|document).{0,20}project\s+knowledge)/i.test(normalized);
|
||||
if (explicitKnowledgeCreation) {
|
||||
return 'knowledge-creation';
|
||||
}
|
||||
|
||||
const asksDocumentation = /(문서화(?:해|해줘|를)|문서(?:로)?\s*(?:정리|작성|만들)|README|가이드|wiki|documentation|document\s+this|write\s+docs)/i.test(normalized);
|
||||
if (asksDocumentation) {
|
||||
return 'documentation';
|
||||
}
|
||||
|
||||
const asksThinking = /(설계|아키텍처|구조|방향|생각|의견|판단|어떤\s*거?\s*같|어때|architecture|design|structure|direction|opinion|think|judge)/i.test(normalized);
|
||||
if (asksThinking) {
|
||||
return 'thinking';
|
||||
}
|
||||
|
||||
return 'general';
|
||||
}
|
||||
|
||||
private isProjectKnowledgeFollowupRequest(prompt: string): boolean {
|
||||
@@ -1153,6 +1393,69 @@ export class AgentExecutor {
|
||||
return /(블로킹 질문|어떤 기능 영역|어떤 부분.*먼저|어떤 기능이나 아키텍처|구체적인 방향|방향 설정이 필요|명확히 알려주시면|우선적으로 정리|최종 사용 목적|Question reason|별도의 파일 기록.*생성되지|파일 기록이 생성되지|더 깊이 있는 분석.*지정|해당 기능.*지정하여 요청)/i.test(content);
|
||||
}
|
||||
|
||||
private isMisroutedProjectKnowledgeAnswer(content: string): boolean {
|
||||
return /(기본 지식 생성 방향|바로 만들 지식 초안|Project Knowledge Overview|프로젝트 지식 1번 문서|프로젝트 지식 기록을 생성|프로젝트 지식.*만들면|지식 생성 작업)/i.test(content);
|
||||
}
|
||||
|
||||
private isShallowProjectReviewAnswer(content: string): boolean {
|
||||
if (!/##\s*(코드리뷰|평가|장점|단점|확장성|리스크|개선|상세 답변)/i.test(content)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const requiredSignals = [
|
||||
/(목적|purpose|fit)/i,
|
||||
/(아키텍처|구조|architecture|structure)/i,
|
||||
/(흐름|flow|pipeline|control|data)/i,
|
||||
/(실패|복구|재시도|failure|recovery|retry)/i,
|
||||
/(운영|관측|로그|diagnostics|observability|operability)/i,
|
||||
/(확장성|extensibility|scalability)/i
|
||||
];
|
||||
const hits = requiredSignals.filter((pattern) => pattern.test(content)).length;
|
||||
return hits < 4;
|
||||
}
|
||||
|
||||
private buildProjectReviewFallbackAnswer(localPathContext: string): string {
|
||||
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
||||
const projectPath = pathMatch?.[1]?.trim() || '제공된 로컬 프로젝트 경로';
|
||||
const treeMatch = localPathContext.match(/Scanned tree:\n([\s\S]*?)(?:\nPriority file previews:|$)/);
|
||||
const treePreview = treeMatch?.[1]?.trim().split('\n').slice(0, 18).join('\n') || '';
|
||||
const priorityFiles = this.extractPriorityPreviewFiles(localPathContext).slice(0, 10);
|
||||
const fileList = priorityFiles.length
|
||||
? priorityFiles.map((file) => `- \`${file}\``).join('\n')
|
||||
: '- 우선 확인 파일을 충분히 찾지 못했습니다.';
|
||||
|
||||
return [
|
||||
'## 간단 요약',
|
||||
'이 요청은 프로젝트 지식 생성이 아니라 코드리뷰와 제품 평가 요청입니다. 확인된 파일 구조 기준으로 보면, 이 프로젝트는 지식 수집 워크플로우를 앱 형태로 묶어 운영하려는 도구로 보이며, 먼저 데이터 수집 흐름의 안정성, 외부 연동 실패 처리, 수집 결과의 저장/재처리 가능성을 중심으로 평가해야 합니다.',
|
||||
'',
|
||||
'## 확인된 근거',
|
||||
`대상 경로: \`${projectPath}\``,
|
||||
'',
|
||||
'확인된 우선 파일:',
|
||||
fileList,
|
||||
treePreview ? `\n확인된 구조 일부:\n\`\`\`text\n${treePreview}\n\`\`\`` : '',
|
||||
'',
|
||||
'## 코드리뷰 관점 평가',
|
||||
'1. 목적 적합성: 지식 수집 프로그램이라면 핵심은 “많이 가져오기”보다 “끊겨도 이어지고, 중복 없이 남고, 다시 검증할 수 있는 수집 흐름”입니다. 현재 구조에서는 `engine`, `api`, `diagnostics`, `gemini`처럼 수집 실행, 외부 연동, 진단, 모델 연동으로 보이는 책임이 드러나므로 목적에 맞는 기본 골격은 있습니다.',
|
||||
'',
|
||||
'2. 아키텍처 형태: `src/lib/*` 아래에 실행 계층이 모이고 `components/AgentDashboard.tsx`가 UI 관측면을 담당하는 형태로 보입니다. 이 분리는 좋지만, 실제로 UI가 엔진 내부 상태를 직접 많이 알고 있으면 확장 때 결합이 커질 수 있습니다.',
|
||||
'',
|
||||
'3. 데이터/제어 흐름: 다음 리뷰의 핵심은 `src/lib/engine.ts`가 작업 큐, 수집 단계, 결과 저장, 재시도 정책을 어디까지 책임지는지 확인하는 것입니다. 수집 도구의 품질은 이 흐름이 명시적인 상태 머신처럼 보이느냐에 달려 있습니다.',
|
||||
'',
|
||||
'4. 실패 복구: 현재 확인된 프리뷰만으로는 수집 실패 후 재시도, 중복 수집 방지, 인증 만료 복구, 장기 실행 상태 저장이 충분히 검증되지 않았습니다. 이게 가장 위험한 blind spot입니다.',
|
||||
'',
|
||||
'5. 운영성/관측성: `diagnostics.ts`가 있다는 점은 강점입니다. 다만 진단이 단순 상태 표시인지, 실패 원인/마지막 성공 지점/재개 가능 여부까지 기록하는지 확인해야 합니다.',
|
||||
'',
|
||||
'6. 확장성: 확장성은 기능 추가보다 파이프라인 안정화에서 나옵니다. 수집 대상이 늘어날수록 커넥터 인터페이스, 결과 스키마, 중복 제거, 품질 점수화가 먼저 필요합니다.',
|
||||
'',
|
||||
'## 확장성 방향',
|
||||
'확장성은 기능을 더 붙이는 방향보다 수집 파이프라인을 안정화하는 쪽으로 잡는 것이 좋습니다. 우선순위는 1. 수집 작업 단위 정의, 2. 상태 저장과 재개, 3. 실패 원인 기록, 4. 중복 제거, 5. 수집 결과 품질 점수화, 6. Second Brain 저장 포맷 표준화 순서가 좋습니다.',
|
||||
'',
|
||||
'## 다음에 깊게 볼 파일',
|
||||
'다음 리뷰에서는 `src/lib/engine.ts`, `src/lib/api.ts`, `src/lib/diagnostics.ts`, `src/lib/gemini.ts`, `src/components/AgentDashboard.tsx`를 순서대로 보면 됩니다. 특히 `engine.ts`가 실제 수집 플로우의 중심인지 확인하고, 실패/재시도/상태 저장이 어디서 책임지는지 보는 게 첫 번째입니다.'
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
private buildProjectKnowledgeFallbackAnswer(localPathContext: string, record?: { filePath: string; relativePath: string } | null): string {
|
||||
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
||||
const projectPath = pathMatch?.[1]?.trim() || '제공된 로컬 프로젝트 경로';
|
||||
|
||||
@@ -174,6 +174,15 @@ Core behavior:
|
||||
- If available evidence is only general knowledge, never say the project architecture is flexible, technically stable, scalable, gateway-based, microservice-ready, separated into layers, or structurally prepared. Say the technical structure cannot be judged from the current information.
|
||||
- For questions about customer evaluation, approval likelihood, requirement fit, UX, business value, product discovery, or purchase conversion, do not over-focus on technical architecture. Treat approval likelihood as an inference unless explicit approval criteria are provided.
|
||||
|
||||
Astra stance:
|
||||
- You are not a template renderer. You are a local operating partner with taste, memory, and engineering judgment.
|
||||
- Your default posture is calm but opinionated: say what you would actually do, what you would postpone, and what you would refuse to overbuild.
|
||||
- Preserve the user's momentum. When the user is sorting out an idea, turn fog into 1-2 crisp choices instead of giving a balanced essay.
|
||||
- Speak like a capable collaborator sitting next to the user: warm, direct, occasionally wry, never theatrical.
|
||||
- Let your point of view show through concrete preferences: simple local files before databases, reliable recovery before new features, evidence before claims, working loops before grand architecture.
|
||||
- If the user's framing is off, gently correct the frame before answering inside it.
|
||||
- If the answer starts sounding like a checklist, collapse it into a verdict, a reason, a risk, and the next move.
|
||||
|
||||
Available action tags:
|
||||
|
||||
[ACTION 1: CREATE NEW FILES]
|
||||
|
||||
Reference in New Issue
Block a user