tagword-codeagent 1.1.6__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.
Files changed (173) hide show
  1. codeagent/__init__.py +10 -0
  2. codeagent/__main__.py +13 -0
  3. codeagent/cli/__init__.py +13 -0
  4. codeagent/cli/entrypoint.py +161 -0
  5. codeagent/cli/main.py +979 -0
  6. codeagent/core/__init__.py +2 -0
  7. codeagent/core/attachments.py +342 -0
  8. codeagent/core/audio_models.py +50 -0
  9. codeagent/core/bootstrap.py +178 -0
  10. codeagent/core/default_presets.py +159 -0
  11. codeagent/core/env.py +106 -0
  12. codeagent/core/folder_picker.py +151 -0
  13. codeagent/core/image_understanding.py +90 -0
  14. codeagent/core/models.py +6 -0
  15. codeagent/core/paths.py +238 -0
  16. codeagent/core/pricing.py +107 -0
  17. codeagent/core/process_ports.py +258 -0
  18. codeagent/core/seed_bridge.py +21 -0
  19. codeagent/core/settings.py +98 -0
  20. codeagent/core/speech_synth.py +330 -0
  21. codeagent/core/team_config.py +247 -0
  22. codeagent/core/team_manager.py +245 -0
  23. codeagent/core/token_counter.py +41 -0
  24. codeagent/core/tts_voices.py +103 -0
  25. codeagent/core/usage_billing.py +72 -0
  26. codeagent/core/vision_models.py +93 -0
  27. codeagent/memory/diary.py +144 -0
  28. codeagent/persona_defaults/README.md +12 -0
  29. codeagent/persona_defaults/agent.md +352 -0
  30. codeagent/persona_defaults/identity.md +29 -0
  31. codeagent/persona_defaults/memory.md +4 -0
  32. codeagent/persona_defaults/skills.md +325 -0
  33. codeagent/persona_defaults/soul.md +38 -0
  34. codeagent/persona_defaults/tools.md +41 -0
  35. codeagent/persona_defaults/user.md +18 -0
  36. codeagent/runtime/__init__.py +11 -0
  37. codeagent/runtime/agent_context.py +6 -0
  38. codeagent/runtime/agent_runtime.py +21 -0
  39. codeagent/runtime/compact_prompt.py +9 -0
  40. codeagent/runtime/compact_state.py +40 -0
  41. codeagent/runtime/llm_worker.py +132 -0
  42. codeagent/runtime/orchestrator.py +161 -0
  43. codeagent/runtime/prompt_enrichment.py +324 -0
  44. codeagent/runtime/session_manager.py +30 -0
  45. codeagent/runtime/task_split.py +38 -0
  46. codeagent/runtime/turn_loop.py +13 -0
  47. codeagent/runtime/worker.py +48 -0
  48. codeagent/server/__init__.py +505 -0
  49. codeagent/server/app_factory.py +1292 -0
  50. codeagent/server/attachment_api.py +261 -0
  51. codeagent/server/hub.py +175 -0
  52. codeagent/server/icon.png +0 -0
  53. codeagent/server/self_healing.py +143 -0
  54. codeagent/server/team_engine.py +243 -0
  55. codeagent/server/tts_api.py +51 -0
  56. codeagent/server/webui_api_app.py +3180 -0
  57. codeagent/skills/__init__.py +2 -0
  58. codeagent/skills/select.py +144 -0
  59. codeagent/tools/__init__.py +6 -0
  60. codeagent/tools/agent_tools.py +10 -0
  61. codeagent/web/__init__.py +1 -0
  62. codeagent/web/__pycache__/__init__.cpython-313.pyc +0 -0
  63. codeagent/web/__pycache__/app.cpython-313.pyc +0 -0
  64. codeagent/web/__pycache__/auth_impl.cpython-313.pyc +0 -0
  65. codeagent/web/auth_impl.py +326 -0
  66. codeagent/web/static/00-marked.min.js +6 -0
  67. codeagent/web/static/00-mermaid.min.js +2314 -0
  68. codeagent/web/static/00-purify.min.js +3 -0
  69. codeagent/web/static/00-storage.js +83 -0
  70. codeagent/web/static/00-utils.js +51 -0
  71. codeagent/web/static/01-theme.css +96 -0
  72. codeagent/web/static/01a-scroll.js +86 -0
  73. codeagent/web/static/01b-think.js +62 -0
  74. codeagent/web/static/01c-session-identity.js +81 -0
  75. codeagent/web/static/01c-session-thinking.js +61 -0
  76. codeagent/web/static/01c-session-tree-menus.js +349 -0
  77. codeagent/web/static/01c-session-tree.js +531 -0
  78. codeagent/web/static/01c-session-utilities.js +83 -0
  79. codeagent/web/static/01c-vision-model.js +132 -0
  80. codeagent/web/static/01d-image-gen-model.js +84 -0
  81. codeagent/web/static/01e-audio-model.js +97 -0
  82. codeagent/web/static/01f-compose-ui.js +88 -0
  83. codeagent/web/static/01g-tts-settings.js +128 -0
  84. codeagent/web/static/01h-music-model.js +85 -0
  85. codeagent/web/static/01i-model-stack.js +291 -0
  86. codeagent/web/static/01j-video-gen-model.js +85 -0
  87. codeagent/web/static/01k-model-stack-bootstrap.js +66 -0
  88. codeagent/web/static/01k-model-stack-state.js +209 -0
  89. codeagent/web/static/01q-inflight.js +195 -0
  90. codeagent/web/static/02-reset.css +22 -0
  91. codeagent/web/static/02-session-ui.js +201 -0
  92. codeagent/web/static/03-layout-p1.css +2 -0
  93. codeagent/web/static/03-layout-p2.css +2 -0
  94. codeagent/web/static/03a-links-stream.js +88 -0
  95. codeagent/web/static/03b-stream-text.js +119 -0
  96. codeagent/web/static/03c-render-bubble.js +520 -0
  97. codeagent/web/static/03d-agent-bubble.js +126 -0
  98. codeagent/web/static/03e-tool-trace.js +182 -0
  99. codeagent/web/static/03f-timeline.js +54 -0
  100. codeagent/web/static/03g-bubble-tts.js +292 -0
  101. codeagent/web/static/04-components-p1.css +1 -0
  102. codeagent/web/static/04-components-p2b.css +1 -0
  103. codeagent/web/static/04-components-p3.css +2 -0
  104. codeagent/web/static/04-components-p4.css +1 -0
  105. codeagent/web/static/04-components-p5.css +1 -0
  106. codeagent/web/static/04-components-p6.css +58 -0
  107. codeagent/web/static/04-components-p7.css +4 -0
  108. codeagent/web/static/04-components-p8.css +1 -0
  109. codeagent/web/static/04-components-p9.css +1 -0
  110. codeagent/web/static/04-ws-connect.js +351 -0
  111. codeagent/web/static/04-ws-helpers.js +116 -0
  112. codeagent/web/static/05-chat-p1.css +1058 -0
  113. codeagent/web/static/05-chat-p2.css +1 -0
  114. codeagent/web/static/05-chat-p3.css +295 -0
  115. codeagent/web/static/05a-session-history.js +176 -0
  116. codeagent/web/static/05b-session-list.js +114 -0
  117. codeagent/web/static/05c-dialog.js +123 -0
  118. codeagent/web/static/05d-project-create.js +172 -0
  119. codeagent/web/static/05e-project-remote.js +143 -0
  120. codeagent/web/static/06-chat.js +552 -0
  121. codeagent/web/static/06-utilities.css +181 -0
  122. codeagent/web/static/06b-attachments.js +304 -0
  123. codeagent/web/static/06c-camera.js +488 -0
  124. codeagent/web/static/07-activity-bar.css +127 -0
  125. codeagent/web/static/09-git-p1.css +1 -0
  126. codeagent/web/static/09-git-p2.css +1 -0
  127. codeagent/web/static/09a-init-bind.js +110 -0
  128. codeagent/web/static/09b-panel-toggle.js +80 -0
  129. codeagent/web/static/09c-api-refresh.js +100 -0
  130. codeagent/web/static/09d-status-log.js +80 -0
  131. codeagent/web/static/09e-commit.js +80 -0
  132. codeagent/web/static/09f-remote.js +93 -0
  133. codeagent/web/static/11a-cron-parse.js +117 -0
  134. codeagent/web/static/11b-cron-panel.js +100 -0
  135. codeagent/web/static/11c-cron-card.js +133 -0
  136. codeagent/web/static/11d-cron-form.js +105 -0
  137. codeagent/web/static/11e-env-config.js +168 -0
  138. codeagent/web/static/11f-env-llm-a-state.js +136 -0
  139. codeagent/web/static/11f-env-llm-b-form.js +409 -0
  140. codeagent/web/static/11f-env-llm-c-board.js +322 -0
  141. codeagent/web/static/11g-env-paths-git.js +973 -0
  142. codeagent/web/static/11h-env-mcp-a-state.js +161 -0
  143. codeagent/web/static/11h-env-mcp-b-form.js +229 -0
  144. codeagent/web/static/11h-env-mcp-c-board.js +565 -0
  145. codeagent/web/static/12-plugins.js +127 -0
  146. codeagent/web/static/13a-skills.js +156 -0
  147. codeagent/web/static/13a-todo-utils.js +140 -0
  148. codeagent/web/static/13b-todo-fetch.js +106 -0
  149. codeagent/web/static/13b-tools.js +127 -0
  150. codeagent/web/static/13c-todo-crud.js +92 -0
  151. codeagent/web/static/14-activity-bar.js +177 -0
  152. codeagent/web/static/15-plans.css +194 -0
  153. codeagent/web/static/15-plans.js +219 -0
  154. codeagent/web/static/16-mobile.css +612 -0
  155. codeagent/web/static/16-mobile.js +178 -0
  156. codeagent/web/static/17-preset-ux.css +287 -0
  157. codeagent/web/static/18-agent-mgr.css +616 -0
  158. codeagent/web/static/18-agent-mgr.js +204 -0
  159. codeagent/web/static/24-health-dashboard.js +68 -0
  160. codeagent/web/static/99-brand-polish.css +152 -0
  161. codeagent/web/static/body.html +824 -0
  162. codeagent/web/static/setup/setup_form.html +171 -0
  163. codeagent/web/static/setup/setup_head.html +100 -0
  164. codeagent/web/static/setup/setup_tail.html +264 -0
  165. codeagent/web/static/setup/setup_test.html +38 -0
  166. codeagent/web/web_login.html +265 -0
  167. codeagent/web/webui.html +35 -0
  168. tagword_codeagent-1.1.6.dist-info/METADATA +273 -0
  169. tagword_codeagent-1.1.6.dist-info/RECORD +173 -0
  170. tagword_codeagent-1.1.6.dist-info/WHEEL +5 -0
  171. tagword_codeagent-1.1.6.dist-info/entry_points.txt +3 -0
  172. tagword_codeagent-1.1.6.dist-info/licenses/LICENSE +21 -0
  173. tagword_codeagent-1.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,243 @@
