@yuaone/core 0.4.9 → 0.6.1
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.
- package/README.md +50 -6
- package/dist/agent-loop.d.ts +5 -27
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +141 -40
- package/dist/agent-loop.js.map +1 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +1 -1
- package/dist/llm-client.d.ts.map +1 -1
- package/dist/llm-client.js +1 -0
- package/dist/llm-client.js.map +1 -1
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +15 -8
- package/dist/security.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,59 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @yuaone/core
|
|
2
2
|
|
|
3
3
|
Agent runtime for YUAN coding agent.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npm install @yuaone/core
|
|
7
|
+
```
|
|
6
8
|
|
|
7
|
-
##
|
|
9
|
+
## Usage
|
|
8
10
|
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
+
```typescript
|
|
12
|
+
import { AgentLoop, createAgentLoop } from "@yuaone/core";
|
|
13
|
+
|
|
14
|
+
const loop = createAgentLoop({
|
|
15
|
+
provider: "anthropic",
|
|
16
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
17
|
+
model: "claude-sonnet-4-6",
|
|
18
|
+
workDir: process.cwd(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
for await (const event of loop.run("refactor auth.ts to async/await")) {
|
|
22
|
+
if (event.kind === "agent:token") process.stdout.write(event.content);
|
|
23
|
+
if (event.kind === "agent:completed") break;
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
| Module | Description |
|
|
30
|
+
|--------|-------------|
|
|
31
|
+
| `AgentLoop` | Core tool-use loop — LLM ↔ tools ↔ approval |
|
|
32
|
+
| `HierarchicalPlanner` | Task decomposition with dependency ordering |
|
|
33
|
+
| `ExecutionPolicyEngine` | Token/cost budget per iteration |
|
|
34
|
+
| `ContinuationEngine` | Checkpoint every 3 iters, recovery on error |
|
|
35
|
+
| `ReflexionEngine` | Per-iteration self-reflection & insight injection |
|
|
36
|
+
| `WorldStateCollector` | Tracks file changes across iterations |
|
|
37
|
+
| `QAPipeline` | Quick + thorough quality checks post-execution |
|
|
38
|
+
| `Governor` | Safety/security scanning before tool execution |
|
|
39
|
+
| `AutoFix` | Automatic lint/type error repair |
|
|
40
|
+
| `ContextManager` | Token budget management & compaction |
|
|
41
|
+
|
|
42
|
+
## Events
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
type AgentEvent =
|
|
46
|
+
| { kind: "agent:thinking"; content: string }
|
|
47
|
+
| { kind: "agent:token"; content: string }
|
|
48
|
+
| { kind: "agent:tool_call"; toolName: string; arguments: unknown }
|
|
49
|
+
| { kind: "agent:tool_result"; toolName: string; result: string; durationMs: number }
|
|
50
|
+
| { kind: "agent:approval_needed"; action: { tool: string; input: unknown } }
|
|
51
|
+
| { kind: "agent:completed"; message: string }
|
|
52
|
+
| { kind: "agent:error"; message: string; retryable: boolean }
|
|
53
|
+
| { kind: "agent:token_usage"; input: number; output: number }
|
|
54
|
+
| { kind: "agent:qa_result"; stage: "quick" | "thorough"; passed: boolean; issues: string[] }
|
|
11
55
|
```
|
|
12
56
|
|
|
13
57
|
## License
|
|
14
58
|
|
|
15
|
-
AGPL-3.0
|
|
59
|
+
AGPL-3.0 — part of [YUAN](https://github.com/yuaone/yuan).
|
package/dist/agent-loop.d.ts
CHANGED
|
@@ -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;
|
|
@@ -419,6 +392,11 @@ export declare class AgentLoop extends EventEmitter {
|
|
|
419
392
|
private handleSoftContextOverflow;
|
|
420
393
|
/** MCP 클라이언트 정리 (세션 종료 시 호출) */
|
|
421
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;
|
|
422
400
|
private emitEvent;
|
|
423
401
|
private emitReasoning;
|
|
424
402
|
private emitSubagent;
|
package/dist/agent-loop.d.ts.map
CHANGED
|
@@ -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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"}
|
package/dist/agent-loop.js
CHANGED
|
@@ -77,6 +77,8 @@ import { QAPipeline } from "./qa-pipeline.js";
|
|
|
77
77
|
* const result = await loop.run("모든 console.log를 제거해줘");
|
|
78
78
|
* ```
|
|
79
79
|
*/
|
|
80
|
+
/** Minimum confidence for classification-based hints/routing to activate */
|
|
81
|
+
const CLASSIFICATION_CONFIDENCE_THRESHOLD = 0.6;
|
|
80
82
|
export class AgentLoop extends EventEmitter {
|
|
81
83
|
abortSignal;
|
|
82
84
|
llmClient;
|
|
@@ -481,7 +483,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
481
483
|
const learnedSkills = this.skillLearner.getAllSkills();
|
|
482
484
|
if (learnedSkills.length > 0) {
|
|
483
485
|
const skillNames = learnedSkills
|
|
484
|
-
.filter((s) => s.confidence >=
|
|
486
|
+
.filter((s) => s.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD)
|
|
485
487
|
.map((s) => s.id);
|
|
486
488
|
if (skillNames.length > 0) {
|
|
487
489
|
this.contextManager.addMessage({
|
|
@@ -615,7 +617,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
615
617
|
buildMemoryContext(memory) {
|
|
616
618
|
const parts = [];
|
|
617
619
|
// 높은 confidence 학습만 포함
|
|
618
|
-
const highConfLearnings = memory.learnings.filter((l) => l.confidence >=
|
|
620
|
+
const highConfLearnings = memory.learnings.filter((l) => l.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD);
|
|
619
621
|
if (highConfLearnings.length > 0) {
|
|
620
622
|
parts.push("## Things I've Learned About This Project");
|
|
621
623
|
for (const l of highConfLearnings.slice(0, 20)) {
|
|
@@ -648,6 +650,8 @@ export class AgentLoop extends EventEmitter {
|
|
|
648
650
|
this.aborted = false;
|
|
649
651
|
this.reasoningAggregator.reset();
|
|
650
652
|
this.reasoningTree.reset();
|
|
653
|
+
// Capture before reset so session snapshot gets accurate file list
|
|
654
|
+
const prevChangedFiles = [...this.changedFiles];
|
|
651
655
|
if (!this.resumedFromSession) {
|
|
652
656
|
this.changedFiles = [];
|
|
653
657
|
this.allToolResults = [];
|
|
@@ -698,7 +702,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
698
702
|
snapshot,
|
|
699
703
|
messages: this.contextManager.getMessages(),
|
|
700
704
|
plan: this.activePlan,
|
|
701
|
-
changedFiles:
|
|
705
|
+
changedFiles: prevChangedFiles,
|
|
702
706
|
});
|
|
703
707
|
}
|
|
704
708
|
// 사용자 입력 검증 (prompt injection 방어)
|
|
@@ -738,7 +742,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
738
742
|
}
|
|
739
743
|
// Task 분류 → 시스템 프롬프트에 tool sequence hint 주입
|
|
740
744
|
const classification = this.taskClassifier.classify(userMessage);
|
|
741
|
-
if (classification.confidence >=
|
|
745
|
+
if (classification.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
|
|
742
746
|
const classificationHint = this.taskClassifier.formatForSystemPrompt(classification);
|
|
743
747
|
this.contextManager.addMessage({
|
|
744
748
|
role: "system",
|
|
@@ -748,7 +752,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
748
752
|
// Specialist routing: 태스크 타입에 맞는 전문 에이전트 설정 주입
|
|
749
753
|
if (classification.specialistDomain) {
|
|
750
754
|
const specialistMatch = this.specialistRegistry.findSpecialist(classification.specialistDomain);
|
|
751
|
-
if (specialistMatch && specialistMatch.confidence >=
|
|
755
|
+
if (specialistMatch && specialistMatch.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
|
|
752
756
|
this.contextManager.addMessage({
|
|
753
757
|
role: "system",
|
|
754
758
|
content: `[Specialist: ${specialistMatch.specialist.name}] ${specialistMatch.specialist.systemPrompt.slice(0, 500)}`,
|
|
@@ -756,13 +760,13 @@ export class AgentLoop extends EventEmitter {
|
|
|
756
760
|
}
|
|
757
761
|
}
|
|
758
762
|
// Tool Planning: 태스크 타입에 맞는 도구 실행 계획 힌트 주입
|
|
759
|
-
if (this.enableToolPlanning && classification.confidence >=
|
|
763
|
+
if (this.enableToolPlanning && classification.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
|
|
760
764
|
const planContext = {
|
|
761
765
|
userMessage,
|
|
762
766
|
};
|
|
763
767
|
this.currentToolPlan = this.toolPlanner.planForTask(classification.type, planContext);
|
|
764
768
|
this.executedToolNames = [];
|
|
765
|
-
if (this.currentToolPlan.confidence >=
|
|
769
|
+
if (this.currentToolPlan.confidence >= CLASSIFICATION_CONFIDENCE_THRESHOLD) {
|
|
766
770
|
const planHint = this.toolPlanner.formatPlanHint(this.currentToolPlan);
|
|
767
771
|
this.contextManager.addMessage({
|
|
768
772
|
role: "system",
|
|
@@ -903,6 +907,18 @@ export class AgentLoop extends EventEmitter {
|
|
|
903
907
|
return result;
|
|
904
908
|
}
|
|
905
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
|
+
}
|
|
906
922
|
return this.handleFatalError(err);
|
|
907
923
|
}
|
|
908
924
|
}
|
|
@@ -1409,7 +1425,21 @@ export class AgentLoop extends EventEmitter {
|
|
|
1409
1425
|
this.iterationCount = iteration;
|
|
1410
1426
|
const iterationStart = Date.now();
|
|
1411
1427
|
this.emitReasoning(`iteration ${iteration}: preparing context`);
|
|
1412
|
-
this.iterationSystemMsgCount = 0; // Reset per-iteration
|
|
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
|
+
}
|
|
1413
1443
|
// Soft context rollover:
|
|
1414
1444
|
// checkpoint first, then let ContextManager compact instead of aborting/throwing.
|
|
1415
1445
|
const contextUsageRatio = this.contextManager.getUsageRatio();
|
|
@@ -1576,15 +1606,7 @@ export class AgentLoop extends EventEmitter {
|
|
|
1576
1606
|
// Level 2: Deep verification before declaring completion
|
|
1577
1607
|
if (this.selfReflection && this.changedFiles.length > 0) {
|
|
1578
1608
|
try {
|
|
1579
|
-
const changedFilesMap =
|
|
1580
|
-
for (const filePath of this.changedFiles) {
|
|
1581
|
-
const lastWrite = this.allToolResults
|
|
1582
|
-
.filter((r) => r.name === "file_write" || r.name === "file_edit")
|
|
1583
|
-
.find((r) => r.output.includes(filePath));
|
|
1584
|
-
if (lastWrite) {
|
|
1585
|
-
changedFilesMap.set(filePath, lastWrite.output);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1609
|
+
const changedFilesMap = this.buildChangedFilesMap();
|
|
1588
1610
|
const verifyFn = async (prompt) => {
|
|
1589
1611
|
const verifyResponse = await this.llmClient.chat([
|
|
1590
1612
|
{ role: "system", content: "You are a meticulous code reviewer." },
|
|
@@ -1698,9 +1720,15 @@ export class AgentLoop extends EventEmitter {
|
|
|
1698
1720
|
const thoroughFailures = thoroughResult.stages
|
|
1699
1721
|
.flatMap((s) => s.checks)
|
|
1700
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
|
|
1701
1727
|
this.emitEvent({
|
|
1702
|
-
kind: "agent:
|
|
1703
|
-
|
|
1728
|
+
kind: "agent:qa_result",
|
|
1729
|
+
stage: "thorough",
|
|
1730
|
+
passed: thoroughFailures.length === 0,
|
|
1731
|
+
issues: thoroughIssues,
|
|
1704
1732
|
});
|
|
1705
1733
|
this.lastQAResult = thoroughResult;
|
|
1706
1734
|
}
|
|
@@ -1791,6 +1819,16 @@ export class AgentLoop extends EventEmitter {
|
|
|
1791
1819
|
const failedChecks = qaResult.stages
|
|
1792
1820
|
.flatMap((s) => s.checks)
|
|
1793
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
|
+
});
|
|
1794
1832
|
if (failedChecks.length > 0 && this.iterationSystemMsgCount < 5) {
|
|
1795
1833
|
const checkSummary = failedChecks
|
|
1796
1834
|
.slice(0, 5)
|
|
@@ -1801,16 +1839,6 @@ export class AgentLoop extends EventEmitter {
|
|
|
1801
1839
|
content: `[QA Quick Check] ${failedChecks.length} issue(s) detected in modified files:\n${checkSummary}`,
|
|
1802
1840
|
});
|
|
1803
1841
|
this.iterationSystemMsgCount++;
|
|
1804
|
-
this.emitEvent({
|
|
1805
|
-
kind: "agent:thinking",
|
|
1806
|
-
content: `QA quick check: ${failedChecks.length} issue(s) in ${this.iterationWriteToolPaths.length} file(s).`,
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
else if (failedChecks.length === 0) {
|
|
1810
|
-
this.emitEvent({
|
|
1811
|
-
kind: "agent:thinking",
|
|
1812
|
-
content: `QA quick check passed for ${this.iterationWriteToolPaths.length} file(s).`,
|
|
1813
|
-
});
|
|
1814
1842
|
}
|
|
1815
1843
|
}
|
|
1816
1844
|
catch {
|
|
@@ -1890,20 +1918,41 @@ export class AgentLoop extends EventEmitter {
|
|
|
1890
1918
|
};
|
|
1891
1919
|
await this.sessionPersistence.checkpoint(this.sessionId, checkpoint);
|
|
1892
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
|
+
}
|
|
1893
1951
|
// Level 1: Quick verification after every 3rd iteration
|
|
1894
1952
|
if (this.selfReflection && iteration % 3 === 0) {
|
|
1895
1953
|
try {
|
|
1896
1954
|
this.emitSubagent("verifier", "start", "running quick verification");
|
|
1897
|
-
const changedFilesMap =
|
|
1898
|
-
for (const filePath of this.changedFiles) {
|
|
1899
|
-
// Collect changed file contents from tool results
|
|
1900
|
-
const lastWrite = this.allToolResults
|
|
1901
|
-
.filter((r) => r.name === "file_write" || r.name === "file_edit")
|
|
1902
|
-
.find((r) => r.output.includes(filePath));
|
|
1903
|
-
if (lastWrite) {
|
|
1904
|
-
changedFilesMap.set(filePath, lastWrite.output);
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1955
|
+
const changedFilesMap = this.buildChangedFilesMap();
|
|
1907
1956
|
const quickResult = await this.selfReflection.quickVerify(changedFilesMap, async (prompt) => {
|
|
1908
1957
|
const verifyResponse = await this.llmClient.chat([
|
|
1909
1958
|
{ role: "system", content: "You are a code verification assistant." },
|
|
@@ -2105,6 +2154,28 @@ export class AgentLoop extends EventEmitter {
|
|
|
2105
2154
|
await this.saveAutoCheckpoint(iteration);
|
|
2106
2155
|
this.checkpointSaved = true;
|
|
2107
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
|
+
}
|
|
2108
2179
|
// ContinuousReflection: 매 5 iteration마다 비상 체크포인트 트리거
|
|
2109
2180
|
// (정기 타이머 외에 iteration 기반 추가 안전망)
|
|
2110
2181
|
if (this.continuousReflection?.isRunning() &&
|
|
@@ -2432,8 +2503,22 @@ export class AgentLoop extends EventEmitter {
|
|
|
2432
2503
|
this.iterationTsFilesModified.push(filePathStr);
|
|
2433
2504
|
}
|
|
2434
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
|
+
}
|
|
2435
2516
|
if (this.impactAnalyzer) {
|
|
2436
|
-
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
|
+
});
|
|
2437
2522
|
}
|
|
2438
2523
|
}
|
|
2439
2524
|
const fixPrompt = await this.validateAndFeedback(toolCall.name, result);
|
|
@@ -3022,6 +3107,22 @@ export class AgentLoop extends EventEmitter {
|
|
|
3022
3107
|
}
|
|
3023
3108
|
}
|
|
3024
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
|
+
}
|
|
3025
3126
|
emitEvent(event) {
|
|
3026
3127
|
this.emit("event", event);
|
|
3027
3128
|
}
|