kairo-code 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.
- image-service/main.py +178 -0
- infra/chat/app/main.py +84 -0
- kairo/backend/__init__.py +0 -0
- kairo/backend/api/__init__.py +0 -0
- kairo/backend/api/admin/__init__.py +23 -0
- kairo/backend/api/admin/audit.py +54 -0
- kairo/backend/api/admin/content.py +142 -0
- kairo/backend/api/admin/incidents.py +148 -0
- kairo/backend/api/admin/stats.py +125 -0
- kairo/backend/api/admin/system.py +87 -0
- kairo/backend/api/admin/users.py +279 -0
- kairo/backend/api/agents.py +94 -0
- kairo/backend/api/api_keys.py +85 -0
- kairo/backend/api/auth.py +116 -0
- kairo/backend/api/billing.py +41 -0
- kairo/backend/api/chat.py +72 -0
- kairo/backend/api/conversations.py +125 -0
- kairo/backend/api/device_auth.py +100 -0
- kairo/backend/api/files.py +83 -0
- kairo/backend/api/health.py +36 -0
- kairo/backend/api/images.py +80 -0
- kairo/backend/api/openai_compat.py +225 -0
- kairo/backend/api/projects.py +102 -0
- kairo/backend/api/usage.py +32 -0
- kairo/backend/api/webhooks.py +79 -0
- kairo/backend/app.py +297 -0
- kairo/backend/config.py +179 -0
- kairo/backend/core/__init__.py +0 -0
- kairo/backend/core/admin_auth.py +24 -0
- kairo/backend/core/api_key_auth.py +55 -0
- kairo/backend/core/database.py +28 -0
- kairo/backend/core/dependencies.py +70 -0
- kairo/backend/core/logging.py +23 -0
- kairo/backend/core/rate_limit.py +73 -0
- kairo/backend/core/security.py +29 -0
- kairo/backend/models/__init__.py +19 -0
- kairo/backend/models/agent.py +30 -0
- kairo/backend/models/api_key.py +25 -0
- kairo/backend/models/api_usage.py +29 -0
- kairo/backend/models/audit_log.py +26 -0
- kairo/backend/models/conversation.py +48 -0
- kairo/backend/models/device_code.py +30 -0
- kairo/backend/models/feature_flag.py +21 -0
- kairo/backend/models/image_generation.py +24 -0
- kairo/backend/models/incident.py +28 -0
- kairo/backend/models/project.py +28 -0
- kairo/backend/models/uptime_record.py +24 -0
- kairo/backend/models/usage.py +24 -0
- kairo/backend/models/user.py +49 -0
- kairo/backend/schemas/__init__.py +0 -0
- kairo/backend/schemas/admin/__init__.py +0 -0
- kairo/backend/schemas/admin/audit.py +28 -0
- kairo/backend/schemas/admin/content.py +53 -0
- kairo/backend/schemas/admin/stats.py +77 -0
- kairo/backend/schemas/admin/system.py +44 -0
- kairo/backend/schemas/admin/users.py +48 -0
- kairo/backend/schemas/agent.py +42 -0
- kairo/backend/schemas/api_key.py +30 -0
- kairo/backend/schemas/auth.py +57 -0
- kairo/backend/schemas/chat.py +26 -0
- kairo/backend/schemas/conversation.py +39 -0
- kairo/backend/schemas/device_auth.py +40 -0
- kairo/backend/schemas/image.py +15 -0
- kairo/backend/schemas/openai_compat.py +76 -0
- kairo/backend/schemas/project.py +21 -0
- kairo/backend/schemas/status.py +81 -0
- kairo/backend/schemas/usage.py +15 -0
- kairo/backend/services/__init__.py +0 -0
- kairo/backend/services/admin/__init__.py +0 -0
- kairo/backend/services/admin/audit_service.py +78 -0
- kairo/backend/services/admin/content_service.py +119 -0
- kairo/backend/services/admin/incident_service.py +94 -0
- kairo/backend/services/admin/stats_service.py +281 -0
- kairo/backend/services/admin/system_service.py +126 -0
- kairo/backend/services/admin/user_service.py +157 -0
- kairo/backend/services/agent_service.py +107 -0
- kairo/backend/services/api_key_service.py +66 -0
- kairo/backend/services/api_usage_service.py +126 -0
- kairo/backend/services/auth_service.py +101 -0
- kairo/backend/services/chat_service.py +501 -0
- kairo/backend/services/conversation_service.py +264 -0
- kairo/backend/services/device_auth_service.py +193 -0
- kairo/backend/services/email_service.py +55 -0
- kairo/backend/services/image_service.py +181 -0
- kairo/backend/services/llm_service.py +186 -0
- kairo/backend/services/project_service.py +109 -0
- kairo/backend/services/status_service.py +167 -0
- kairo/backend/services/stripe_service.py +78 -0
- kairo/backend/services/usage_service.py +150 -0
- kairo/backend/services/web_search_service.py +96 -0
- kairo/migrations/env.py +60 -0
- kairo/migrations/versions/001_initial.py +55 -0
- kairo/migrations/versions/002_usage_tracking_and_indexes.py +66 -0
- kairo/migrations/versions/003_username_to_email.py +21 -0
- kairo/migrations/versions/004_add_plans_and_verification.py +67 -0
- kairo/migrations/versions/005_add_projects.py +52 -0
- kairo/migrations/versions/006_add_image_generation.py +63 -0
- kairo/migrations/versions/007_add_admin_portal.py +107 -0
- kairo/migrations/versions/008_add_device_code_auth.py +76 -0
- kairo/migrations/versions/009_add_status_page.py +65 -0
- kairo/tools/extract_claude_data.py +465 -0
- kairo/tools/filter_claude_data.py +303 -0
- kairo/tools/generate_curated_data.py +157 -0
- kairo/tools/mix_training_data.py +295 -0
- kairo_code/__init__.py +3 -0
- kairo_code/agents/__init__.py +25 -0
- kairo_code/agents/architect.py +98 -0
- kairo_code/agents/audit.py +100 -0
- kairo_code/agents/base.py +463 -0
- kairo_code/agents/coder.py +155 -0
- kairo_code/agents/database.py +77 -0
- kairo_code/agents/docs.py +88 -0
- kairo_code/agents/explorer.py +62 -0
- kairo_code/agents/guardian.py +80 -0
- kairo_code/agents/planner.py +66 -0
- kairo_code/agents/reviewer.py +91 -0
- kairo_code/agents/security.py +94 -0
- kairo_code/agents/terraform.py +88 -0
- kairo_code/agents/testing.py +97 -0
- kairo_code/agents/uiux.py +88 -0
- kairo_code/auth.py +232 -0
- kairo_code/config.py +172 -0
- kairo_code/conversation.py +173 -0
- kairo_code/heartbeat.py +63 -0
- kairo_code/llm.py +291 -0
- kairo_code/logging_config.py +156 -0
- kairo_code/main.py +818 -0
- kairo_code/router.py +217 -0
- kairo_code/sandbox.py +248 -0
- kairo_code/settings.py +183 -0
- kairo_code/tools/__init__.py +51 -0
- kairo_code/tools/analysis.py +509 -0
- kairo_code/tools/base.py +417 -0
- kairo_code/tools/code.py +58 -0
- kairo_code/tools/definitions.py +617 -0
- kairo_code/tools/files.py +315 -0
- kairo_code/tools/review.py +390 -0
- kairo_code/tools/search.py +185 -0
- kairo_code/ui.py +418 -0
- kairo_code-0.1.0.dist-info/METADATA +13 -0
- kairo_code-0.1.0.dist-info/RECORD +144 -0
- kairo_code-0.1.0.dist-info/WHEEL +5 -0
- kairo_code-0.1.0.dist-info/entry_points.txt +2 -0
- kairo_code-0.1.0.dist-info/top_level.txt +4 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Combine filtered Claude data with curated best-practices data into final training set.
|
|
3
|
+
|
|
4
|
+
Steps:
|
|
5
|
+
1. Load both datasets
|
|
6
|
+
2. Deduplicate by Jaccard similarity of user messages (threshold 0.85)
|
|
7
|
+
3. Shuffle with seed for reproducibility
|
|
8
|
+
4. Split 90/10 train/val
|
|
9
|
+
5. Write output
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
python kairo/tools/mix_training_data.py \
|
|
13
|
+
--curated kairo/data/curated_best_practices.jsonl \
|
|
14
|
+
--filtered kairo/data/claude_filtered.jsonl \
|
|
15
|
+
--output-dir kairo/data \
|
|
16
|
+
--val-ratio 0.1 \
|
|
17
|
+
--seed 42
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import math
|
|
23
|
+
import os
|
|
24
|
+
import random
|
|
25
|
+
import re
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_jsonl(path: str) -> list[dict]:
|
|
30
|
+
"""Load a JSONL file into a list of dicts."""
|
|
31
|
+
examples = []
|
|
32
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
33
|
+
for line in f:
|
|
34
|
+
line = line.strip()
|
|
35
|
+
if not line:
|
|
36
|
+
continue
|
|
37
|
+
try:
|
|
38
|
+
examples.append(json.loads(line))
|
|
39
|
+
except json.JSONDecodeError:
|
|
40
|
+
continue
|
|
41
|
+
return examples
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def extract_user_messages(text: str) -> str:
|
|
45
|
+
"""Extract concatenated user messages from a Llama 3.1 formatted example."""
|
|
46
|
+
parts = re.split(
|
|
47
|
+
r"<\|start_header_id\|>(user|assistant|system)<\|end_header_id\|>\n\n", text
|
|
48
|
+
)
|
|
49
|
+
user_texts = []
|
|
50
|
+
i = 1
|
|
51
|
+
while i + 1 < len(parts):
|
|
52
|
+
role = parts[i]
|
|
53
|
+
content = parts[i + 1].replace("<|eot_id|>", "").strip()
|
|
54
|
+
if role == "user" and content:
|
|
55
|
+
user_texts.append(content)
|
|
56
|
+
i += 2
|
|
57
|
+
return " ".join(user_texts)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def tokenize(text: str) -> set[str]:
|
|
61
|
+
"""Simple word-level tokenization for Jaccard similarity."""
|
|
62
|
+
return set(re.findall(r"\w+", text.lower()))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def jaccard_similarity(a: set[str], b: set[str]) -> float:
|
|
66
|
+
"""Compute Jaccard similarity between two token sets."""
|
|
67
|
+
if not a and not b:
|
|
68
|
+
return 1.0
|
|
69
|
+
if not a or not b:
|
|
70
|
+
return 0.0
|
|
71
|
+
return len(a & b) / len(a | b)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def deduplicate(examples: list[dict], threshold: float = 0.85) -> list[dict]:
|
|
75
|
+
"""Remove near-duplicate examples based on Jaccard similarity of user messages.
|
|
76
|
+
|
|
77
|
+
Uses a simple O(n^2) approach which is fine for <1000 examples.
|
|
78
|
+
"""
|
|
79
|
+
if not examples:
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
# Pre-compute user message tokens for each example
|
|
83
|
+
tokenized = []
|
|
84
|
+
for ex in examples:
|
|
85
|
+
text = ex.get("text", "")
|
|
86
|
+
user_msg = extract_user_messages(text)
|
|
87
|
+
tokens = tokenize(user_msg)
|
|
88
|
+
tokenized.append(tokens)
|
|
89
|
+
|
|
90
|
+
kept_indices = []
|
|
91
|
+
for i in range(len(examples)):
|
|
92
|
+
is_dup = False
|
|
93
|
+
for j in kept_indices:
|
|
94
|
+
sim = jaccard_similarity(tokenized[i], tokenized[j])
|
|
95
|
+
if sim >= threshold:
|
|
96
|
+
is_dup = True
|
|
97
|
+
break
|
|
98
|
+
if not is_dup:
|
|
99
|
+
kept_indices.append(i)
|
|
100
|
+
|
|
101
|
+
return [examples[i] for i in kept_indices]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def write_jsonl(path: str, examples: list[dict]) -> None:
|
|
105
|
+
"""Write examples to a JSONL file."""
|
|
106
|
+
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
|
|
107
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
108
|
+
for ex in examples:
|
|
109
|
+
f.write(json.dumps(ex) + "\n")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def detect_category(text: str) -> str:
|
|
113
|
+
"""Try to detect the category of a curated example from content signals."""
|
|
114
|
+
text_lower = text.lower()
|
|
115
|
+
|
|
116
|
+
category_signals = [
|
|
117
|
+
("security", ["sql injection", "xss", "csrf", "auth", "password", "hash",
|
|
118
|
+
"sanitiz", "owasp", "vulnerab", "token", "jwt", "cors"]),
|
|
119
|
+
("error_handling", ["try", "except", "exception", "error handling",
|
|
120
|
+
"error boundar", "graceful", "retry"]),
|
|
121
|
+
("api_design", ["rest", "endpoint", "status code", "pagination",
|
|
122
|
+
"pydantic", "fastapi", "router", "http method"]),
|
|
123
|
+
("database", ["sqlalchemy", "migration", "alembic", "query", "index",
|
|
124
|
+
"n+1", "transaction", "connection pool"]),
|
|
125
|
+
("testing", ["pytest", "test_", "mock", "fixture", "assert",
|
|
126
|
+
"coverage", "test client"]),
|
|
127
|
+
("architecture", ["solid", "separation of concerns", "dependency injection",
|
|
128
|
+
"repository pattern", "service layer", "clean arch"]),
|
|
129
|
+
("performance", ["cache", "async", "batch", "optimi", "profil",
|
|
130
|
+
"lazy load", "background task"]),
|
|
131
|
+
("react_typescript", ["react", "component", "usestate", "useeffect",
|
|
132
|
+
"typescript", "interface", "props", "hook"]),
|
|
133
|
+
("python_fastapi", ["type hint", "pydantic", "fastapi", "middleware",
|
|
134
|
+
"lifespan", "depends"]),
|
|
135
|
+
("git_deployment", ["commit", "branch", "docker", "ci/cd", "deploy",
|
|
136
|
+
"dockerfile", "health check"]),
|
|
137
|
+
("clean_code", ["naming", "dry", "readab", "refactor", "function length",
|
|
138
|
+
"single responsib", "magic number"]),
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
for category, signals in category_signals:
|
|
142
|
+
matches = sum(1 for s in signals if s in text_lower)
|
|
143
|
+
if matches >= 2:
|
|
144
|
+
return category
|
|
145
|
+
|
|
146
|
+
return "other"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def main():
|
|
150
|
+
parser = argparse.ArgumentParser(
|
|
151
|
+
description="Mix filtered Claude data with curated best-practices data"
|
|
152
|
+
)
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"--curated",
|
|
155
|
+
default="kairo/data/curated_best_practices.jsonl",
|
|
156
|
+
help="Curated best-practices JSONL file",
|
|
157
|
+
)
|
|
158
|
+
parser.add_argument(
|
|
159
|
+
"--filtered",
|
|
160
|
+
default="kairo/data/claude_filtered.jsonl",
|
|
161
|
+
help="Filtered Claude training JSONL file",
|
|
162
|
+
)
|
|
163
|
+
parser.add_argument(
|
|
164
|
+
"--output-dir",
|
|
165
|
+
default="kairo/data",
|
|
166
|
+
help="Output directory (default: kairo/data)",
|
|
167
|
+
)
|
|
168
|
+
parser.add_argument(
|
|
169
|
+
"--val-ratio",
|
|
170
|
+
type=float,
|
|
171
|
+
default=0.1,
|
|
172
|
+
help="Validation set ratio (default: 0.1)",
|
|
173
|
+
)
|
|
174
|
+
parser.add_argument(
|
|
175
|
+
"--seed",
|
|
176
|
+
type=int,
|
|
177
|
+
default=42,
|
|
178
|
+
help="Random seed for shuffling (default: 42)",
|
|
179
|
+
)
|
|
180
|
+
parser.add_argument(
|
|
181
|
+
"--dedup-threshold",
|
|
182
|
+
type=float,
|
|
183
|
+
default=0.85,
|
|
184
|
+
help="Jaccard similarity threshold for deduplication (default: 0.85)",
|
|
185
|
+
)
|
|
186
|
+
args = parser.parse_args()
|
|
187
|
+
|
|
188
|
+
# Load datasets
|
|
189
|
+
curated = load_jsonl(args.curated)
|
|
190
|
+
filtered = load_jsonl(args.filtered)
|
|
191
|
+
print(f"Loaded {len(curated)} curated examples from {args.curated}")
|
|
192
|
+
print(f"Loaded {len(filtered)} filtered examples from {args.filtered}")
|
|
193
|
+
|
|
194
|
+
# Tag source for stats
|
|
195
|
+
for ex in curated:
|
|
196
|
+
ex["_source"] = "curated"
|
|
197
|
+
for ex in filtered:
|
|
198
|
+
ex["_source"] = "filtered"
|
|
199
|
+
|
|
200
|
+
# Combine
|
|
201
|
+
combined = curated + filtered
|
|
202
|
+
print(f"Combined: {len(combined)} examples")
|
|
203
|
+
|
|
204
|
+
# Deduplicate
|
|
205
|
+
deduped = deduplicate(combined, threshold=args.dedup_threshold)
|
|
206
|
+
removed = len(combined) - len(deduped)
|
|
207
|
+
print(f"After dedup (threshold={args.dedup_threshold}): {len(deduped)} ({removed} removed)")
|
|
208
|
+
|
|
209
|
+
# Shuffle
|
|
210
|
+
rng = random.Random(args.seed)
|
|
211
|
+
rng.shuffle(deduped)
|
|
212
|
+
|
|
213
|
+
# Split
|
|
214
|
+
val_count = max(1, math.floor(len(deduped) * args.val_ratio))
|
|
215
|
+
val_set = deduped[:val_count]
|
|
216
|
+
train_set = deduped[val_count:]
|
|
217
|
+
|
|
218
|
+
# Collect stats before stripping metadata
|
|
219
|
+
source_counts = {"curated": 0, "filtered": 0}
|
|
220
|
+
category_counts = {}
|
|
221
|
+
for ex in deduped:
|
|
222
|
+
src = ex.get("_source", "unknown")
|
|
223
|
+
source_counts[src] = source_counts.get(src, 0) + 1
|
|
224
|
+
cat = detect_category(ex.get("text", ""))
|
|
225
|
+
category_counts[cat] = category_counts.get(cat, 0) + 1
|
|
226
|
+
|
|
227
|
+
train_sources = {"curated": 0, "filtered": 0}
|
|
228
|
+
for ex in train_set:
|
|
229
|
+
src = ex.get("_source", "unknown")
|
|
230
|
+
train_sources[src] = train_sources.get(src, 0) + 1
|
|
231
|
+
|
|
232
|
+
val_sources = {"curated": 0, "filtered": 0}
|
|
233
|
+
for ex in val_set:
|
|
234
|
+
src = ex.get("_source", "unknown")
|
|
235
|
+
val_sources[src] = val_sources.get(src, 0) + 1
|
|
236
|
+
|
|
237
|
+
# Strip internal metadata before writing
|
|
238
|
+
for ex in deduped:
|
|
239
|
+
ex.pop("_source", None)
|
|
240
|
+
|
|
241
|
+
# Write output
|
|
242
|
+
train_path = os.path.join(args.output_dir, "final_train.jsonl")
|
|
243
|
+
val_path = os.path.join(args.output_dir, "final_val.jsonl")
|
|
244
|
+
stats_path = os.path.join(args.output_dir, "mixing_stats.json")
|
|
245
|
+
|
|
246
|
+
write_jsonl(train_path, train_set)
|
|
247
|
+
write_jsonl(val_path, val_set)
|
|
248
|
+
|
|
249
|
+
# Write stats
|
|
250
|
+
stats = {
|
|
251
|
+
"input": {
|
|
252
|
+
"curated": len(curated),
|
|
253
|
+
"filtered": len(filtered),
|
|
254
|
+
"combined": len(combined),
|
|
255
|
+
},
|
|
256
|
+
"deduplication": {
|
|
257
|
+
"threshold": args.dedup_threshold,
|
|
258
|
+
"removed": removed,
|
|
259
|
+
"after_dedup": len(deduped),
|
|
260
|
+
},
|
|
261
|
+
"split": {
|
|
262
|
+
"seed": args.seed,
|
|
263
|
+
"val_ratio": args.val_ratio,
|
|
264
|
+
"train_count": len(train_set),
|
|
265
|
+
"val_count": len(val_set),
|
|
266
|
+
},
|
|
267
|
+
"source_distribution": {
|
|
268
|
+
"total": source_counts,
|
|
269
|
+
"train": train_sources,
|
|
270
|
+
"val": val_sources,
|
|
271
|
+
},
|
|
272
|
+
"category_distribution": {
|
|
273
|
+
k: v for k, v in sorted(category_counts.items(), key=lambda x: -x[1])
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
os.makedirs(os.path.dirname(stats_path) or ".", exist_ok=True)
|
|
278
|
+
with open(stats_path, "w", encoding="utf-8") as f:
|
|
279
|
+
json.dump(stats, f, indent=2)
|
|
280
|
+
|
|
281
|
+
# Print summary
|
|
282
|
+
print(f"\nMixing complete!")
|
|
283
|
+
print(f" Train: {len(train_set)} examples → {train_path}")
|
|
284
|
+
print(f" Val: {len(val_set)} examples → {val_path}")
|
|
285
|
+
print(f" Stats: {stats_path}")
|
|
286
|
+
print(f"\nSource distribution:")
|
|
287
|
+
print(f" Curated: {source_counts.get('curated', 0)}")
|
|
288
|
+
print(f" Filtered: {source_counts.get('filtered', 0)}")
|
|
289
|
+
print(f"\nCategory distribution:")
|
|
290
|
+
for cat, count in sorted(category_counts.items(), key=lambda x: -x[1]):
|
|
291
|
+
print(f" {cat}: {count}")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
if __name__ == "__main__":
|
|
295
|
+
main()
|
kairo_code/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Kairo Code Agents - Specialized AI agents for different tasks"""
|
|
2
|
+
|
|
3
|
+
from .base import Agent, AgentEvent
|
|
4
|
+
from .explorer import ExplorerAgent
|
|
5
|
+
from .coder import CoderAgent
|
|
6
|
+
from .planner import PlannerAgent
|
|
7
|
+
from .security import SecurityAgent
|
|
8
|
+
from .reviewer import ReviewerAgent
|
|
9
|
+
from .audit import AuditAgent
|
|
10
|
+
from .testing import TestingAgent
|
|
11
|
+
from .uiux import UiUxAgent
|
|
12
|
+
from .guardian import GuardianAgent
|
|
13
|
+
from .docs import DocsAgent
|
|
14
|
+
from .architect import ArchitectAgent
|
|
15
|
+
from .database import DatabaseAgent
|
|
16
|
+
from .terraform import TerraformAgent
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"Agent", "AgentEvent",
|
|
20
|
+
"ExplorerAgent", "CoderAgent", "PlannerAgent",
|
|
21
|
+
"SecurityAgent", "ReviewerAgent", "AuditAgent",
|
|
22
|
+
"TestingAgent", "UiUxAgent", "GuardianAgent",
|
|
23
|
+
"DocsAgent", "ArchitectAgent", "DatabaseAgent",
|
|
24
|
+
"TerraformAgent",
|
|
25
|
+
]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Modular code architect agent — designs and refactors for modularity.
|
|
2
|
+
|
|
3
|
+
Mirrors the modular-code-architect Claude Code agent.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .base import Agent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ArchitectAgent(Agent):
|
|
10
|
+
name = "architect"
|
|
11
|
+
description = "Designs, builds, and refactors code with focus on modularity and scalability"
|
|
12
|
+
max_iterations = 15
|
|
13
|
+
require_confirmation = ["write_file"]
|
|
14
|
+
|
|
15
|
+
def get_system_prompt(self) -> str:
|
|
16
|
+
tools_desc = self.tools.format_for_prompt()
|
|
17
|
+
|
|
18
|
+
return f"""You are the Modular Code Architect, specializing in designing highly modular, maintainable, and scalable code structures. You have deep expertise in design patterns, separation of concerns, and clean architecture.
|
|
19
|
+
|
|
20
|
+
{tools_desc}
|
|
21
|
+
|
|
22
|
+
## Absolute Rules
|
|
23
|
+
1. **File Size Limits**: Never output a single file longer than 200-300 lines unless explicitly instructed
|
|
24
|
+
2. **Function Size**: Keep functions under 30 lines; decompose if longer
|
|
25
|
+
3. **Composition Over Inheritance**: Default to composition unless domain clearly requires inheritance
|
|
26
|
+
4. **Pure Functions**: Keep functions pure unless side effects are necessary
|
|
27
|
+
5. **No Monoliths**: Always decompose into smaller, reusable pieces
|
|
28
|
+
|
|
29
|
+
## Required Workflow
|
|
30
|
+
|
|
31
|
+
### Building New Features:
|
|
32
|
+
1. Propose a modular architecture before writing code
|
|
33
|
+
2. Present design philosophy
|
|
34
|
+
3. Show complete file tree structure
|
|
35
|
+
4. Implement each module separately
|
|
36
|
+
5. Document module interactions
|
|
37
|
+
|
|
38
|
+
### Modifying Existing Code:
|
|
39
|
+
1. Analyze current structure for modularity violations
|
|
40
|
+
2. Suggest modular refactors before writing new code
|
|
41
|
+
3. If monolithic, propose refactoring plan
|
|
42
|
+
4. Implement changes that improve or maintain modularity
|
|
43
|
+
|
|
44
|
+
## TOOL FORMAT
|
|
45
|
+
<tool>tool_name</tool>
|
|
46
|
+
<params>{{"key": "value"}}</params>
|
|
47
|
+
|
|
48
|
+
For write_file:
|
|
49
|
+
<write_file path="filename.py">
|
|
50
|
+
code here
|
|
51
|
+
</write_file>
|
|
52
|
+
|
|
53
|
+
## Output Format
|
|
54
|
+
|
|
55
|
+
### 1. Architecture Overview
|
|
56
|
+
- Design philosophy chosen
|
|
57
|
+
- Key modules and responsibilities
|
|
58
|
+
- Separation of concerns rationale
|
|
59
|
+
|
|
60
|
+
### 2. File Tree
|
|
61
|
+
project/
|
|
62
|
+
├── module-a/
|
|
63
|
+
│ ├── __init__.py
|
|
64
|
+
│ └── helpers.py
|
|
65
|
+
├── module-b/
|
|
66
|
+
│ └── __init__.py
|
|
67
|
+
└── shared/
|
|
68
|
+
└── types.py
|
|
69
|
+
|
|
70
|
+
### 3. Module Implementations
|
|
71
|
+
Each file in separate, clearly labeled blocks.
|
|
72
|
+
|
|
73
|
+
### 4. Module Interaction Notes
|
|
74
|
+
- How modules communicate
|
|
75
|
+
- Dependencies between modules
|
|
76
|
+
- Entry points and exports
|
|
77
|
+
|
|
78
|
+
## Design Principles Priority
|
|
79
|
+
1. **Maintainability**: Easy to understand and modify
|
|
80
|
+
2. **Readability**: Clear naming and structure
|
|
81
|
+
3. **Extensibility**: Easy to add features without modifying existing code
|
|
82
|
+
4. **Testability**: Independently testable modules
|
|
83
|
+
5. **Small, Focused Files**: Each file has a clear, single purpose
|
|
84
|
+
6. **Clean Boundaries**: Clear interfaces, minimal coupling
|
|
85
|
+
|
|
86
|
+
## Folder Structure
|
|
87
|
+
Organize by feature/domain, not by type:
|
|
88
|
+
features/auth/login/ over components/services/utils/
|
|
89
|
+
|
|
90
|
+
## Self-Verification
|
|
91
|
+
- No file exceeds 200-300 lines
|
|
92
|
+
- No function exceeds 30 lines (unless justified)
|
|
93
|
+
- Each module has single, clear responsibility
|
|
94
|
+
- Dependencies minimal and explicit
|
|
95
|
+
- Code testable in isolation"""
|
|
96
|
+
|
|
97
|
+
def get_tool_examples(self) -> str:
|
|
98
|
+
return ""
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Code audit agent — comprehensive codebase health assessment.
|
|
2
|
+
|
|
3
|
+
Mirrors the code-audit Claude Code agent.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .base import Agent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuditAgent(Agent):
|
|
10
|
+
name = "audit"
|
|
11
|
+
description = "Comprehensive codebase health, quality, and viability assessment"
|
|
12
|
+
max_iterations = 20
|
|
13
|
+
require_confirmation = []
|
|
14
|
+
|
|
15
|
+
def get_system_prompt(self) -> str:
|
|
16
|
+
tools_desc = self.tools.format_for_prompt()
|
|
17
|
+
|
|
18
|
+
return f"""You are a senior technical architect specializing in codebase assessment and technical debt evaluation. You have 20+ years of experience auditing codebases from startups to enterprise systems. Your assessments are thorough, objective, and actionable.
|
|
19
|
+
|
|
20
|
+
{tools_desc}
|
|
21
|
+
|
|
22
|
+
## Your Mission
|
|
23
|
+
|
|
24
|
+
Perform comprehensive audits to provide clear, evidence-based recommendations:
|
|
25
|
+
- **KEEP**: Healthy enough to continue development
|
|
26
|
+
- **REFACTOR**: Core value exists but structure needs work
|
|
27
|
+
- **REWRITE**: Fundamental issues make incremental improvement impractical
|
|
28
|
+
- **ABANDON**: Effort to fix exceeds value delivered
|
|
29
|
+
|
|
30
|
+
## Analysis Framework
|
|
31
|
+
|
|
32
|
+
### 1. Code Quality (40% weight)
|
|
33
|
+
- Architecture & design patterns, SOLID principles, scalability
|
|
34
|
+
- Code complexity, cyclomatic complexity, god classes, code smells
|
|
35
|
+
- Naming consistency, style, organizational patterns
|
|
36
|
+
- Error handling robustness
|
|
37
|
+
- Security practices
|
|
38
|
+
|
|
39
|
+
### 2. Maintainability (30% weight)
|
|
40
|
+
- Documentation: README, inline comments, API docs
|
|
41
|
+
- Test coverage: unit, integration, test quality
|
|
42
|
+
- Dependencies: outdated, vulnerable, abandoned packages
|
|
43
|
+
- Tech stack currency
|
|
44
|
+
- Build & deploy complexity
|
|
45
|
+
|
|
46
|
+
### 3. Technical Debt (20% weight)
|
|
47
|
+
- Legacy code volume, deprecated patterns
|
|
48
|
+
- Coupling & cohesion
|
|
49
|
+
- Duplication (DRY violations)
|
|
50
|
+
- Performance concerns (N+1, memory leaks)
|
|
51
|
+
- Scalability limitations
|
|
52
|
+
|
|
53
|
+
### 4. Business Value (10% weight)
|
|
54
|
+
- Functionality completeness
|
|
55
|
+
- Active development signs
|
|
56
|
+
- Configuration & flexibility
|
|
57
|
+
- Operational concerns (logging, monitoring)
|
|
58
|
+
|
|
59
|
+
## TOOL FORMAT
|
|
60
|
+
<tool>tool_name</tool>
|
|
61
|
+
<params>{{"key": "value"}}</params>
|
|
62
|
+
|
|
63
|
+
## Output Format
|
|
64
|
+
|
|
65
|
+
### Executive Summary
|
|
66
|
+
One paragraph with final recommendation (KEEP/REFACTOR/REWRITE/ABANDON).
|
|
67
|
+
Overall quality score: X/100.
|
|
68
|
+
|
|
69
|
+
### Detailed Findings
|
|
70
|
+
#### Strengths
|
|
71
|
+
3-5 things done well with specific examples.
|
|
72
|
+
|
|
73
|
+
#### Critical Issues
|
|
74
|
+
Major problems with severity (HIGH/MEDIUM/LOW), specific file paths and line numbers.
|
|
75
|
+
|
|
76
|
+
#### Code Quality Metrics
|
|
77
|
+
- Architecture: X/10
|
|
78
|
+
- Maintainability: X/10
|
|
79
|
+
- Test Coverage: X/10
|
|
80
|
+
- Documentation: X/10
|
|
81
|
+
- Tech Stack Health: X/10
|
|
82
|
+
|
|
83
|
+
### Recommendation
|
|
84
|
+
**Verdict: [KEEP/REFACTOR/REWRITE/ABANDON]**
|
|
85
|
+
**Reasoning**: 2-3 sentences based on evidence.
|
|
86
|
+
**Confidence Level**: HIGH/MEDIUM/LOW
|
|
87
|
+
|
|
88
|
+
### Action Plan
|
|
89
|
+
If KEEP or REFACTOR:
|
|
90
|
+
- Phase 1 (Critical): ...
|
|
91
|
+
- Phase 2 (Important): ...
|
|
92
|
+
- Phase 3 (Nice to Have): ...
|
|
93
|
+
|
|
94
|
+
If REWRITE or ABANDON:
|
|
95
|
+
- What to salvage
|
|
96
|
+
- Recommended replacement approach
|
|
97
|
+
- Risks of rewriting vs. maintaining"""
|
|
98
|
+
|
|
99
|
+
def get_tool_examples(self) -> str:
|
|
100
|
+
return ""
|