@yuaone/core 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -75,33 +75,6 @@ export interface AgentLoopOptions {
75
75
  /** Enable background agents (persistent monitors, default false — opt-in) */
76
76
  enableBackgroundAgents?: boolean;
77
77
  }
78
- /**
79
- * AgentLoop — YUAN 에이전트의 핵심 실행 루프.
80
- *
81
- * 동작 흐름:
82
- * 1. 사용자 메시지 수신
83
- * 2. 시스템 프롬프트 + 히스토리로 LLM 호출
84
- * 3. LLM 응답에서 tool_call 파싱
85
- * 4. Governor가 안전성 검증
86
- * 5. 도구 실행 → 결과를 히스토리에 추가
87
- * 6. LLM에 결과 피드백 → 2번으로 반복
88
- * 7. 종료 조건 충족 시 결과 반환
89
- *
90
- * @example
91
- * ```typescript
92
- * const loop = new AgentLoop({
93
- * config: agentConfig,
94
- * toolExecutor: executor,
95
- * governorConfig: { planTier: "PRO" },
96
- * });
97
- *
98
- * loop.on("event", (event: AgentEvent) => {
99
- * // SSE 스트리밍
100
- * });
101
- *
102
- * const result = await loop.run("모든 console.log를 제거해줘");
103
- * ```
104
- */
105
78
  export declare class AgentLoop extends EventEmitter {
106
79
  private readonly abortSignal?;
107
80
  private readonly llmClient;
@@ -171,6 +144,16 @@ export declare class AgentLoop extends EventEmitter {
171
144
  private static readonly MAX_ACTIVE_SKILLS;
172
145
  /** Context Budget: track injected system messages per iteration to cap at 5 */
173
146
  private iterationSystemMsgCount;
147
+ /** Task 1: ContextBudgetManager for LLM-based summarization at 60-70% context usage */
148
+ private contextBudgetManager;
149
+ /** Task 2: Track whether write tools ran this iteration for QA triggering */
150
+ private iterationWriteToolPaths;
151
+ /** Task 2: Last QA result (surfaced to LLM on issues) */
152
+ private lastQAResult;
153
+ /** Task 3: Track TS files modified this run for auto-tsc */
154
+ private iterationTsFilesModified;
155
+ /** Task 3: Whether tsc was run in the previous iteration (skip cooldown) */
156
+ private tscRanLastIteration;
174
157
  private tokenUsage;
175
158
  private readonly reasoningAggregator;
176
159
  private readonly reasoningTree;
@@ -409,6 +392,11 @@ export declare class AgentLoop extends EventEmitter {
409
392
  private handleSoftContextOverflow;
410
393
  /** MCP 클라이언트 정리 (세션 종료 시 호출) */
411
394
  dispose(): Promise<void>;
395
+ /**
396
+ * Builds a Map<filePath, toolOutput> for all changed files from write/edit tool results.
397
+ * Used by selfReflection deepVerify and quickVerify.
398
+ */
399
+ private buildChangedFilesMap;
412
400
  private emitEvent;
413
401
  private emitReasoning;
414
402
  private emitSubagent;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,8 @@ import { ReasoningTree } from "./reasoning-tree.js";
48
48
  import { ContextCompressor } from "./context-compressor.js";
49
49
  import { DependencyAnalyzer } from "./dependency-analyzer.js";
50
50
  import { CrossFileRefactor } from "./cross-file-refactor.js";
51
+ import { ContextBudgetManager } from "./context-budget.js";
52
+ import { QAPipeline } from "./qa-pipeline.js";
51
53
  /**
52
54
  * AgentLoop — YUAN 에이전트의 핵심 실행 루프.
53
55
  *
@@ -75,6 +77,8 @@ import { CrossFileRefactor } from "./cross-file-refactor.js";
75
77
  * const result = await loop.run("모든 console.log를 제거해줘");
76
78
  * ```
77
79
  */
80
+ /** Minimum confidence for classification-based hints/routing to activate */
81
+ const CLASSIFICATION_CONFIDENCE_THRESHOLD = 0.6;
78
82
  export class AgentLoop extends EventEmitter {
79
83
  abortSignal;
80
84
  llmClient;
@@ -144,6 +148,16 @@ export class AgentLoop extends EventEmitter {
144
148
  static MAX_ACTIVE_SKILLS = 3;
145
149
  /** Context Budget: track injected system messages per iteration to cap at 5 */
146
150
  iterationSystemMsgCount = 0;
151
+ /** Task 1: ContextBudgetManager for LLM-based summarization at 60-70% context usage */
152
+ contextBudgetManager = null;
153
+ /** Task 2: Track whether write tools ran this iteration for QA triggering */
154
+ iterationWriteToolPaths = [];
155
+ /** Task 2: Last QA result (surfaced to LLM on issues) */
156
+ lastQAResult = null;
157
+ /** Task 3: Track TS files modified this run for auto-tsc */
158
+ iterationTsFilesModified = [];
159
+ /** Task 3: Whether tsc was run in the previous iteration (skip cooldown) */
160
+ tscRanLastIteration = false;
147
161
  tokenUsage = {
148
162
  input: 0,
149
163
  output: 0,
@@ -278,6 +292,12 @@ export class AgentLoop extends EventEmitter {
278
292
  if (this.initialized)
279
293
  return;
280
294
  this.initialized = true;
295
+ // Task 1: Initialize ContextBudgetManager with the total token budget
296
+ this.contextBudgetManager = new ContextBudgetManager({
297
+ totalBudget: this.config.loop.totalTokenBudget,
298
+ enableSummarization: true,
299
+ summarizationThreshold: 0.60, // trigger summarize() at 60% (before ContextCompressor at 70%)
300
+ });
281
301
  const projectPath = this.config.loop.projectPath;
282
302
  if (!projectPath)
283
303
  return;
@@ -463,7 +483,7 @@ export class AgentLoop extends EventEmitter {
463
483
  const learnedSkills = this.skillLearner.getAllSkills();
464
484
  if (learnedSkills.length > 0) {
465
485
  const skillNames = learnedSkills
466
- .filter((s) => s.confidence >= 0.3)
486
+ .filter((s) => s.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD)
467
487
  .map((s) => s.id);
468
488
  if (skillNames.length > 0) {
469
489
  this.contextManager.addMessage({
@@ -597,7 +617,7 @@ export class AgentLoop extends EventEmitter {
597
617
  buildMemoryContext(memory) {
598
618
  const parts = [];
599
619
  // 높은 confidence 학습만 포함
600
- const highConfLearnings = memory.learnings.filter((l) => l.confidence >= 0.3);
620
+ const highConfLearnings = memory.learnings.filter((l) => l.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD);
601
621
  if (highConfLearnings.length > 0) {
602
622
  parts.push("## Things I've Learned About This Project");
603
623
  for (const l of highConfLearnings.slice(0, 20)) {
@@ -630,6 +650,8 @@ export class AgentLoop extends EventEmitter {
630
650
  this.aborted = false;
631
651
  this.reasoningAggregator.reset();
632
652
  this.reasoningTree.reset();
653
+ // Capture before reset so session snapshot gets accurate file list
654
+ const prevChangedFiles = [...this.changedFiles];
633
655
  if (!this.resumedFromSession) {
634
656
  this.changedFiles = [];
635
657
  this.allToolResults = [];
@@ -645,6 +667,9 @@ export class AgentLoop extends EventEmitter {
645
667
  total: 0,
646
668
  };
647
669
  this.impactHintInjected = false;
670
+ // Task 3: reset tsc tracking per run
671
+ this.iterationTsFilesModified = [];
672
+ this.tscRanLastIteration = false;
648
673
  }
649
674
  this.checkpointSaved = false;
650
675
  this.failureRecovery.reset();
@@ -677,7 +702,7 @@ export class AgentLoop extends EventEmitter {
677
702
  snapshot,
678
703
  messages: this.contextManager.getMessages(),
679
704
  plan: this.activePlan,
680
- changedFiles: this.changedFiles,
705
+ changedFiles: prevChangedFiles,
681
706
  });
682
707
  }
683
708
  // 사용자 입력 검증 (prompt injection 방어)
@@ -717,7 +742,7 @@ export class AgentLoop extends EventEmitter {
717
742
  }
718
743
  // Task 분류 → 시스템 프롬프트에 tool sequence hint 주입
719
744
  const classification = this.taskClassifier.classify(userMessage);
720
- if (classification.confidence >= 0.3) {
745
+ if (classification.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
721
746
  const classificationHint = this.taskClassifier.formatForSystemPrompt(classification);
722
747
  this.contextManager.addMessage({
723
748
  role: "system",
@@ -727,7 +752,7 @@ export class AgentLoop extends EventEmitter {
727
752
  // Specialist routing: 태스크 타입에 맞는 전문 에이전트 설정 주입
728
753
  if (classification.specialistDomain) {
729
754
  const specialistMatch = this.specialistRegistry.findSpecialist(classification.specialistDomain);
730
- if (specialistMatch && specialistMatch.confidence >= 0.5) {
755
+ if (specialistMatch && specialistMatch.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
731
756
  this.contextManager.addMessage({
732
757
  role: "system",
733
758
  content: `[Specialist: ${specialistMatch.specialist.name}] ${specialistMatch.specialist.systemPrompt.slice(0, 500)}`,
@@ -735,13 +760,13 @@ export class AgentLoop extends EventEmitter {
735
760
  }
736
761
  }
737
762
  // Tool Planning: 태스크 타입에 맞는 도구 실행 계획 힌트 주입
738
- if (this.enableToolPlanning && classification.confidence >= 0.3) {
763
+ if (this.enableToolPlanning && classification.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
739
764
  const planContext = {
740
765
  userMessage,
741
766
  };
742
767
  this.currentToolPlan = this.toolPlanner.planForTask(classification.type, planContext);
743
768
  this.executedToolNames = [];
744
- if (this.currentToolPlan.confidence >= 0.5) {
769
+ if (this.currentToolPlan.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
745
770
  const planHint = this.toolPlanner.formatPlanHint(this.currentToolPlan);
746
771
  this.contextManager.addMessage({
747
772
  role: "system",
@@ -882,6 +907,18 @@ export class AgentLoop extends EventEmitter {
882
907
  return result;
883
908
  }
884
909
  catch (err) {
910
+ // Attempt recovery from last checkpoint via ContinuationEngine
911
+ if (this.continuationEngine) {
912
+ try {
913
+ const recovered = await this.continuationEngine.findLatestCheckpoint();
914
+ if (recovered) {
915
+ this.emitReasoning(`recovered from checkpoint at iteration ${recovered.iterationsCompleted ?? "unknown"}`);
916
+ }
917
+ }
918
+ catch {
919
+ // Recovery failure is non-fatal
920
+ }
921
+ }
885
922
  return this.handleFatalError(err);
886
923
  }
887
924
  }
@@ -1388,10 +1425,48 @@ export class AgentLoop extends EventEmitter {
1388
1425
  this.iterationCount = iteration;
1389
1426
  const iterationStart = Date.now();
1390
1427
  this.emitReasoning(`iteration ${iteration}: preparing context`);
1391
- this.iterationSystemMsgCount = 0; // Reset per-iteration system message counter
1428
+ this.iterationSystemMsgCount = 0; // Reset per-iteration (prevents accumulation across iterations)
1429
+ // Policy validation — check cost limits from ExecutionPolicyEngine
1430
+ if (this.policyEngine) {
1431
+ try {
1432
+ const costPolicy = this.policyEngine.get("cost");
1433
+ const iterationTokensUsed = this.tokenUsage.input + this.tokenUsage.output;
1434
+ if (costPolicy.maxTokensPerIteration > 0 && iterationTokensUsed > costPolicy.maxTokensPerIteration) {
1435
+ this.emitReasoning(`policy blocked iteration ${iteration}: token usage ${iterationTokensUsed} exceeds maxTokensPerIteration ${costPolicy.maxTokensPerIteration}`);
1436
+ return { reason: "BUDGET_EXHAUSTED", tokensUsed: iterationTokensUsed };
1437
+ }
1438
+ }
1439
+ catch {
1440
+ // Policy engine failure is non-fatal
1441
+ }
1442
+ }
1392
1443
  // Soft context rollover:
1393
1444
  // checkpoint first, then let ContextManager compact instead of aborting/throwing.
1394
1445
  const contextUsageRatio = this.contextManager.getUsageRatio();
1446
+ // Task 1: ContextBudgetManager LLM summarization at 60-70% — runs BEFORE ContextCompressor
1447
+ // Summarizes old "medium" priority conversation turns into a compact summary message,
1448
+ // freeing tokens before the heavier ContextCompressor kicks in at 70%.
1449
+ if (contextUsageRatio >= 0.60 && contextUsageRatio < 0.70 && this.contextBudgetManager) {
1450
+ try {
1451
+ // Sync current messages into the budget manager so it knows what to summarize
1452
+ this.contextBudgetManager.importMessages(this.contextManager.getMessages());
1453
+ if (this.contextBudgetManager.needsSummarization()) {
1454
+ const summary = await this.contextBudgetManager.summarize(async (prompt) => {
1455
+ const resp = await this.llmClient.chat([{ role: "user", content: prompt }], []);
1456
+ return typeof resp.content === "string" ? resp.content : "";
1457
+ });
1458
+ if (summary) {
1459
+ this.emitEvent({
1460
+ kind: "agent:thinking",
1461
+ content: `Context at ${Math.round(contextUsageRatio * 100)}%: summarized ${summary.originalIds.length} old messages (${summary.originalTokens} → ${summary.summarizedTokens} tokens, ${Math.round(summary.compressionRatio * 100)}% ratio).`,
1462
+ });
1463
+ }
1464
+ }
1465
+ }
1466
+ catch {
1467
+ // ContextBudgetManager summarization failure is non-fatal
1468
+ }
1469
+ }
1395
1470
  // Bug 5 fix: use ContextCompressor as an alternative when context pressure is high (>70%)
1396
1471
  // At 70-84% we apply intelligent priority-based compression before falling back to truncation.
1397
1472
  if (contextUsageRatio >= 0.70 && contextUsageRatio < 0.85) {
@@ -1531,15 +1606,7 @@ export class AgentLoop extends EventEmitter {
1531
1606
  // Level 2: Deep verification before declaring completion
1532
1607
  if (this.selfReflection && this.changedFiles.length > 0) {
1533
1608
  try {
1534
- const changedFilesMap = new Map();
1535
- for (const filePath of this.changedFiles) {
1536
- const lastWrite = this.allToolResults
1537
- .filter((r) => r.name === "file_write" || r.name === "file_edit")
1538
- .find((r) => r.output.includes(filePath));
1539
- if (lastWrite) {
1540
- changedFilesMap.set(filePath, lastWrite.output);
1541
- }
1542
- }
1609
+ const changedFilesMap = this.buildChangedFilesMap();
1543
1610
  const verifyFn = async (prompt) => {
1544
1611
  const verifyResponse = await this.llmClient.chat([
1545
1612
  { role: "system", content: "You are a meticulous code reviewer." },
@@ -1625,6 +1692,50 @@ export class AgentLoop extends EventEmitter {
1625
1692
  content: finalSummary,
1626
1693
  });
1627
1694
  }
1695
+ // Task 2: QAPipeline "thorough" mode at final task completion (LLM review included)
1696
+ if (this.changedFiles.length > 0 && this.config.loop.projectPath) {
1697
+ try {
1698
+ const thoroughQA = new QAPipeline({
1699
+ projectPath: this.config.loop.projectPath,
1700
+ level: "thorough",
1701
+ enableStructural: true,
1702
+ enableSemantic: false, // skip tests for speed — structural + quality + review
1703
+ enableQuality: true,
1704
+ enableReview: true,
1705
+ enableDecision: true,
1706
+ autoFix: false,
1707
+ });
1708
+ const thoroughResult = await thoroughQA.run(this.changedFiles, async (prompt) => {
1709
+ try {
1710
+ const reviewResp = await this.llmClient.chat([
1711
+ { role: "system", content: "You are a code reviewer. Review the code changes concisely." },
1712
+ { role: "user", content: prompt },
1713
+ ], []);
1714
+ return typeof reviewResp.content === "string" ? reviewResp.content : "";
1715
+ }
1716
+ catch {
1717
+ return "";
1718
+ }
1719
+ });
1720
+ const thoroughFailures = thoroughResult.stages
1721
+ .flatMap((s) => s.checks)
1722
+ .filter((c) => c.status === "fail");
1723
+ const thoroughIssues = thoroughFailures
1724
+ .slice(0, 10)
1725
+ .map((c) => `[${c.severity}] ${c.name}: ${c.message}`);
1726
+ // Emit structured qa_result event for TUI display
1727
+ this.emitEvent({
1728
+ kind: "agent:qa_result",
1729
+ stage: "thorough",
1730
+ passed: thoroughFailures.length === 0,
1731
+ issues: thoroughIssues,
1732
+ });
1733
+ this.lastQAResult = thoroughResult;
1734
+ }
1735
+ catch {
1736
+ // Thorough QA failure is non-fatal — proceed with completion
1737
+ }
1738
+ }
1628
1739
  this.emitEvent({
1629
1740
  kind: "agent:completed",
1630
1741
  summary: finalSummary,
@@ -1688,6 +1799,105 @@ export class AgentLoop extends EventEmitter {
1688
1799
  content: fixPrompt,
1689
1800
  });
1690
1801
  }
1802
+ // Task 2: QAPipeline — run "quick" (structural only) after any WRITE tool call this iteration
1803
+ const projectPath = this.config.loop.projectPath;
1804
+ if (this.iterationWriteToolPaths.length > 0 && projectPath) {
1805
+ try {
1806
+ const qaPipeline = new QAPipeline({
1807
+ projectPath,
1808
+ level: "quick",
1809
+ enableStructural: true,
1810
+ enableSemantic: false,
1811
+ enableQuality: false,
1812
+ enableReview: false,
1813
+ enableDecision: true,
1814
+ autoFix: false,
1815
+ });
1816
+ const qaResult = await qaPipeline.run(this.iterationWriteToolPaths);
1817
+ this.lastQAResult = qaResult;
1818
+ // Surface QA issues as a system message so LLM sees them next iteration
1819
+ const failedChecks = qaResult.stages
1820
+ .flatMap((s) => s.checks)
1821
+ .filter((c) => c.status === "fail" || c.status === "warn");
1822
+ const qaIssues = failedChecks
1823
+ .slice(0, 10)
1824
+ .map((c) => `[${c.severity}] ${c.name}: ${c.message}`);
1825
+ // Emit structured qa_result event for TUI display
1826
+ this.emitEvent({
1827
+ kind: "agent:qa_result",
1828
+ stage: "quick",
1829
+ passed: failedChecks.length === 0,
1830
+ issues: qaIssues,
1831
+ });
1832
+ if (failedChecks.length > 0 && this.iterationSystemMsgCount < 5) {
1833
+ const checkSummary = failedChecks
1834
+ .slice(0, 5)
1835
+ .map((c) => ` - [${c.severity}] ${c.name}: ${c.message}`)
1836
+ .join("\n");
1837
+ this.contextManager.addMessage({
1838
+ role: "system",
1839
+ content: `[QA Quick Check] ${failedChecks.length} issue(s) detected in modified files:\n${checkSummary}`,
1840
+ });
1841
+ this.iterationSystemMsgCount++;
1842
+ }
1843
+ }
1844
+ catch {
1845
+ // QAPipeline failure is non-fatal
1846
+ }
1847
+ }
1848
+ // Reset per-iteration write tool tracking
1849
+ this.iterationWriteToolPaths = [];
1850
+ // Task 3: Auto-run tsc --noEmit after 2+ TS files modified in this iteration
1851
+ // Skip if tsc was already run in the previous iteration (cooldown)
1852
+ const tscFilesThisIteration = [...this.iterationTsFilesModified];
1853
+ this.iterationTsFilesModified = []; // reset for next iteration
1854
+ const tscRanPrev = this.tscRanLastIteration;
1855
+ this.tscRanLastIteration = false; // will set to true below if we run it
1856
+ if (tscFilesThisIteration.length >= 2 && projectPath && !tscRanPrev) {
1857
+ try {
1858
+ const tscResult = await this.toolExecutor.execute({
1859
+ id: `auto-tsc-${Date.now()}`,
1860
+ name: "shell_exec",
1861
+ arguments: JSON.stringify({
1862
+ command: "npx tsc --noEmit 2>&1 || true",
1863
+ cwd: projectPath,
1864
+ timeout: 60000,
1865
+ }),
1866
+ });
1867
+ this.tscRanLastIteration = true;
1868
+ // Inject TypeScript errors into context so LLM sees them next iteration
1869
+ if (tscResult.success && tscResult.output && tscResult.output.trim().length > 0) {
1870
+ const tscOutput = tscResult.output.trim();
1871
+ // Only inject if there are actual TS errors (output is non-empty)
1872
+ const hasErrors = tscOutput.includes(": error TS") || tscOutput.includes("error TS");
1873
+ if (hasErrors && this.iterationSystemMsgCount < 5) {
1874
+ // Truncate long tsc output to avoid context bloat
1875
+ const truncated = tscOutput.length > 2000
1876
+ ? tscOutput.slice(0, 2000) + "\n[...tsc output truncated]"
1877
+ : tscOutput;
1878
+ this.contextManager.addMessage({
1879
+ role: "system",
1880
+ content: `[Auto-TSC] TypeScript errors detected after modifying ${tscFilesThisIteration.length} files:\n\`\`\`\n${truncated}\n\`\`\`\nPlease fix these type errors.`,
1881
+ });
1882
+ this.iterationSystemMsgCount++;
1883
+ this.emitEvent({
1884
+ kind: "agent:thinking",
1885
+ content: `Auto-TSC: TypeScript errors found after editing ${tscFilesThisIteration.join(", ")}.`,
1886
+ });
1887
+ }
1888
+ else if (!hasErrors) {
1889
+ this.emitEvent({
1890
+ kind: "agent:thinking",
1891
+ content: `Auto-TSC: No type errors after editing ${tscFilesThisIteration.length} file(s).`,
1892
+ });
1893
+ }
1894
+ }
1895
+ }
1896
+ catch {
1897
+ // Auto-tsc failure is non-fatal
1898
+ this.tscRanLastIteration = false;
1899
+ }
1900
+ }
1691
1901
  // iteration 이벤트
1692
1902
  this.emitEvent({
1693
1903
  kind: "agent:iteration",
@@ -1708,20 +1918,41 @@ export class AgentLoop extends EventEmitter {
1708
1918
  };
1709
1919
  await this.sessionPersistence.checkpoint(this.sessionId, checkpoint);
1710
1920
  }
1921
+ // ReflexionEngine: reflect on this iteration's tool results
1922
+ if (this.reflexionEngine && toolResults.length > 0) {
1923
+ try {
1924
+ const iterReflection = this.reflexionEngine.reflect({
1925
+ goal: "",
1926
+ runId: `iter-${iteration}-${randomUUID()}`,
1927
+ termination: { reason: "USER_CANCELLED" },
1928
+ toolResults,
1929
+ messages: this.contextManager.getMessages(),
1930
+ tokensUsed: this.tokenUsage.total,
1931
+ durationMs: Date.now() - iterationStart,
1932
+ changedFiles: this.changedFiles,
1933
+ });
1934
+ // Build insight from available reflection fields
1935
+ const insight = iterReflection.reflection.alternativeApproach ??
1936
+ (iterReflection.reflection.whatFailed.length > 0
1937
+ ? iterReflection.reflection.whatFailed.slice(0, 2).join("; ")
1938
+ : null);
1939
+ if (insight && insight.length > 10 && this.iterationSystemMsgCount < 5) {
1940
+ this.contextManager.addMessage({
1941
+ role: "system",
1942
+ content: `[Reflection] ${insight}`,
1943
+ });
1944
+ this.iterationSystemMsgCount++;
1945
+ }
1946
+ }
1947
+ catch {
1948
+ // Reflection failure is non-fatal
1949
+ }
1950
+ }
1711
1951
  // Level 1: Quick verification after every 3rd iteration
1712
1952
  if (this.selfReflection && iteration % 3 === 0) {
1713
1953
  try {
1714
1954
  this.emitSubagent("verifier", "start", "running quick verification");
1715
- const changedFilesMap = new Map();
1716
- for (const filePath of this.changedFiles) {
1717
- // Collect changed file contents from tool results
1718
- const lastWrite = this.allToolResults
1719
- .filter((r) => r.name === "file_write" || r.name === "file_edit")
1720
- .find((r) => r.output.includes(filePath));
1721
- if (lastWrite) {
1722
- changedFilesMap.set(filePath, lastWrite.output);
1723
- }
1724
- }
1955
+ const changedFilesMap = this.buildChangedFilesMap();
1725
1956
  const quickResult = await this.selfReflection.quickVerify(changedFilesMap, async (prompt) => {
1726
1957
  const verifyResponse = await this.llmClient.chat([
1727
1958
  { role: "system", content: "You are a code verification assistant." },
@@ -1923,6 +2154,28 @@ export class AgentLoop extends EventEmitter {
1923
2154
  await this.saveAutoCheckpoint(iteration);
1924
2155
  this.checkpointSaved = true;
1925
2156
  }
2157
+ // ContinuationEngine: checkpoint current state after each iteration (every 3 iterations, non-fatal)
2158
+ if (this.continuationEngine && iteration > 0 && iteration % 3 === 0 && !this.checkpointSaved) {
2159
+ try {
2160
+ const progress = this.extractProgress();
2161
+ await this.continuationEngine.saveCheckpoint({
2162
+ sessionId: this.sessionId ?? `session-${Date.now()}`,
2163
+ goal: this.contextManager.getMessages().find((m) => m.role === "user")?.content ?? "",
2164
+ progress,
2165
+ changedFiles: [...this.changedFiles].map((p) => ({ path: p, diff: "" })),
2166
+ workingMemory: this.buildWorkingMemorySummary(),
2167
+ yuanMdUpdates: [],
2168
+ errors: [],
2169
+ contextUsageAtSave: this.config.loop.totalTokenBudget > 0 ? this.tokenUsage.total / this.config.loop.totalTokenBudget : 0,
2170
+ totalTokensUsed: this.tokenUsage.total,
2171
+ iterationsCompleted: iteration,
2172
+ createdAt: new Date(),
2173
+ });
2174
+ }
2175
+ catch {
2176
+ // Checkpoint failure is non-fatal
2177
+ }
2178
+ }
1926
2179
  // ContinuousReflection: 매 5 iteration마다 비상 체크포인트 트리거
1927
2180
  // (정기 타이머 외에 iteration 기반 추가 안전망)
1928
2181
  if (this.continuousReflection?.isRunning() &&
@@ -2241,9 +2494,31 @@ export class AgentLoop extends EventEmitter {
2241
2494
  if (!this.changedFiles.includes(filePathStr)) {
2242
2495
  this.changedFiles.push(filePathStr);
2243
2496
  }
2497
+ // Task 2: track write tool paths per-iteration for QA triggering
2498
+ if (!this.iterationWriteToolPaths.includes(filePathStr)) {
2499
+ this.iterationWriteToolPaths.push(filePathStr);
2500
+ }
2501
+ // Task 3: track TS/TSX files modified this iteration for auto-tsc
2502
+ if (filePathStr.match(/\.[cm]?tsx?$/) && !this.iterationTsFilesModified.includes(filePathStr)) {
2503
+ this.iterationTsFilesModified.push(filePathStr);
2504
+ }
2244
2505
  this.emitEvent({ kind: "agent:file_change", path: filePathStr, diff: result.output });
2506
+ // Update world state after file modification
2507
+ if (this.config.loop.projectPath) {
2508
+ const wsProjectPath = this.config.loop.projectPath;
2509
+ new WorldStateCollector({ projectPath: wsProjectPath, skipTest: true })
2510
+ .collect()
2511
+ .then((snapshot) => { this.worldState = snapshot; })
2512
+ .catch(() => {
2513
+ // Non-fatal: world state update failure should not interrupt tool execution
2514
+ });
2515
+ }
2245
2516
  if (this.impactAnalyzer) {
2246
- this.analyzeFileImpact(filePathStr).catch(() => { });
2517
+ this.analyzeFileImpact(filePathStr).catch((err) => {
2518
+ // Non-fatal: impact analysis failure should not interrupt tool execution
2519
+ const msg = err instanceof Error ? err.message : String(err);
2520
+ console.warn(`[AgentLoop] impact analysis skipped for ${filePathStr}: ${msg}`);
2521
+ });
2247
2522
  }
2248
2523
  }
2249
2524
  const fixPrompt = await this.validateAndFeedback(toolCall.name, result);
@@ -2832,6 +3107,22 @@ export class AgentLoop extends EventEmitter {
2832
3107
  }
2833
3108
  }
2834
3109
  // ─── Helpers ───
3110
+ /**
3111
+ * Builds a Map<filePath, toolOutput> for all changed files from write/edit tool results.
3112
+ * Used by selfReflection deepVerify and quickVerify.
3113
+ */
3114
+ buildChangedFilesMap() {
3115
+ const map = new Map();
3116
+ for (const filePath of this.changedFiles) {
3117
+ const lastWrite = this.allToolResults
3118
+ .filter((r) => r.name === "file_write" || r.name === "file_edit")
3119
+ .find((r) => r.output.includes(filePath));
3120
+ if (lastWrite) {
3121
+ map.set(filePath, lastWrite.output);
3122
+ }
3123
+ }
3124
+ return map;
3125
+ }
2835
3126
  emitEvent(event) {
2836
3127
  this.emit("event", event);
2837
3128
  }