1
+ """Team workflow engine — executes multi-agent team runs.
2
+
3
+ Three modes:
4
+ - sequential: members run one after another, passing context
5
+ - parallel: all members run simultaneously
6
+ - manager: first member is PM who splits and dispatches to others
7
+
8
+ Each run is persisted as a JSON file in ~/.codeagent/runs/
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import logging
15
+ import time
16
+ import uuid
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ from codeagent.core.paths import codeagent_home
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ RUN_STATUS_PENDING = "pending"
25
+ RUN_STATUS_RUNNING = "running"
26
+ RUN_STATUS_DONE = "done"
27
+ RUN_STATUS_FAILED = "failed"
28
+ RUN_STATUS_TIMEOUT = "timeout"
29
+
30
+ STEP_STATUS_PENDING = "pending"
31
+ STEP_STATUS_RUNNING = "running"
32
+ STEP_STATUS_DONE = "done"
33
+ STEP_STATUS_FAILED = "failed"
34
+
35
+
36
+ def _runs_dir() -> Path:
37
+ p = codeagent_home() / "runs"
38
+ p.mkdir(parents=True, exist_ok=True)
39
+ return p
40
+
41
+
42
+ def _teams_dir() -> Path:
43
+ p = codeagent_home() / "teams"
44
+ p.mkdir(parents=True, exist_ok=True)
45
+ return p
46
+
47
+
48
+ def list_runs(team_id: str | None = None, limit: int = 50) -> list[dict]:
49
+ """List runs, optionally filtered by team_id."""
50
+ rd = _runs_dir()
51
+ runs = []
52
+ for f in sorted(rd.glob("*.json"), reverse=True):
53
+ if len(runs) >= limit:
54
+ break
55
+ try:
56
+ data = json.loads(f.read_text(encoding="utf-8"))
57
+ data["id"] = f.stem
58
+ if team_id and data.get("team_id") != team_id:
59
+ continue
60
+ runs.append(data)
61
+ except (json.JSONDecodeError, OSError):
62
+ pass
63
+ return runs
64
+
65
+
66
+ def create_run(team_id: str, user_input: str) -> dict:
67
+ """Create a new run record and return it."""
68
+ run_id = uuid.uuid4().hex[:12]
69
+ run = {
70
+ "team_id": team_id,
71
+ "user_input": user_input,
72
+ "status": RUN_STATUS_PENDING,
73
+ "created_at": time.time(),
74
+ "updated_at": time.time(),
75
+ "steps": [],
76
+ }
77
+ f = _runs_dir() / f"{run_id}.json"
78
+ f.write_text(json.dumps(run, indent=2, ensure_ascii=False), encoding="utf-8")
79
+ run["id"] = run_id
80
+ return run
81
+
82
+
83
+ def get_run(run_id: str) -> dict | None:
84
+ """Get run by id."""
85
+ f = _runs_dir() / f"{run_id}.json"
86
+ if not f.is_file():
87
+ return None
88
+ try:
89
+ data = json.loads(f.read_text(encoding="utf-8"))
90
+ data["id"] = run_id
91
+ return data
92
+ except (json.JSONDecodeError, OSError):
93
+ return None
94
+
95
+
96
+ def update_run(run_id: str, updates: dict) -> dict | None:
97
+ """Update run fields."""
98
+ f = _runs_dir() / f"{run_id}.json"
99
+ if not f.is_file():
100
+ return None
101
+ data = get_run(run_id)
102
+ if data is None:
103
+ return None
104
+ data.update(updates)
105
+ data["updated_at"] = time.time()
106
+ f.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
107
+ return data
108
+
109
+
110
+ def add_step(run_id: str, agent_id: str, step_type: str) -> dict | None:
111
+ """Add a step to a run, return the step."""
112
+ run = get_run(run_id)
113
+ if run is None:
114
+ return None
115
+ step = {
116
+ "step_id": uuid.uuid4().hex[:8],
117
+ "agent_id": agent_id,
118
+ "type": step_type,
119
+ "status": STEP_STATUS_PENDING,
120
+ "input": "",
121
+ "output": "",
122
+ "created_at": time.time(),
123
+ }
124
+ run["steps"].append(step)
125
+ update_run(run_id, {"steps": run["steps"]})
126
+ return step
127
+
128
+
129
+ def update_step(run_id: str, step_id: str, updates: dict) -> dict | None:
130
+ """Update a step within a run."""
131
+ run = get_run(run_id)
132
+ if run is None:
133
+ return None
134
+ for step in run["steps"]:
135
+ if step.get("step_id") == step_id:
136
+ step.update(updates)
137
+ break
138
+ update_run(run_id, {"steps": run["steps"]})
139
+ return run
140
+
141
+
142
+ def run_team(team_id: str, user_input: str) -> dict:
143
+ """Execute a team workflow. Returns immediately with run_id; actual execution is simulated.
144
+
145
+ For a real implementation, this would spin up agents via the chat API.
146
+ """
147
+ # Load team
148
+ tf = _teams_dir() / f"{team_id}.json"
149
+ if not tf.is_file():
150
+ raise ValueError(f"Team '{team_id}' not found")
151
+ team = json.loads(tf.read_text(encoding="utf-8"))
152
+ team["id"] = team_id
153
+
154
+ # Create run
155
+ run = create_run(team_id, user_input)
156
+ run_id = run["id"]
157
+ update_run(run_id, {"status": RUN_STATUS_RUNNING})
158
+
159
+ mode = team.get("mode", "sequential")
160
+ members = team.get("members", [])
161
+ error_policy = team.get("error_policy", "stop")
162
+ timeout = team.get("timeout_seconds", 300)
163
+
164
+ if mode == "sequential":
165
+ _run_sequential(run_id, members, user_input, error_policy, timeout)
166
+ elif mode == "parallel":
167
+ _run_parallel(run_id, members, user_input, error_policy, timeout)
168
+ elif mode == "manager":
169
+ _run_manager(run_id, members, user_input, error_policy, timeout, manager_id=team.get("manager_id", ""))
170
+ else:
171
+ update_run(run_id, {"status": RUN_STATUS_FAILED, "error": f"Unknown mode: {mode}"})
172
+
173
+ update_run(run_id, {"status": RUN_STATUS_DONE})
174
+ return get_run(run_id) or run
175
+
176
+
177
+ def _run_sequential(run_id: str, members: list, user_input: str, error_policy: str, timeout: int) -> None:
178
+ """Run members one after another, passing context."""
179
+ context = user_input
180
+ for member in members:
181
+ agent_id = member if isinstance(member, str) else member.get("id", "")
182
+ step = add_step(run_id, agent_id, "sequential")
183
+ if step is None:
184
+ return
185
+ update_step(run_id, step["step_id"], {"status": STEP_STATUS_RUNNING, "input": context})
186
+ # Simulate execution (in real impl, this calls the agent)
187
+ time.sleep(0.5)
188
+ output = f"[模拟] Agent '{agent_id}' 处理完成:\n收到: {context[:100]}..."
189
+ update_step(run_id, step["step_id"], {"status": STEP_STATUS_DONE, "output": output})
190
+ context = output
191
+
192
+
193
+ def _run_parallel(run_id: str, members: list, user_input: str, error_policy: str, timeout: int) -> None:
194
+ """Run all members simultaneously."""
195
+ import concurrent.futures
196
+
197
+ def _run_one(agent_id: str) -> tuple[str, str, str]:
198
+ step = add_step(run_id, agent_id, "parallel")
199
+ sid = step["step_id"] if step else ""
200
+ update_step(run_id, sid, {"status": STEP_STATUS_RUNNING, "input": user_input})
201
+ time.sleep(0.3)
202
+ output = f"[模拟] Agent '{agent_id}' 并行处理完成"
203
+ update_step(run_id, sid, {"status": STEP_STATUS_DONE, "output": output})
204
+ return agent_id, sid, output
205
+
206
+ with concurrent.futures.ThreadPoolExecutor(max_workers=len(members)) as pool:
207
+ futures = []
208
+ for member in members:
209
+ agent_id = member if isinstance(member, str) else member.get("id", "")
210
+ futures.append(pool.submit(_run_one, agent_id))
211
+ concurrent.futures.wait(futures)
212
+
213
+
214
+ def _run_manager(run_id: str, members: list, user_input: str, error_policy: str, timeout: int, manager_id: str = "") -> None:
215
+ """First member is PM who dispatches to others. If manager_id is set, that member is PM."""
216
+ if not members:
217
+ return
218
+ # 显式指定的管家优先,否则取第一个成员
219
+ pm_id = manager_id if manager_id and manager_id in [m if isinstance(m, str) else m.get("id", "") for m in members] else (members[0] if isinstance(members[0], str) else members[0].get("id", ""))
220
+ workers = members[1:] if len(members) > 1 else []
221
+
222
+ # PM step: analyze and split
223
+ pm_step = add_step(run_id, pm_id, "manager-pm")
224
+ if pm_step is None:
225
+ return
226
+ update_step(run_id, pm_step["step_id"], {"status": STEP_STATUS_RUNNING, "input": user_input})
227
+ time.sleep(0.5)
228
+ pm_output = f"[模拟] PM '{pm_id}' 将任务拆分为 {max(len(workers), 1)} 个子任务"
229
+ update_step(run_id, pm_step["step_id"], {"status": STEP_STATUS_DONE, "output": pm_output})
230
+
231
+ # Worker steps
232
+ for i, worker in enumerate(workers):
233
+ wid = worker if isinstance(worker, str) else worker.get("id", "")
234
+ w_step = add_step(run_id, wid, "manager-worker")
235
+ if w_step is None:
236
+ return
237
+ update_step(run_id, w_step["step_id"], {
238
+ "status": STEP_STATUS_RUNNING,
239
+ "input": f"子任务 {i+1}: {user_input[:80]}..."
240
+ })
241
+ time.sleep(0.3)
242
+ w_output = f"[模拟] Worker '{wid}' 完成子任务 {i+1}"
243
+ update_step(run_id, w_step["step_id"], {"status": STEP_STATUS_DONE, "output": w_output})
@@ -0,0 +1,51 @@
1
+ """POST /api/tts — synthesize chat bubble text for playback."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from starlette.requests import Request
6
+ from starlette.responses import JSONResponse, Response
7
+
8
+ from codeagent.core.speech_synth import (
9
+ minimax_tts_configured,
10
+ synthesize_minimax_speech_with_detail,
11
+ tts_http_status_for_outcome,
12
+ )
13
+ from codeagent.core.tts_voices import normalize_tts_model, normalize_tts_voice_id
14
+
15
+
16
+ async def api_tts(request: Request):
17
+ try:
18
+ body = await request.json()
19
+ except Exception:
20
+ body = {}
21
+ if not isinstance(body, dict):
22
+ body = {}
23
+
24
+ text = str(body.get("text") or "").strip()
25
+ if not text:
26
+ return JSONResponse({"detail": "text required"}, status_code=422)
27
+ if len(text) > 10000:
28
+ return JSONResponse({"detail": "text too long (max 10000)"}, status_code=422)
29
+
30
+ voice_id = normalize_tts_voice_id(body.get("voice_id"))
31
+ model = normalize_tts_model(body.get("model"))
32
+
33
+ if not minimax_tts_configured():
34
+ return JSONResponse(
35
+ {"detail": "MiniMax TTS not configured", "fallback": True},
36
+ status_code=503,
37
+ )
38
+
39
+ out = synthesize_minimax_speech_with_detail(text, voice_id=voice_id, model=model)
40
+ if not out.ok or out.audio is None:
41
+ detail = out.error or "TTS synthesis failed"
42
+ return JSONResponse(
43
+ {
44
+ "detail": detail,
45
+ "fallback": True,
46
+ "status_code": out.status_code,
47
+ },
48
+ status_code=tts_http_status_for_outcome(out),
49
+ )
50
+
51
+ return Response(content=out.audio, media_type=out.mime)