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/__init__.py +0 -0
- agents/audit_agent.py +223 -0
- agents/backend_agent.py +179 -0
- agents/base_agent.py +406 -0
- agents/frontend_agent.py +148 -0
- agents/test_agent.py +155 -0
- coordinator/__init__.py +0 -0
- coordinator/coordinator.py +452 -0
- coordinator/dag.py +147 -0
- executor/__init__.py +0 -0
- executor/cb_integration.py +160 -0
- full_stack_coding_assistant_agent/__init__.py +6 -0
- full_stack_coding_assistant_agent/cli.py +10 -0
- full_stack_coding_assistant_agent/main.py +686 -0
- full_stack_coding_assistant_agent-0.1.0.dist-info/METADATA +849 -0
- full_stack_coding_assistant_agent-0.1.0.dist-info/RECORD +31 -0
- full_stack_coding_assistant_agent-0.1.0.dist-info/WHEEL +5 -0
- full_stack_coding_assistant_agent-0.1.0.dist-info/entry_points.txt +2 -0
- full_stack_coding_assistant_agent-0.1.0.dist-info/top_level.txt +7 -0
- model/__init__.py +0 -0
- model/config.py +62 -0
- model/model_router.py +150 -0
- storage/__init__.py +0 -0
- storage/context_db.py +274 -0
- utils/__init__.py +0 -0
- utils/agent_selector.py +243 -0
- utils/config_validator.py +143 -0
- utils/logger.py +95 -0
- utils/output_manager.py +1572 -0
- utils/pdf_reader.py +122 -0
- utils/version.py +188 -0
agents/__init__.py
ADDED
|
File without changes
|
agents/audit_agent.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""
|
|
2
|
+
代码审计智能体
|
|
3
|
+
异步执行安全扫描、代码质量检查
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Dict, List
|
|
10
|
+
|
|
11
|
+
from agents.base_agent import BaseAgent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuditAgent(BaseAgent):
|
|
15
|
+
"""代码审计专家 Agent"""
|
|
16
|
+
|
|
17
|
+
def get_system_prompt(self) -> str:
|
|
18
|
+
return """你是一位资深代码安全审计专家,精通 OWASP Top 10、代码质量分析。
|
|
19
|
+
你的职责是:
|
|
20
|
+
1. 检查代码安全漏洞(SQL 注入、XSS、CSRF 等)
|
|
21
|
+
2. 分析代码质量和最佳实践
|
|
22
|
+
3. 检查敏感信息泄露(API Key、密码等)
|
|
23
|
+
4. 生成结构化审计报告
|
|
24
|
+
|
|
25
|
+
输出格式(JSON):
|
|
26
|
+
每个问题一行 JSON 对象,包含字段:
|
|
27
|
+
{
|
|
28
|
+
"severity": "high|medium|low",
|
|
29
|
+
"category": "安全|质量|性能",
|
|
30
|
+
"message": "问题描述",
|
|
31
|
+
"suggestion": "修复建议",
|
|
32
|
+
"line_number": 可选的行号
|
|
33
|
+
}
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def _get_sub_dir(self) -> str:
|
|
37
|
+
return "audits"
|
|
38
|
+
|
|
39
|
+
def execute(self, task_id: str, context: Dict) -> Dict:
|
|
40
|
+
"""
|
|
41
|
+
执行代码审计任务(异步)
|
|
42
|
+
|
|
43
|
+
流程:
|
|
44
|
+
1. 获取待审计的代码
|
|
45
|
+
2. 调用 LLM 进行审计
|
|
46
|
+
3. 解析审计结果
|
|
47
|
+
4. 保存到数据库
|
|
48
|
+
5. 将审计报告写入文件系统
|
|
49
|
+
"""
|
|
50
|
+
# 1. 获取待审计代码
|
|
51
|
+
code = context.get("code", "")
|
|
52
|
+
file_path = context.get("file_path", "unknown")
|
|
53
|
+
agent_type = context.get("agent_type", "unknown")
|
|
54
|
+
|
|
55
|
+
if not code:
|
|
56
|
+
return {"status": "skipped", "reason": "no code to audit"}
|
|
57
|
+
|
|
58
|
+
# 2. 调用 LLM 审计
|
|
59
|
+
system_prompt = self.get_system_prompt()
|
|
60
|
+
prompt = f"""请审计以下代码,找出安全漏洞和代码质量问题:
|
|
61
|
+
|
|
62
|
+
## 代码
|
|
63
|
+
```
|
|
64
|
+
{code}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 文件路径
|
|
68
|
+
{file_path}
|
|
69
|
+
|
|
70
|
+
请以 JSON 格式输出审计结果,每个问题一个 JSON 对象,包含字段:
|
|
71
|
+
- severity: 严重程度 (high/medium/low)
|
|
72
|
+
- category: 问题类别 (安全/质量/性能)
|
|
73
|
+
- message: 问题描述
|
|
74
|
+
- suggestion: 修复建议
|
|
75
|
+
- line_number: 问题所在行号(如果可确定)
|
|
76
|
+
|
|
77
|
+
如果有多个问题,每行输出一个 JSON 对象。
|
|
78
|
+
"""
|
|
79
|
+
audit_result = self._call_llm(prompt, temperature=0.2)
|
|
80
|
+
|
|
81
|
+
# 3. 解析审计结果
|
|
82
|
+
reports = self._parse_audit_result(audit_result)
|
|
83
|
+
|
|
84
|
+
# 4. 保存到数据库
|
|
85
|
+
for report in reports:
|
|
86
|
+
self.db.add_audit_report(
|
|
87
|
+
task_id=task_id,
|
|
88
|
+
agent_type=agent_type,
|
|
89
|
+
severity=report.get("severity", "low"),
|
|
90
|
+
message=report.get("message", ""),
|
|
91
|
+
file_path=file_path,
|
|
92
|
+
line_number=report.get("line_number"),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# 5. 将审计报告写入文件系统
|
|
96
|
+
audit_md = self._format_audit_report(reports, file_path, audit_result)
|
|
97
|
+
audit_filename = f"audits/audit_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
|
|
98
|
+
self._write_file(audit_filename, audit_md)
|
|
99
|
+
|
|
100
|
+
# 6. 返回结果
|
|
101
|
+
result = {
|
|
102
|
+
"status": "success",
|
|
103
|
+
"reports_count": len(reports),
|
|
104
|
+
"high_severity": sum(1 for r in reports if r.get("severity") == "high"),
|
|
105
|
+
"reports": reports,
|
|
106
|
+
"audit_file": audit_filename,
|
|
107
|
+
}
|
|
108
|
+
self._save_result(task_id, str(result))
|
|
109
|
+
|
|
110
|
+
# 7. 保存 Agent 执行 trace(完整 I/O 审计)
|
|
111
|
+
self._save_trace(
|
|
112
|
+
task_id=task_id,
|
|
113
|
+
system_prompt=system_prompt,
|
|
114
|
+
user_prompt=prompt,
|
|
115
|
+
llm_response=audit_result,
|
|
116
|
+
parsed_result=result,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
def _format_audit_report(
|
|
122
|
+
self, reports: List[Dict], file_path: str, raw_result: str
|
|
123
|
+
) -> str:
|
|
124
|
+
"""将审计结果格式化为 Markdown 报告"""
|
|
125
|
+
lines = [
|
|
126
|
+
"# 代码审计报告",
|
|
127
|
+
"",
|
|
128
|
+
f"- 审计时间: {datetime.now().isoformat()}",
|
|
129
|
+
f"- 审计文件: {file_path}",
|
|
130
|
+
f"- 发现问题数: {len(reports)}",
|
|
131
|
+
"",
|
|
132
|
+
"## 问题列表",
|
|
133
|
+
"",
|
|
134
|
+
]
|
|
135
|
+
for i, r in enumerate(reports, 1):
|
|
136
|
+
lines.append(
|
|
137
|
+
f"### {i}. [{r.get('severity', 'low').upper()}] {r.get('category', '未知')}"
|
|
138
|
+
)
|
|
139
|
+
lines.append(f"- **描述**: {r.get('message', '')}")
|
|
140
|
+
lines.append(f"- **建议**: {r.get('suggestion', '')}")
|
|
141
|
+
if r.get("line_number"):
|
|
142
|
+
lines.append(f"- **行号**: {r.get('line_number')}")
|
|
143
|
+
lines.append("")
|
|
144
|
+
|
|
145
|
+
lines += ["## 原始审计输出", "", "```", raw_result, "```", ""]
|
|
146
|
+
return "\n".join(lines)
|
|
147
|
+
|
|
148
|
+
def _parse_audit_result(self, audit_text: str) -> List[Dict]:
|
|
149
|
+
"""
|
|
150
|
+
解析 LLM 返回的审计结果
|
|
151
|
+
支持多种格式:
|
|
152
|
+
1. ```json 代码块中的 JSON 数组或对象
|
|
153
|
+
2. 裸 JSON 数组 [{{}}, {{}}]
|
|
154
|
+
3. 每行一个 JSON 对象
|
|
155
|
+
"""
|
|
156
|
+
reports = []
|
|
157
|
+
|
|
158
|
+
# 尝试 1: json 代码块(支持 ```json 和 ``` 两种格式)
|
|
159
|
+
json_match = re.search(r"```(?:json)?\s*\n?(.*?)\n?```", audit_text, re.DOTALL)
|
|
160
|
+
if json_match:
|
|
161
|
+
try:
|
|
162
|
+
data = json.loads(json_match.group(1).strip())
|
|
163
|
+
if isinstance(data, list):
|
|
164
|
+
return [r for r in data if isinstance(r, dict)]
|
|
165
|
+
elif isinstance(data, dict):
|
|
166
|
+
return [data]
|
|
167
|
+
except json.JSONDecodeError:
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
# 尝试 2: 裸 JSON 数组或对象(整个文本就是 JSON)
|
|
171
|
+
stripped = audit_text.strip()
|
|
172
|
+
if stripped.startswith("[") or stripped.startswith("{"):
|
|
173
|
+
try:
|
|
174
|
+
data = json.loads(stripped)
|
|
175
|
+
if isinstance(data, list):
|
|
176
|
+
return [r for r in data if isinstance(r, dict)]
|
|
177
|
+
elif isinstance(data, dict):
|
|
178
|
+
return [data]
|
|
179
|
+
except json.JSONDecodeError:
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
# 尝试 3: 逐行解析 JSON 对象
|
|
183
|
+
for line in audit_text.split("\n"):
|
|
184
|
+
line = line.strip()
|
|
185
|
+
if not line or not line.startswith("{"):
|
|
186
|
+
continue
|
|
187
|
+
try:
|
|
188
|
+
report = json.loads(line)
|
|
189
|
+
if "severity" in report and "message" in report:
|
|
190
|
+
reports.append(report)
|
|
191
|
+
except json.JSONDecodeError:
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
return reports
|
|
195
|
+
|
|
196
|
+
def run_security_scan(self, task_id: str, code: str) -> Dict:
|
|
197
|
+
"""
|
|
198
|
+
执行安全扫描(同步,用于关键代码)
|
|
199
|
+
|
|
200
|
+
检查常见安全漏洞:
|
|
201
|
+
- SQL 注入
|
|
202
|
+
- XSS
|
|
203
|
+
- 敏感信息泄露
|
|
204
|
+
- 不安全的依赖
|
|
205
|
+
"""
|
|
206
|
+
prompt = f"""请对以下代码进行安全扫描,重点检查:
|
|
207
|
+
|
|
208
|
+
1. SQL 注入漏洞
|
|
209
|
+
2. XSS 跨站脚本
|
|
210
|
+
3. CSRF 漏洞
|
|
211
|
+
4. 敏感信息泄露(硬编码密码、API Key 等)
|
|
212
|
+
5. 不安全的加密算法
|
|
213
|
+
6. 权限绕过风险
|
|
214
|
+
|
|
215
|
+
代码:
|
|
216
|
+
```
|
|
217
|
+
{code}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
只输出发现的安全问题,格式:
|
|
221
|
+
[SEVERITY] 问题描述 - 修复建议
|
|
222
|
+
"""
|
|
223
|
+
return {"scan_result": self._call_llm(prompt, temperature=0.1)}
|
agents/backend_agent.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
后端专家智能体
|
|
3
|
+
负责生成后端代码、API 接口,并提取 API 契约供前端使用
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from typing import Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from agents.base_agent import BaseAgent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BackendAgent(BaseAgent):
|
|
14
|
+
"""后端专家 Agent"""
|
|
15
|
+
|
|
16
|
+
def get_system_prompt(self) -> str:
|
|
17
|
+
return """你是一位资深后端开发专家,精通 Python/Java/Node.js 后端开发。
|
|
18
|
+
你的职责是:
|
|
19
|
+
1. 根据需求生成高质量的后端代码
|
|
20
|
+
2. 设计 RESTful API 接口
|
|
21
|
+
3. 编写数据库模型和数据访问层
|
|
22
|
+
4. 确保代码的安全性、性能和可维护性
|
|
23
|
+
|
|
24
|
+
输出格式要求:
|
|
25
|
+
- 每个文件用 ### FILE: 标记,格式如下:
|
|
26
|
+
### FILE: backend/main.py
|
|
27
|
+
```python
|
|
28
|
+
# code here
|
|
29
|
+
```
|
|
30
|
+
- 代码必须可直接运行
|
|
31
|
+
- API 接口必须包含完整的请求/响应 Schema
|
|
32
|
+
- 在代码注释中标注 API 契约信息(endpoint, method, request_schema, response_schema)
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def execute(self, task_id: str, context: Dict) -> Dict:
|
|
36
|
+
"""
|
|
37
|
+
执行后端开发任务
|
|
38
|
+
|
|
39
|
+
流程:
|
|
40
|
+
1. 检查依赖
|
|
41
|
+
2. 如果是迭代模式,读取已有代码注入 prompt
|
|
42
|
+
3. 调用 LLM 生成后端代码
|
|
43
|
+
4. 解析多文件输出并写入文件系统
|
|
44
|
+
5. 提取 API 契约并保存到数据库
|
|
45
|
+
6. 更新任务状态
|
|
46
|
+
"""
|
|
47
|
+
# 1. 检查依赖
|
|
48
|
+
if not self._check_dependencies(context, ["description"]):
|
|
49
|
+
raise ValueError("缺少必需的任务描述")
|
|
50
|
+
|
|
51
|
+
description = context["description"]
|
|
52
|
+
requirements = context.get("requirements", "")
|
|
53
|
+
is_iteration = context.get("is_iteration", False)
|
|
54
|
+
|
|
55
|
+
# 2. 构建 prompt
|
|
56
|
+
prompt = f"""请根据以下需求生成后端代码:
|
|
57
|
+
|
|
58
|
+
## 需求描述
|
|
59
|
+
{description}
|
|
60
|
+
|
|
61
|
+
## 详细要求
|
|
62
|
+
{requirements}
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# 迭代模式:注入已有代码
|
|
66
|
+
if is_iteration:
|
|
67
|
+
existing_code = self._collect_existing_code()
|
|
68
|
+
if existing_code:
|
|
69
|
+
prompt += f"""
|
|
70
|
+
## 已有代码(请基于以下代码进行修改,不要重复生成已有文件)
|
|
71
|
+
{existing_code}
|
|
72
|
+
|
|
73
|
+
重要:请只输出需要新增或修改的文件,不要重复输出未修改的文件。
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
prompt += """
|
|
77
|
+
请生成完整的后端代码,每个文件用 ### FILE: 标记,格式如下:
|
|
78
|
+
|
|
79
|
+
### FILE: backend/main.py
|
|
80
|
+
```python
|
|
81
|
+
# code here
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### FILE: backend/api.py
|
|
85
|
+
```python
|
|
86
|
+
# code here
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
在代码中用注释标注 API 契约,格式如下:
|
|
90
|
+
### API_CONTRACT_START
|
|
91
|
+
endpoint: /api/xxx
|
|
92
|
+
method: GET/POST/...
|
|
93
|
+
request_schema: {{...}}
|
|
94
|
+
response_schema: {{...}}
|
|
95
|
+
### API_CONTRACT_END
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# 3. 调用 LLM 生成代码
|
|
99
|
+
system_prompt = self.get_system_prompt()
|
|
100
|
+
code_result = self._call_llm(prompt, temperature=0.3)
|
|
101
|
+
|
|
102
|
+
# 4. 解析多文件输出并写入文件系统
|
|
103
|
+
files = self._parse_llm_code_output(code_result)
|
|
104
|
+
change_type = "update" if is_iteration else "create"
|
|
105
|
+
for file_path, content in files.items():
|
|
106
|
+
self._write_file(file_path, content)
|
|
107
|
+
self._log_change(
|
|
108
|
+
task_id=task_id,
|
|
109
|
+
file_path=file_path,
|
|
110
|
+
change_type=change_type,
|
|
111
|
+
diff=content,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# 5. 提取 API 契约
|
|
115
|
+
contracts = self._extract_api_contracts(code_result)
|
|
116
|
+
for contract in contracts:
|
|
117
|
+
self.db.save_api_contract(
|
|
118
|
+
task_id=task_id,
|
|
119
|
+
endpoint=contract["endpoint"],
|
|
120
|
+
method=contract["method"],
|
|
121
|
+
request_schema=contract.get("request_schema"),
|
|
122
|
+
response_schema=contract.get("response_schema"),
|
|
123
|
+
created_by="backend",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# 6. 保存结果
|
|
127
|
+
result = {
|
|
128
|
+
"status": "success",
|
|
129
|
+
"files": list(files.keys()),
|
|
130
|
+
"contracts": contracts,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# 7. 保存 Agent 执行 trace(完整 I/O 审计)
|
|
134
|
+
self._save_trace(
|
|
135
|
+
task_id=task_id,
|
|
136
|
+
system_prompt=system_prompt,
|
|
137
|
+
user_prompt=prompt,
|
|
138
|
+
llm_response=code_result,
|
|
139
|
+
parsed_result=result,
|
|
140
|
+
)
|
|
141
|
+
self._save_result(task_id, json.dumps(result))
|
|
142
|
+
|
|
143
|
+
return result
|
|
144
|
+
|
|
145
|
+
def _extract_api_contracts(self, code: str) -> List[Dict]:
|
|
146
|
+
"""
|
|
147
|
+
从生成的代码中提取 API 契约
|
|
148
|
+
|
|
149
|
+
匹配格式:
|
|
150
|
+
### API_CONTRACT_START
|
|
151
|
+
endpoint: /api/xxx
|
|
152
|
+
method: GET
|
|
153
|
+
request_schema: {...}
|
|
154
|
+
response_schema: {...}
|
|
155
|
+
### API_CONTRACT_END
|
|
156
|
+
"""
|
|
157
|
+
contracts = []
|
|
158
|
+
pattern = r"### API_CONTRACT_START(.*?)### API_CONTRACT_END"
|
|
159
|
+
matches = re.findall(pattern, code, re.DOTALL)
|
|
160
|
+
|
|
161
|
+
for match in matches:
|
|
162
|
+
contract = {}
|
|
163
|
+
lines = match.strip().split("\n")
|
|
164
|
+
for line in lines:
|
|
165
|
+
if ":" in line:
|
|
166
|
+
key, value = line.split(":", 1)
|
|
167
|
+
key = key.strip()
|
|
168
|
+
value = value.strip()
|
|
169
|
+
if key in ["endpoint", "method"]:
|
|
170
|
+
contract[key] = value
|
|
171
|
+
elif key in ["request_schema", "response_schema"]:
|
|
172
|
+
try:
|
|
173
|
+
contract[key] = json.loads(value)
|
|
174
|
+
except json.JSONDecodeError:
|
|
175
|
+
contract[key] = {"raw": value}
|
|
176
|
+
if "endpoint" in contract and "method" in contract:
|
|
177
|
+
contracts.append(contract)
|
|
178
|
+
|
|
179
|
+
return contracts
|