full-stack-coding-assistant-agent 0.1.0__py3-none-any.whl

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.
agents/base_agent.py ADDED
@@ -0,0 +1,406 @@
1
+ """
2
+ Agent 基类 - 定义所有智能体的通用接口
3
+ """
4
+
5
+ import re
6
+ from abc import ABC, abstractmethod
7
+ from pathlib import Path
8
+ from typing import Dict, List, Optional
9
+
10
+ from model.model_router import ModelRouter
11
+ from storage.context_db import ContextDB
12
+
13
+
14
+ class BaseAgent(ABC):
15
+ """智能体抽象基类"""
16
+
17
+ def __init__(
18
+ self,
19
+ agent_type: str,
20
+ model_router: ModelRouter,
21
+ db: ContextDB,
22
+ ):
23
+ """
24
+ 初始化 Agent
25
+
26
+ Args:
27
+ agent_type: Agent 类型标识 (frontend/backend/test/audit)
28
+ model_router: 模型路由器实例
29
+ db: 数据库实例
30
+ """
31
+ self.agent_type = agent_type
32
+ self.model_router = model_router
33
+ self.db = db
34
+ self.model = self.model_router.get_model_for_agent(agent_type)
35
+ self._output_dir: Optional[Path] = None # 输出目录,由 Coordinator 注入
36
+ self._usage_log: List[Dict] = [] # 每步 LLM 调用的 token 用量记录
37
+
38
+ @abstractmethod
39
+ def get_system_prompt(self) -> str:
40
+ """获取系统提示词 - 子类必须实现"""
41
+ pass
42
+
43
+ @abstractmethod
44
+ def execute(self, task_id: str, context: Dict) -> Dict:
45
+ """
46
+ 执行任务 - 子类必须实现
47
+
48
+ Args:
49
+ task_id: 任务 ID
50
+ context: 任务上下文(包含依赖的任务结果)
51
+
52
+ Returns:
53
+ 执行结果字典
54
+ """
55
+ pass
56
+
57
+ def _call_llm(self, user_prompt: str, temperature: float = 0.7) -> str:
58
+ """
59
+ 调用 LLM 的通用方法
60
+
61
+ Args:
62
+ user_prompt: 用户提示词
63
+ temperature: 温度参数
64
+
65
+ Returns:
66
+ 模型生成的文本
67
+ """
68
+ messages = [
69
+ {"role": "system", "content": self.get_system_prompt()},
70
+ {"role": "user", "content": user_prompt},
71
+ ]
72
+ result = self.model_router.chat(
73
+ messages=messages,
74
+ model=self.model,
75
+ temperature=temperature,
76
+ )
77
+
78
+ # 记录 token 用量
79
+ usage = result.get("usage", {})
80
+ if usage:
81
+ self._usage_log.append(
82
+ {
83
+ "step": len(self._usage_log) + 1,
84
+ "model": result.get("model", self.model),
85
+ "prompt_tokens": usage.get("prompt_tokens", 0),
86
+ "completion_tokens": usage.get("completion_tokens", 0),
87
+ "total_tokens": usage.get("total_tokens", 0),
88
+ "latency_ms": result.get("latency_ms", 0),
89
+ }
90
+ )
91
+
92
+ return result["content"]
93
+
94
+ def _check_dependencies(
95
+ self,
96
+ context: Dict,
97
+ required_keys: List[str],
98
+ ) -> bool:
99
+ """
100
+ 检查任务依赖是否满足
101
+
102
+ Args:
103
+ context: 任务上下文
104
+ required_keys: 必需的上下文键列表
105
+
106
+ Returns:
107
+ 是否满足所有依赖
108
+ """
109
+ for key in required_keys:
110
+ if key not in context:
111
+ return False
112
+ return True
113
+
114
+ def _log_change(
115
+ self,
116
+ task_id: str,
117
+ file_path: str,
118
+ change_type: str,
119
+ diff: Optional[str] = None,
120
+ ):
121
+ """记录代码变更到数据库"""
122
+ self.db.log_code_change(
123
+ task_id=task_id,
124
+ agent_type=self.agent_type,
125
+ file_path=file_path,
126
+ change_type=change_type,
127
+ diff=diff,
128
+ )
129
+
130
+ def _save_result(self, task_id: str, result: str):
131
+ """保存任务结果到数据库"""
132
+ self.db.update_task_status(
133
+ task_id=task_id,
134
+ status="completed",
135
+ result=result,
136
+ )
137
+
138
+ # ------------------------------------------------------------------ #
139
+ # 输出目录相关方法(由 Coordinator 注入 output_dir)
140
+ # ------------------------------------------------------------------ #
141
+
142
+ def _set_output_dir(self, output_dir: Path):
143
+ """设置输出目录(由 Coordinator 在初始化后调用)"""
144
+ self._output_dir = output_dir
145
+
146
+ def _get_sub_dir(self) -> str:
147
+ """
148
+ 返回当前 Agent 对应的子目录名
149
+ 子类可重写,默认使用 agent_type
150
+ """
151
+ return self.agent_type
152
+
153
+ def _write_file(self, rel_path: str, content: str):
154
+ """
155
+ 将内容写入输出目录下的指定相对路径
156
+
157
+ 仅在 _output_dir 已设置时实际写入文件系统;
158
+ 否则仅记录日志(向后兼容)。
159
+
160
+ Args:
161
+ rel_path: 相对路径,如 "backend/main.py"
162
+ content: 文件内容
163
+ """
164
+ if self._output_dir is None:
165
+ # 向后兼容:未设置输出目录时不写入文件
166
+ return
167
+
168
+ file_path = self._output_dir / rel_path
169
+ file_path.parent.mkdir(parents=True, exist_ok=True)
170
+ file_path.write_text(content, encoding="utf-8")
171
+
172
+ def _read_file(self, rel_path: str) -> str:
173
+ """
174
+ 读取输出目录下的指定文件
175
+
176
+ Args:
177
+ rel_path: 相对路径
178
+
179
+ Returns:
180
+ 文件内容;文件不存在时返回空字符串
181
+ """
182
+ if self._output_dir is None:
183
+ return ""
184
+
185
+ file_path = self._output_dir / rel_path
186
+ if not file_path.exists():
187
+ return ""
188
+ return file_path.read_text(encoding="utf-8", errors="replace")
189
+
190
+ def _collect_existing_code(self) -> str:
191
+ """
192
+ 收集当前 Agent 对应子目录下所有已有代码,
193
+ 用于构建迭代模式的 LLM prompt 上下文
194
+
195
+ Returns:
196
+ 格式化的代码块字符串,每个文件用 ### FILE: 标记
197
+ """
198
+ if self._output_dir is None:
199
+ return ""
200
+
201
+ sub_dir = self._output_dir / self._get_sub_dir()
202
+ if not sub_dir.exists():
203
+ return ""
204
+
205
+ parts = []
206
+ for file_path in sorted(sub_dir.rglob("*")):
207
+ if file_path.is_file():
208
+ rel = file_path.relative_to(self._output_dir)
209
+ content = file_path.read_text(encoding="utf-8", errors="replace")
210
+ parts.append(f"### FILE: {rel}\n{content}\n")
211
+ return "\n".join(parts)
212
+
213
+ def _save_trace(
214
+ self,
215
+ task_id: str,
216
+ system_prompt: str,
217
+ user_prompt: str,
218
+ llm_response: str,
219
+ parsed_result: Dict,
220
+ ):
221
+ """
222
+ 保存 Agent 执行 trace 到输出目录
223
+
224
+ 记录完整的 LLM 输入输出以及 token 用量,以便审计和验证 Agent 的每一步行为。
225
+
226
+ Args:
227
+ task_id: 任务 ID
228
+ system_prompt: 系统提示词
229
+ user_prompt: 发送给 LLM 的完整用户提示词
230
+ llm_response: LLM 的原始返回
231
+ parsed_result: 解析后的结果(files, contracts 等)
232
+ """
233
+ if self._output_dir is None:
234
+ return
235
+
236
+ from datetime import datetime
237
+
238
+ traces_dir = self._output_dir / "traces" / self.agent_type
239
+ traces_dir.mkdir(parents=True, exist_ok=True)
240
+
241
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
242
+ filename = f"{timestamp}_{task_id}.md"
243
+ file_path = traces_dir / filename
244
+
245
+ # 构建 token 用量部分
246
+ usage_lines = self._build_usage_section()
247
+
248
+ # 构建解析结果部分
249
+ parsed_lines = []
250
+ if parsed_result.get("files"):
251
+ parsed_lines.append("### 生成/修改的文件")
252
+ for f in parsed_result["files"]:
253
+ parsed_lines.append(f"- `{f}`")
254
+ parsed_lines.append("")
255
+ if parsed_result.get("contracts"):
256
+ parsed_lines.append("### 提取的 API 契约")
257
+ for c in parsed_result["contracts"]:
258
+ parsed_lines.append(
259
+ f"- **{c.get('method', '?')} {c.get('endpoint', '?')}**"
260
+ )
261
+ parsed_lines.append("")
262
+ if parsed_result.get("reports_count") is not None:
263
+ parsed_lines.append(
264
+ f"- 发现问题数: {parsed_result.get('reports_count', 0)}"
265
+ )
266
+ parsed_lines.append(f"- 高危问题: {parsed_result.get('high_severity', 0)}")
267
+ parsed_lines.append("")
268
+ if parsed_result.get("status"):
269
+ parsed_lines.append(f"- 状态: {parsed_result['status']}")
270
+ parsed_lines.append("")
271
+
272
+ content = f"""# Agent Trace: {self.agent_type}
273
+
274
+ - **时间**: {datetime.now().isoformat()}
275
+ - **任务ID**: {task_id}
276
+ - **Agent 类型**: {self.agent_type}
277
+
278
+ ---
279
+
280
+ {usage_lines}
281
+
282
+ ---
283
+
284
+ ## 系统提示词 (System Prompt)
285
+
286
+ {system_prompt}
287
+
288
+ ---
289
+
290
+ ## 用户提示词 (User Prompt, sent to LLM)
291
+
292
+ {user_prompt}
293
+
294
+ ---
295
+
296
+ ## LLM 原始输出 (Raw Response)
297
+
298
+ {llm_response}
299
+
300
+ ---
301
+
302
+ ## 解析结果 (Parsed Result)
303
+
304
+ {chr(10).join(parsed_lines) if parsed_lines else '(无解析结果)'}
305
+
306
+ ---
307
+ """
308
+ file_path.write_text(content, encoding="utf-8")
309
+
310
+ def _build_usage_section(self) -> str:
311
+ """构建 token 用量报告 Markdown 段"""
312
+ if not self._usage_log:
313
+ return "## Token 用量\n\n(无用量数据)"
314
+
315
+ lines = [
316
+ "## Token 用量",
317
+ "",
318
+ "| Step | 模型 | Prompt Tokens | Completion Tokens | Total Tokens | 耗时(ms) |",
319
+ "|------|------|---------------|-------------------|--------------|----------|",
320
+ ]
321
+ total_prompt = 0
322
+ total_completion = 0
323
+ total_tokens = 0
324
+ total_latency = 0.0
325
+ for entry in self._usage_log:
326
+ lines.append(
327
+ f"| {entry['step']} | {entry['model']} "
328
+ f"| {entry['prompt_tokens']:,} "
329
+ f"| {entry['completion_tokens']:,} "
330
+ f"| {entry['total_tokens']:,} "
331
+ f"| {entry['latency_ms']} |"
332
+ )
333
+ total_prompt += entry["prompt_tokens"]
334
+ total_completion += entry["completion_tokens"]
335
+ total_tokens += entry["total_tokens"]
336
+ total_latency += entry.get("latency_ms", 0)
337
+
338
+ lines.append(
339
+ f"| **合计** | — "
340
+ f"| **{total_prompt:,}** "
341
+ f"| **{total_completion:,}** "
342
+ f"| **{total_tokens:,}** "
343
+ f"| **{total_latency:.0f}** |"
344
+ )
345
+ return "\n".join(lines)
346
+
347
+ def get_usage_summary(self) -> Dict:
348
+ """
349
+ 获取当前 Agent 的 token 用量汇总
350
+
351
+ Returns:
352
+ 字典: {
353
+ "agent_type": str,
354
+ "steps": int,
355
+ "total_prompt_tokens": int,
356
+ "total_completion_tokens": int,
357
+ "total_tokens": int,
358
+ "total_latency_ms": float,
359
+ "details": List[Dict],
360
+ }
361
+ """
362
+ total_prompt = sum(e["prompt_tokens"] for e in self._usage_log)
363
+ total_completion = sum(e["completion_tokens"] for e in self._usage_log)
364
+ total_tokens = sum(e["total_tokens"] for e in self._usage_log)
365
+ total_latency = sum(e.get("latency_ms", 0) for e in self._usage_log)
366
+
367
+ return {
368
+ "agent_type": self.agent_type,
369
+ "steps": len(self._usage_log),
370
+ "total_prompt_tokens": total_prompt,
371
+ "total_completion_tokens": total_completion,
372
+ "total_tokens": total_tokens,
373
+ "total_latency_ms": round(total_latency, 1),
374
+ "details": list(self._usage_log),
375
+ }
376
+
377
+ def _parse_llm_code_output(self, text: str) -> Dict[str, str]:
378
+ """
379
+ 解析 LLM 返回内容中的文件块
380
+
381
+ 期望格式:
382
+ ### FILE: path/to/file.py
383
+ ```python
384
+ # code here
385
+ ```
386
+
387
+ 也支持无代码块包裹的纯代码(直到下一个 ### FILE: 或文件结束)。
388
+
389
+ Returns:
390
+ 字典 {相对文件路径: 文件内容}
391
+ """
392
+ result: Dict[str, str] = {}
393
+ pattern = r"### FILE:\s*(\S+)\n(.*?)(?=\n### FILE:|\Z)"
394
+ matches = re.findall(pattern, text, re.DOTALL)
395
+
396
+ if not matches:
397
+ # 无法解析出多文件,整段内容作为单个文件
398
+ return {"output.txt": text.strip()}
399
+
400
+ for file_path, content in matches:
401
+ # 去掉代码块标记(``` 包裹)
402
+ cleaned = re.sub(r"```[\w]*\n?", "", content)
403
+ cleaned = re.sub(r"```\s*$", "", cleaned)
404
+ result[file_path.strip()] = cleaned.strip()
405
+
406
+ return result
@@ -0,0 +1,148 @@
1
+ """
2
+ 前端专家智能体
3
+ 负责生成前端组件代码,并根据后端 API 契约调整接口调用
4
+ """
5
+
6
+ from typing import Dict
7
+
8
+ from agents.base_agent import BaseAgent
9
+
10
+
11
+ class FrontendAgent(BaseAgent):
12
+ """前端专家 Agent"""
13
+
14
+ def get_system_prompt(self) -> str:
15
+ return """你是一位资深前端开发专家,精通 React/Vue/Angular 等主流框架。
16
+ 你的职责是:
17
+ 1. 根据 UI 需求生成高质量的前端组件代码
18
+ 2. 编写类型安全的 TypeScript 代码
19
+ 3. 实现响应式布局和交互逻辑
20
+ 4. 根据后端 API 契约生成接口调用代码
21
+
22
+ 输出格式要求:
23
+ - 每个文件用 ### FILE: 标记,格式如下:
24
+ ### FILE: frontend/App.tsx
25
+ ```tsx
26
+ // code here
27
+ ```
28
+ - 使用函数式组件和 Hooks
29
+ - 包含完整的 TypeScript 类型定义
30
+ - 代码必须可直接运行
31
+
32
+ 【重要】必须同时生成前端项目的工程配置文件,让项目可以 npm install && npm start 直接运行:
33
+ - frontend/package.json(含 react、react-dom、react-scripts 等必要依赖)
34
+ - frontend/tsconfig.json
35
+ - frontend/public/index.html(入口 HTML)
36
+ """
37
+
38
+ def execute(self, task_id: str, context: Dict) -> Dict:
39
+ """
40
+ 执行前端开发任务
41
+
42
+ 流程:
43
+ 1. 获取后端 API 契约(如果有)
44
+ 2. 如果是迭代模式,读取已有代码注入 prompt
45
+ 3. 调用 LLM 生成前端代码
46
+ 4. 解析多文件输出并写入文件系统
47
+ 5. 记录代码变更
48
+ """
49
+ # 1. 获取 API 契约
50
+ api_contracts = self.db.get_api_contracts(task_id)
51
+ contracts_str = ""
52
+ if api_contracts:
53
+ contracts_str = "\n## 后端 API 契约(必须严格按照此契约调用接口)\n"
54
+ for contract in api_contracts:
55
+ contracts_str += f"""
56
+ ### {contract['method']} {contract['endpoint']}
57
+ - 请求 Schema: {contract.get('request_schema', '无')}
58
+ - 响应 Schema: {contract.get('response_schema', '无')}
59
+ """
60
+
61
+ description = context.get("description", "")
62
+ requirements = context.get("requirements", "")
63
+ is_iteration = context.get("is_iteration", False)
64
+
65
+ # 2. 构建 prompt
66
+ prompt = f"""请根据以下需求生成前端代码:
67
+
68
+ ## 需求描述
69
+ {description}
70
+
71
+ ## 详细要求
72
+ {requirements}
73
+ {contracts_str}
74
+ """
75
+
76
+ # 迭代模式:注入已有代码
77
+ if is_iteration:
78
+ existing_code = self._collect_existing_code()
79
+ if existing_code:
80
+ prompt += f"""
81
+ ## 已有代码(请基于以下代码进行修改,不要重复生成未修改的文件)
82
+ {existing_code}
83
+ """
84
+
85
+ prompt += """
86
+ 请生成完整的前端代码,每个文件用 ### FILE: 标记,格式如下:
87
+
88
+ ### FILE: frontend/App.tsx
89
+ ```tsx
90
+ // code here
91
+ ```
92
+
93
+ ### FILE: frontend/components/Login.tsx
94
+ ```tsx
95
+ // code here
96
+ ```
97
+
98
+ 代码要求:
99
+ - 使用函数式组件和 Hooks
100
+ - 完整的 TypeScript 类型定义
101
+ - 包含错误处理和加载状态
102
+ - 使用 Tailwind CSS 做样式
103
+
104
+ 【必须生成以下工程配置文件,否则项目无法运行】:
105
+ ### FILE: frontend/package.json
106
+ 包含完整的 dependencies(react, react-dom, react-scripts 等)和 scripts(start, build, test)
107
+
108
+ ### FILE: frontend/tsconfig.json
109
+ TypeScript 配置,target 为 ES2020,jsx 为 react-jsx,strict 模式
110
+
111
+ ### FILE: frontend/public/index.html
112
+ React 入口 HTML 文件
113
+ """
114
+
115
+ # 3. 调用 LLM 生成代码
116
+ system_prompt = self.get_system_prompt()
117
+ code_result = self._call_llm(prompt, temperature=0.3)
118
+
119
+ # 4. 解析多文件输出并写入文件系统
120
+ files = self._parse_llm_code_output(code_result)
121
+ change_type = "update" if is_iteration else "create"
122
+ for file_path, content in files.items():
123
+ self._write_file(file_path, content)
124
+ self._log_change(
125
+ task_id=task_id,
126
+ file_path=file_path,
127
+ change_type=change_type,
128
+ diff=content,
129
+ )
130
+
131
+ # 5. 保存结果
132
+ result = {
133
+ "status": "success",
134
+ "files": list(files.keys()),
135
+ "api_contracts_used": len(api_contracts),
136
+ }
137
+
138
+ # 6. 保存 Agent 执行 trace(完整 I/O 审计)
139
+ self._save_trace(
140
+ task_id=task_id,
141
+ system_prompt=system_prompt,
142
+ user_prompt=prompt,
143
+ llm_response=code_result,
144
+ parsed_result=result,
145
+ )
146
+ self._save_result(task_id, str(result))
147
+
148
+ return result
agents/test_agent.py ADDED
@@ -0,0 +1,155 @@
1
+ """
2
+ 测试专家智能体
3
+ 负责生成单元测试、集成测试代码
4
+ """
5
+
6
+ from typing import Dict
7
+
8
+ from agents.base_agent import BaseAgent
9
+
10
+
11
+ class TestAgent(BaseAgent):
12
+ """测试专家 Agent"""
13
+
14
+ def get_system_prompt(self) -> str:
15
+ return """你是一位资深测试开发专家,精通单元测试、集成测试和 E2E 测试。
16
+ 你的职责是:
17
+ 1. 为前端组件生成单元测试(Jest + React Testing Library)
18
+ 2. 为后端 API 生成集成测试
19
+ 3. 编写测试用例覆盖正常和异常场景
20
+ 4. 确保测试代码的可维护性和可读性
21
+
22
+ 输出格式要求:
23
+ - 每个文件用 ### FILE: 标记,格式如下:
24
+ ### FILE: tests/test_api.py
25
+ ```python
26
+ # code here
27
+ ```
28
+ - 测试用例必须完整覆盖主要逻辑分支
29
+ - 包含 Mock 数据和方法
30
+ - 测试代码必须可直接运行
31
+
32
+ 【重要】如果生成了前端测试(.tsx/.ts 文件),也必须生成测试运行所需的配置文件:
33
+ - frontend/jest.config.js(或 package.json 中的 jest 配置节)
34
+ - frontend/src/setupTests.ts(Jest setup 文件,导入 @testing-library/jest-dom)
35
+ """
36
+
37
+ def execute(self, task_id: str, context: Dict) -> Dict:
38
+ """
39
+ 执行测试生成任务
40
+
41
+ 流程:
42
+ 1. 获取前后端代码
43
+ 2. 如果是迭代模式,读取已有测试代码注入 prompt
44
+ 3. 调用 LLM 生成测试代码
45
+ 4. 解析多文件输出并写入文件系统
46
+ 5. 记录代码变更
47
+ """
48
+ # 1. 获取前后端代码
49
+ frontend_code = context.get("frontend_code", "")
50
+ backend_code = context.get("backend_code", "")
51
+ is_iteration = context.get("is_iteration", False)
52
+
53
+ # 2. 构建 prompt
54
+ prompt = f"""请为以下代码生成完整的测试:
55
+
56
+ ## 前端代码
57
+ ```tsx
58
+ {frontend_code}
59
+ ```
60
+
61
+ ## 后端代码
62
+ ```python
63
+ {backend_code}
64
+ ```
65
+ """
66
+
67
+ # 迭代模式:注入已有测试代码
68
+ if is_iteration:
69
+ existing_code = self._collect_existing_code()
70
+ if existing_code:
71
+ prompt += f"""
72
+ ## 已有测试代码(请基于以下代码进行补充或修改)
73
+ {existing_code}
74
+ """
75
+
76
+ prompt += """
77
+ 请生成:
78
+ 1. 前端单元测试(使用 Jest + React Testing Library)——注意放在 frontend/src/ 下
79
+ 2. 后端 API 集成测试(使用 pytest)
80
+ 3. Mock 数据和辅助函数
81
+ 4. 测试运行所需的配置文件(如 jest.config.js、setupTests.ts)
82
+
83
+ 每个文件用 ### FILE: 标记,格式如下:
84
+
85
+ 后端测试(放在 tests/ 目录):
86
+ ### FILE: tests/test_api.py
87
+ ```python
88
+ # code here
89
+ ```
90
+
91
+ 前端测试(放在 frontend/src/ 目录,文件名以 .test.tsx 结尾以匹配 CRA/Jest 约定):
92
+ ### FILE: frontend/src/__tests__/ComponentName.test.tsx
93
+ ```tsx
94
+ // code here
95
+ ```
96
+
97
+ 或直接放在 frontend/src/ 下:
98
+ ### FILE: frontend/src/components.test.tsx
99
+ ```tsx
100
+ // code here
101
+ ```
102
+
103
+ 【如果生成了前端测试,必须同时生成以下配置文件】:
104
+ ### FILE: frontend/jest.config.js
105
+ ```js
106
+ module.exports = {
107
+ testEnvironment: 'jsdom',
108
+ setupFilesAfterSetup: ['<rootDir>/src/setupTests.ts'],
109
+ };
110
+ ```
111
+
112
+ ### FILE: frontend/src/setupTests.ts
113
+ ```ts
114
+ import '@testing-library/jest-dom';
115
+ ```
116
+
117
+ 测试要求:
118
+ - 覆盖正常流程和异常流程
119
+ - 包含边界条件测试
120
+ - 测试代码可直接运行
121
+ """
122
+
123
+ # 3. 调用 LLM 生成测试
124
+ system_prompt = self.get_system_prompt()
125
+ test_code = self._call_llm(prompt, temperature=0.3)
126
+
127
+ # 4. 解析多文件输出并写入文件系统
128
+ files = self._parse_llm_code_output(test_code)
129
+ change_type = "update" if is_iteration else "create"
130
+ for file_path, content in files.items():
131
+ self._write_file(file_path, content)
132
+ self._log_change(
133
+ task_id=task_id,
134
+ file_path=file_path,
135
+ change_type=change_type,
136
+ diff=content,
137
+ )
138
+
139
+ # 5. 保存结果
140
+ result = {
141
+ "status": "success",
142
+ "files": list(files.keys()),
143
+ }
144
+
145
+ # 6. 保存 Agent 执行 trace(完整 I/O 审计)
146
+ self._save_trace(
147
+ task_id=task_id,
148
+ system_prompt=system_prompt,
149
+ user_prompt=prompt,
150
+ llm_response=test_code,
151
+ parsed_result=result,
152
+ )
153
+ self._save_result(task_id, str(result))
154
+
155
+ return result
File without changes