Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions agent_go/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
"""

import json
import logging
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field

__all__ = ["load_agent_type", "list_agent_types"]

logger = logging.getLogger(__name__)

AGENT_GO_AGENTS_DIR = Path.home() / ".agent_go" / "agents"
AGENT_GO_AGENTS_DIR.mkdir(parents=True, exist_ok=True)

Expand Down Expand Up @@ -90,8 +93,8 @@ def load_agent_type(name: str, project_root: Optional[Path] = None) -> Optional[
claude_config=data.get("claude_config", {}),
preload_skills=data.get("preload_skills", []),
)
except (json.JSONDecodeError, Exception):
pass
except (json.JSONDecodeError, OSError, KeyError) as e:
logger.debug("Failed to load agent type from %s: %s", path, e)

# 降级到内置类型
builtin = _BUILTIN_AGENTS.get(name)
Expand Down Expand Up @@ -129,8 +132,8 @@ def list_agent_types() -> list[dict]:
"source": "user",
})
seen.add(name)
except json.JSONDecodeError:
pass
except json.JSONDecodeError as e:
logger.debug("Invalid JSON in agent file %s: %s", f, e)

return result

Expand Down
23 changes: 14 additions & 9 deletions agent_go/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from pathlib import Path
from datetime import datetime

logger = logging.getLogger(__name__)

from .config import get_api_key, log_event, DECOMPOSE_RULES, AGENT_GO_DIR
from .git_utils import analyze_project, get_git_info, get_resource_map
from .skills import list_skills
Expand Down Expand Up @@ -74,7 +76,8 @@ def call_api(config, messages, logger):
except urllib.error.HTTPError as e:
try:
err_body = e.read().decode("utf-8", errors="replace")[:500]
except Exception:
except Exception as exc:
logger.debug("Failed to read HTTP error body: %s", exc)
err_body = str(e)
log_event(logger, "api_error", {
"provider": provider, "status_code": e.code,
Expand Down Expand Up @@ -312,7 +315,8 @@ def load_cached_plan(cache_key, task, config, logger):

try:
entry = json.loads(cache_file.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
except (json.JSONDecodeError, OSError) as e:
logger.debug("Corrupt or missing cache file %s: %s", cache_file, e)
return None

ttl = config.get("cache", {}).get("plan_ttl", 86400)
Expand All @@ -324,8 +328,8 @@ def load_cached_plan(cache_key, task, config, logger):
cache_file.unlink(missing_ok=True)
logger.info(f"[缓存] 已过期,删除: {cache_key[:12]}...")
return None
except ValueError:
pass
except ValueError as e:
logger.debug("Invalid cache timestamp in %s: %s", cache_key[:12], e)

plan = entry.get("plan")
if not plan or not plan.get("steps"):
Expand Down Expand Up @@ -381,7 +385,8 @@ def _format_age(iso_str):
elif age < 86400:
return f"{int(age // 3600)}h前"
return f"{int(age // 86400)}d前"
except Exception:
except Exception as e:
logger.debug("Failed to format age for '%s': %s", iso_str, e)
return "?"


Expand All @@ -394,8 +399,8 @@ def list_cache_entries():
try:
e = json.loads(f.read_text(encoding="utf-8"))
entries.append(e)
except (json.JSONDecodeError, OSError):
pass
except (json.JSONDecodeError, OSError) as e:
logger.debug("Failed to read cache entry %s: %s", f, e)
return sorted(entries, key=lambda e: e.get("meta", {}).get("created_at", ""), reverse=True)


Expand All @@ -413,6 +418,6 @@ def clean_expired_cache(config):
if f.exists():
f.unlink()
removed += 1
except ValueError:
pass
except ValueError as e:
logger.debug("Invalid timestamp in cache entry: %s", e)
return removed
37 changes: 21 additions & 16 deletions agent_go/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from pathlib import Path
from datetime import datetime

logger = logging.getLogger(__name__)

from .config import load_config, safe_input, setup_logger, AGENT_GO_DIR
from .api import generate_plan, decompose_fallback
from .ui import confirm_plan, plan_to_md, plan_to_subtasks, confirm_subtasks
Expand Down Expand Up @@ -39,6 +41,7 @@ def cmd_run():
sys.argv.pop(pi + 1)
sys.argv.pop(pi)
except (IndexError, ValueError):
logger.debug("Invalid --parallel value, defaulting to 3")
parallel = 3

# 并发模式要求 headless(避免同时打开多个交互式 Claude Code 终端)
Expand All @@ -58,7 +61,7 @@ def cmd_run():
sys.argv.pop(ri + 1)
sys.argv.pop(ri)
except (IndexError, ValueError):
pass
logger.debug("Invalid --remote flag value, ignoring")

if "--issue" in sys.argv:
try:
Expand All @@ -67,7 +70,7 @@ def cmd_run():
sys.argv.pop(iss_idx + 1)
sys.argv.pop(iss_idx)
except (IndexError, ValueError):
pass
logger.debug("Invalid --issue flag value, ignoring")

if "--docs" in sys.argv:
docs_idx = sys.argv.index("--docs")
Expand All @@ -83,7 +86,7 @@ def cmd_run():
sys.argv.pop(sk_idx + 1)
sys.argv.pop(sk_idx)
except (IndexError, ValueError):
pass
logger.debug("Invalid --skill flag value, ignoring")

if "--agent-type" in sys.argv:
try:
Expand All @@ -92,7 +95,7 @@ def cmd_run():
sys.argv.pop(ag_idx + 1)
sys.argv.pop(ag_idx)
except (IndexError, ValueError):
pass
logger.debug("Invalid --agent-type flag value, ignoring")

if len(sys.argv) < 3:
print("Usage: agent_go run <repo-path> '<task>' [--docs <doc1,doc2>] [--skill <name>] [--agent-type <type>] [--yes] [--headless] [--issue <N>] [--parallel N] [--remote <url>]")
Expand Down Expand Up @@ -122,6 +125,7 @@ def cmd_run():
task_dir.mkdir(parents=True, exist_ok=False)
break
except FileExistsError:
# 任务 ID 碰撞,重试下一轮
time.sleep(0.01)
else:
task_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -274,8 +278,8 @@ def cmd_resume():
try:
r = json.loads(result_file.read_text(encoding="utf-8"))
results.append(r)
except (json.JSONDecodeError, OSError):
pass
except (json.JSONDecodeError, OSError) as e:
logger.debug("Failed to read result for %s: %s", st["id"], e)
worktree_map = {}
results_map = {}
completed_ids = set()
Expand All @@ -301,13 +305,14 @@ def cmd_resume():
pi = sys.argv.index("--parallel")
parallel = max(1, int(sys.argv[pi + 1]))
except (IndexError, ValueError):
logger.debug("Invalid --parallel value, defaulting to 3")
parallel = 3
if "--remote" in sys.argv:
try:
ri = sys.argv.index("--remote")
remote_url = sys.argv[ri + 1]
except (IndexError, ValueError):
pass
logger.debug("Invalid --remote flag value, ignoring")
issue_ref = meta.get("issue", "")

if auto_yes:
Expand Down Expand Up @@ -398,7 +403,7 @@ def cmd_review():
try:
pr_ref = sys.argv[sys.argv.index("--pr") + 1]
except (IndexError, ValueError):
pass
logger.debug("Invalid --pr flag value, ignoring")

prompt = "请审查当前项目的代码变更,输出审查报告。重点检查:安全性、错误处理、代码质量、潜在bug。"
if pr_ref:
Expand Down Expand Up @@ -539,8 +544,8 @@ def _get_task_status(task_dir):
try:
evt = json.loads(line.split(" | ")[-1].strip())
current = evt.get("title", current)
except Exception:
pass
except (json.JSONDecodeError, KeyError, IndexError):
logger.debug("Failed to parse subtask_start event from log")
break
progress = f"{completed}/{total}" if total > 0 else "-"
icon = {"completed": "✅", "degraded": "⚠️", "running": "🔄", "failed": "❌", "aborted": "⏹️"}.get(status, "❓")
Expand All @@ -558,8 +563,8 @@ def _get_task_status(task_dir):
end = datetime.now()
delta = end - start
elapsed = f"{int(delta.total_seconds() // 60)}m{int(delta.total_seconds() % 60)}s"
except Exception:
pass
except ValueError:
logger.debug("Failed to parse elapsed time from created timestamp")
tail_lines = _get_task_tail_lines(log_path) if verbose and status == "running" else []
return {
"id": task_dir.name, "icon": icon, "status": status,
Expand Down Expand Up @@ -623,8 +628,8 @@ def cmd_clean():
repo_str = meta.get("repo", "")
if repo_str and Path(repo_str).exists():
repos_to_prune.add(repo_str)
except (json.JSONDecodeError, OSError):
pass
except (json.JSONDecodeError, OSError) as e:
logger.debug("Failed to read meta for %s: %s", t.name, e)
for t in tasks:
# 读取 task_id 用于清理 tag
meta_path = t / "meta.json"
Expand All @@ -633,8 +638,8 @@ def cmd_clean():
try:
meta = json.loads(meta_path.read_text(encoding="utf-8"))
task_id = meta.get("task_id", t.name)
except (json.JSONDecodeError, OSError):
pass
except (json.JSONDecodeError, OSError) as e:
logger.debug("Failed to read task_id from %s: %s", meta_path, e)
_shutil.rmtree(t, ignore_errors=True)
for repo_path in repos_to_prune:
subprocess.run(["git", "worktree", "prune"], cwd=repo_path, capture_output=True)
Expand Down
12 changes: 8 additions & 4 deletions agent_go/eval.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging
from pathlib import Path
from datetime import datetime

Expand All @@ -7,6 +8,9 @@
"aggregate_quality", "aggregate_performance", "cmd_eval",
]

logger = logging.getLogger(__name__)


def _read_meta(task_dir):
path = Path(task_dir) / "meta.json"
if not path.exists():
Expand All @@ -23,8 +27,8 @@ def _read_log_events(log_path, event_name):
try:
json_part = line.split(" | ")[-1]
events.append(json.loads(json_part))
except (json.JSONDecodeError, IndexError):
pass
except (json.JSONDecodeError, IndexError) as e:
logger.debug("Failed to parse log event line: %s", e)
return events


Expand Down Expand Up @@ -156,8 +160,8 @@ def analyze_performance(meta, log_path=None):
first_ts = datetime.strptime(lines[0].split(" | ")[0], "%Y-%m-%d %H:%M:%S")
last_ts = datetime.strptime(lines[-1].split(" | ")[0], "%Y-%m-%d %H:%M:%S")
p1 = round((last_ts - first_ts).total_seconds(), 1)
except (ValueError, IndexError):
pass
except (ValueError, IndexError) as e:
logger.debug("Failed to parse log timestamps: %s", e)
if p1 > 0:
p6 = round(sum_duration / p1 * 100)

Expand Down
9 changes: 6 additions & 3 deletions agent_go/git_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

__all__ = ["analyze_project", "get_git_info", "get_resource_map"]

logger = logging.getLogger(__name__)

def analyze_project(repo):
"""分析项目结构,返回文件列表和关键目录。"""
try:
Expand All @@ -16,7 +18,8 @@ def analyze_project(repo):
result = subprocess.run(["find", ".", "-maxdepth", "2", "-type", "f"], cwd=str(repo), capture_output=True, text=True, timeout=5)
files = result.stdout.strip().split("\n")[:30]
return "\n".join(f.lstrip("./") for f in files)
except (FileNotFoundError, subprocess.SubprocessError):
except (FileNotFoundError, subprocess.SubprocessError) as e:
logger.debug("Failed to analyze project: %s", e)
return ""

def get_git_info(repo):
Expand All @@ -32,8 +35,8 @@ def get_git_info(repo):
c = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=str(repo), capture_output=True, text=True, timeout=3)
if c.returncode == 0:
info["commit"] = c.stdout.strip()
except (FileNotFoundError, subprocess.SubprocessError):
pass
except (FileNotFoundError, subprocess.SubprocessError) as e:
logger.debug("Failed to get git info: %s", e)
return info

def _worktree_create(repo, branch, worktree_path):
Expand Down
3 changes: 3 additions & 0 deletions agent_go/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from pathlib import Path
from datetime import datetime

logger = logging.getLogger(__name__)

from .executor import run_subtask
from .git_utils import _set_gc_auto, _worktree_remove, _worktree_prune

Expand Down Expand Up @@ -40,6 +42,7 @@ def _on_interrupt(signum, frame):
try:
os.kill(pid, signal.SIGKILL)
except (ProcessLookupError, PermissionError):
# Process may have already exited between enumerate and kill
pass
logger.info(f"任务已暂停 ({len(completed_ids)}/{total}),可通过 agent_go resume {task_id} 恢复")
sys.exit(0)
Expand Down
7 changes: 5 additions & 2 deletions agent_go/role_skill_map.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import json
import logging
from pathlib import Path
from fnmatch import fnmatch

logger = logging.getLogger(__name__)

from .config import AGENT_GO_DIR

__all__ = ["load_role_skill_map", "apply_rules"]
Expand Down Expand Up @@ -52,8 +55,8 @@ def _load_json(path):
if path and path.exists():
try:
return json.loads(path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
pass
except (json.JSONDecodeError, OSError) as e:
logger.debug("Failed to load JSON from %s: %s", path, e)
return None


Expand Down
7 changes: 5 additions & 2 deletions agent_go/skills.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import re
import json
import logging
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field
Expand All @@ -24,6 +25,8 @@
"render_skill_for_plan", "render_skill_for_execution",
]

logger = logging.getLogger(__name__)

AGENT_GO_SKILLS_DIR = Path.home() / ".agent_go" / "skills"
AGENT_GO_SKILLS_DIR.mkdir(parents=True, exist_ok=True)

Expand Down Expand Up @@ -76,8 +79,8 @@ def _parse_frontmatter(text: str) -> tuple[dict, str]:
elif value.startswith("[") and value.endswith("]"):
try:
value = json.loads(value)
except json.JSONDecodeError:
pass
except json.JSONDecodeError as e:
logger.debug("Failed to parse JSON list in frontmatter key '%s': %s", key, e)
frontmatter[key] = value
return frontmatter, body.strip()

Expand Down
Loading
Loading