发布类型: [feature/bugfix/hotfix/docs]

影响范围: [core/api/ui/config]
测试状态: [passed/failed/pending]
回滚策略: [已准备/无需回滚]
This commit is contained in:
ben 2025-08-31 01:42:50 +00:00
parent 7dd48c5781
commit 09a42d29ea
7 changed files with 1215 additions and 0 deletions

View File

@ -0,0 +1,227 @@
#!/usr/bin/env python3
"""
Agent Identity Manager
为每个AI agent提供独立的git身份和提交能力
这个系统让每个agent拥有
- 独立的SSH key对
- 独立的GPG签名key
- 独立的git配置name, email
- 可追溯的提交历史
模拟真实团队协作而非内部讨论
"""
import os
import json
import subprocess
import shutil
from pathlib import Path
from typing import Dict, List, Optional
import logging
class AgentIdentity:
"""单个agent的身份信息"""
def __init__(self, name: str, email: str, role: str):
self.name = name
self.email = email
self.role = role
self.ssh_key_path = None
self.gpg_key_id = None
def to_dict(self) -> Dict:
return {
"name": self.name,
"email": self.email,
"role": self.role,
"ssh_key_path": str(self.ssh_key_path) if self.ssh_key_path else None,
"gpg_key_id": self.gpg_key_id
}
class AgentIdentityManager:
"""管理所有agent的身份和git操作"""
def __init__(self, base_dir: str = "/home/ben/github/liurenchaxin"):
self.base_dir = Path(base_dir)
self.agents_dir = self.base_dir / "agents"
self.keys_dir = self.agents_dir / "keys"
self.config_file = self.agents_dir / "identities.json"
# 确保目录存在
self.agents_dir.mkdir(exist_ok=True)
self.keys_dir.mkdir(exist_ok=True)
self.identities: Dict[str, AgentIdentity] = {}
self.load_identities()
def load_identities(self):
"""从配置文件加载agent身份"""
if self.config_file.exists():
with open(self.config_file, 'r', encoding='utf-8') as f:
data = json.load(f)
for name, identity_data in data.items():
identity = AgentIdentity(
identity_data["name"],
identity_data["email"],
identity_data["role"]
)
identity.ssh_key_path = Path(identity_data["ssh_key_path"]) if identity_data["ssh_key_path"] else None
identity.gpg_key_id = identity_data["gpg_key_id"]
self.identities[name] = identity
def save_identities(self):
"""保存agent身份到配置文件"""
data = {name: identity.to_dict() for name, identity in self.identities.items()}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def create_agent(self, name: str, email: str, role: str) -> AgentIdentity:
"""创建新的agent身份"""
if name in self.identities:
raise ValueError(f"Agent {name} 已存在")
identity = AgentIdentity(name, email, role)
# 生成SSH key
ssh_key_path = self.keys_dir / f"{name}_rsa"
self._generate_ssh_key(name, email, ssh_key_path)
identity.ssh_key_path = ssh_key_path
# 生成GPG key
gpg_key_id = self._generate_gpg_key(name, email)
identity.gpg_key_id = gpg_key_id
self.identities[name] = identity
self.save_identities()
logging.info(f"创建agent: {name} ({role})")
return identity
def _generate_ssh_key(self, name: str, email: str, key_path: Path):
"""为agent生成SSH key"""
cmd = [
"ssh-keygen",
"-t", "rsa",
"-b", "4096",
"-C", email,
"-f", str(key_path),
"-N", "" # 空密码
]
try:
subprocess.run(cmd, check=True, capture_output=True)
logging.info(f"SSH key已生成: {key_path}")
except subprocess.CalledProcessError as e:
logging.error(f"生成SSH key失败: {e}")
raise
def _generate_gpg_key(self, name: str, email: str) -> str:
"""为agent生成GPG key"""
# 这里简化处理实际应该使用python-gnupg库
# 返回模拟的key ID
return f"{name.upper()}12345678"
def switch_to_agent(self, agent_name: str):
"""切换到指定agent身份"""
if agent_name not in self.identities:
raise ValueError(f"Agent {agent_name} 不存在")
identity = self.identities[agent_name]
# 设置git配置
commands = [
["git", "config", "user.name", identity.name],
["git", "config", "user.email", identity.email],
["git", "config", "user.signingkey", identity.gpg_key_id],
["git", "config", "commit.gpgsign", "true"]
]
for cmd in commands:
try:
subprocess.run(cmd, check=True, cwd=self.base_dir)
except subprocess.CalledProcessError as e:
logging.error(f"设置git配置失败: {e}")
raise
# 设置SSH key (通过ssh-agent)
if identity.ssh_key_path and identity.ssh_key_path.exists():
self._setup_ssh_agent(identity.ssh_key_path)
logging.info(f"已切换到agent: {agent_name}")
def _setup_ssh_agent(self, key_path: Path):
"""设置SSH agent使用指定key"""
# 这里简化处理实际应该管理ssh-agent
os.environ["GIT_SSH_COMMAND"] = f"ssh -i {key_path}"
def commit_as_agent(self, agent_name: str, message: str, files: List[str] = None):
"""以指定agent身份提交代码"""
self.switch_to_agent(agent_name)
# 添加文件
if files:
subprocess.run(["git", "add"] + files, check=True, cwd=self.base_dir)
else:
subprocess.run(["git", "add", "."], check=True, cwd=self.base_dir)
# 提交
subprocess.run(["git", "commit", "-S", "-m", message], check=True, cwd=self.base_dir)
logging.info(f"Agent {agent_name} 提交: {message}")
def list_agents(self) -> List[Dict]:
"""列出所有agent"""
return [identity.to_dict() for identity in self.identities.values()]
def get_agent_stats(self, agent_name: str) -> Dict:
"""获取agent的git统计信息"""
if agent_name not in self.identities:
raise ValueError(f"Agent {agent_name} 不存在")
identity = self.identities[agent_name]
# 获取提交统计
cmd = [
"git", "log", "--author", identity.email,
"--pretty=format:%h|%an|%ae|%ad|%s",
"--date=short"
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.base_dir)
commits = result.stdout.strip().split('\n') if result.stdout.strip() else []
return {
"agent_name": agent_name,
"total_commits": len(commits),
"commits": commits[:10] # 最近10条
}
except subprocess.CalledProcessError:
return {
"agent_name": agent_name,
"total_commits": 0,
"commits": []
}
# 使用示例和初始化
if __name__ == "__main__":
manager = AgentIdentityManager()
# 创建示例agents
agents_config = [
{"name": "claude-ai", "email": "claude@ai-collaboration.local", "role": "架构师"},
{"name": "gemini-dev", "email": "gemini@ai-collaboration.local", "role": "开发者"},
{"name": "qwen-ops", "email": "qwen@ai-collaboration.local", "role": "运维"},
{"name": "llama-research", "email": "llama@ai-collaboration.local", "role": "研究员"}
]
for agent in agents_config:
try:
manager.create_agent(agent["name"], agent["email"], agent["role"])
print(f"✅ 创建agent: {agent['name']}")
except ValueError as e:
print(f"⚠️ {e}")
print("\n📊 当前agent列表:")
for agent in manager.list_agents():
print(f" - {agent['name']} ({agent['role']}) - {agent['email']}")

0
agents/cli.py Normal file
View File

0
agents/cli_tool.py Normal file
View File

View File

@ -0,0 +1,270 @@
#!/usr/bin/env python3
"""
Agent协作演示
展示如何让不同AI agent以真实身份协作完成任务
这个演示模拟以下场景
1. 架构师agent设计系统架构
2. 开发者agent实现核心功能
3. 运维agent配置部署
4. 研究员agent撰写文档
每个步骤都有真实的git提交记录
"""
import os
import subprocess
import time
from pathlib import Path
from agent_identity_manager import AgentIdentityManager
class AgentCollaborationDemo:
def __init__(self):
self.manager = AgentIdentityManager()
self.base_dir = Path("/home/ben/github/liurenchaxin")
def create_demo_files(self):
"""创建演示用的文件"""
demo_dir = self.base_dir / "demo_feature"
demo_dir.mkdir(exist_ok=True)
# 架构师的设计文档
architecture_file = demo_dir / "architecture.md"
architecture_content = """# 新功能架构设计
## 概述
设计一个智能监控系统用于跟踪AI agent的工作状态
## 组件设计
- 状态收集器收集各agent的运行状态
- 分析引擎分析agent行为模式
- 告警系统异常行为实时通知
## 技术栈
- Python 3.9+
- Redis作为消息队列
- PostgreSQL存储状态数据
- FastAPI提供REST接口
"""
architecture_file.write_text(architecture_content)
# 开发者的实现代码
core_file = demo_dir / "monitor.py"
core_content = """#!/usr/bin/env python3
import asyncio
import json
from datetime import datetime
from typing import Dict, Any
class AgentMonitor:
def __init__(self):
self.agents_status = {}
async def collect_status(self, agent_name: str) -> Dict[str, Any]:
return {
"name": agent_name,
"timestamp": datetime.now().isoformat(),
"status": "active",
"tasks_completed": 0
}
async def run(self):
while True:
# 模拟状态收集
await asyncio.sleep(1)
if __name__ == "__main__":
monitor = AgentMonitor()
asyncio.run(monitor.run())
"""
core_file.write_text(core_content)
# 运维的配置文件
config_file = demo_dir / "deploy.yaml"
config_content = """version: '3.8'
services:
agent-monitor:
build: .
ports:
- "8000:8000"
environment:
- REDIS_URL=redis://redis:6379
- DB_URL=postgresql://user:pass@postgres:5432/agentdb
depends_on:
- redis
- postgres
redis:
image: redis:alpine
ports:
- "6379:6379"
postgres:
image: postgres:13
environment:
POSTGRES_DB: agentdb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
"""
config_file.write_text(config_content)
# 研究员的文档
docs_file = demo_dir / "usage_guide.md"
docs_content = """# Agent监控系统使用指南
## 快速开始
### 1. 启动监控服务
```bash
docker-compose up -d
```
### 2. 查看agent状态
```bash
curl http://localhost:8000/api/agents
```
### 3. 配置告警
编辑 `config/alerts.yaml` 文件设置告警规则
## API文档
### GET /api/agents
获取所有agent的当前状态
### POST /api/agents/{name}/task
记录agent完成的任务
"""
docs_file.write_text(docs_content)
return [architecture_file, core_file, config_file, docs_file]
def run_collaboration_demo(self):
"""运行协作演示"""
print("🎭 开始Agent协作演示")
print("=" * 50)
# 1. 架构师设计
print("1⃣ 架构师agent开始设计...")
files = self.create_demo_files()
self.manager.commit_as_agent(
"claude-ai",
"📐 设计智能监控系统架构 - 添加架构设计文档",
[str(f) for f in files[:1]]
)
time.sleep(1)
# 2. 开发者实现
print("2⃣ 开发者agent开始编码...")
self.manager.commit_as_agent(
"gemini-dev",
"💻 实现监控系统核心功能 - 添加AgentMonitor类",
[str(files[1])]
)
time.sleep(1)
# 3. 运维配置
print("3⃣ 运维agent配置部署...")
self.manager.commit_as_agent(
"qwen-ops",
"⚙️ 添加Docker部署配置 - 支持一键启动",
[str(files[2])]
)
time.sleep(1)
# 4. 研究员文档
print("4⃣ 研究员agent撰写文档...")
self.manager.commit_as_agent(
"llama-research",
"📚 完善使用文档 - 添加API说明和快速指南",
[str(files[3])]
)
time.sleep(1)
# 5. 架构师review
print("5⃣ 架构师review并优化...")
optimize_file = self.base_dir / "demo_feature" / "optimization.md"
optimize_content = """# 架构优化建议
基于实现代码的review提出以下优化
## 性能优化
- 使用asyncio.create_task替换直接调用
- 添加连接池管理
## 监控增强
- 添加prometheus指标收集
- 实现健康检查端点
## 下一步计划
1. 实现告警系统
2. 添加Web界面
3. 集成日志分析
"""
optimize_file.write_text(optimize_content)
self.manager.commit_as_agent(
"claude-ai",
"🔍 架构review - 提出性能优化和监控增强建议",
[str(optimize_file)]
)
print("\n✅ 协作演示完成!")
def show_git_history(self):
"""显示git提交历史"""
print("\n📊 Git提交历史按agent分组:")
print("=" * 50)
for agent_name in ["claude-ai", "gemini-dev", "qwen-ops", "llama-research"]:
stats = self.manager.get_agent_stats(agent_name)
if stats["commits"]:
print(f"\n👤 {agent_name}:")
for commit in stats["commits"]:
parts = commit.split("|", 4)
if len(parts) >= 5:
hash_id, name, email, date, message = parts
print(f" {hash_id[:8]} {date} {message}")
def cleanup_demo(self):
"""清理演示文件"""
demo_dir = self.base_dir / "demo_feature"
if demo_dir.exists():
# 保留git历史只移除工作区文件
subprocess.run(["git", "rm", "-rf", "demo_feature"],
cwd=self.base_dir, capture_output=True)
subprocess.run(["git", "commit", "-m", "🧹 清理演示文件 - 保留协作历史"],
cwd=self.base_dir, capture_output=True)
print("🧹 演示文件已清理git历史保留")
def main():
"""主函数"""
demo = AgentCollaborationDemo()
print("🎭 AI Agent协作演示")
print("=" * 50)
print("这个演示将展示如何让不同agent以真实身份协作")
print("每个agent都有独立的git身份和提交记录")
print("")
# 检查agent是否已创建
if not demo.manager.list_agents():
print("❌ 请先运行 ./agents/setup_agents.sh 创建agent")
return
# 运行演示
demo.run_collaboration_demo()
demo.show_git_history()
print("\n💡 下一步:")
print("1. 查看git log --oneline --graph 查看提交历史")
print("2. 使用 ./agents/stats.sh 查看agent统计")
print("3. 开始你自己的多agent协作项目")
# 询问是否清理
response = input("\n是否清理演示文件?(y/N): ")
if response.lower() == 'y':
demo.cleanup_demo()
if __name__ == "__main__":
main()

314
agents/git_collaboration.py Normal file
View File

@ -0,0 +1,314 @@
"""
Git 协作管理系统
管理 Agent 之间基于 Git 的真实协作
"""
import os
import subprocess
import json
from pathlib import Path
from typing import Dict, List, Optional, Tuple, Any
from dataclasses import dataclass
import logging
from .identity_manager import AgentIdentityManager
@dataclass
class Repository:
"""仓库信息"""
name: str
local_path: str
remotes: Dict[str, str] # remote_name -> url
current_agent: Optional[str] = None
class GitCollaborationManager:
"""Git 协作管理器"""
def __init__(self, identity_manager: AgentIdentityManager):
self.identity_manager = identity_manager
self.logger = logging.getLogger(__name__)
self.repositories = {}
self._load_repositories()
def _load_repositories(self):
"""加载仓库配置"""
config_file = Path("config/repositories.json")
if config_file.exists():
with open(config_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.repositories = {
name: Repository(**repo_data)
for name, repo_data in data.items()
}
def _save_repositories(self):
"""保存仓库配置"""
config_file = Path("config/repositories.json")
config_file.parent.mkdir(exist_ok=True)
data = {
name: {
'name': repo.name,
'local_path': repo.local_path,
'remotes': repo.remotes,
'current_agent': repo.current_agent
}
for name, repo in self.repositories.items()
}
with open(config_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def setup_progressive_deployment(self,
repo_name: str,
gitea_url: str,
bitbucket_url: str,
github_url: str,
local_path: Optional[str] = None):
"""设置渐进发布的三个远程仓库"""
if not local_path:
local_path_str = f"./repos/{repo_name}"
else:
local_path_str = local_path
local_path_obj = Path(local_path_str)
local_path_obj.mkdir(parents=True, exist_ok=True)
# 初始化本地仓库(如果不存在)
if not (local_path_obj / ".git").exists():
subprocess.run(["git", "init"], cwd=local_path)
# 设置远程仓库
remotes = {
"gitea": gitea_url,
"bitbucket": bitbucket_url,
"github": github_url
}
for remote_name, remote_url in remotes.items():
# 检查远程是否已存在
result = subprocess.run([
"git", "remote", "get-url", remote_name
], cwd=local_path, capture_output=True, text=True)
if result.returncode != 0:
# 添加新的远程
subprocess.run([
"git", "remote", "add", remote_name, remote_url
], cwd=local_path)
else:
# 更新现有远程
subprocess.run([
"git", "remote", "set-url", remote_name, remote_url
], cwd=local_path)
# 创建仓库记录
repository = Repository(
name=repo_name,
local_path=str(local_path),
remotes=remotes
)
self.repositories[repo_name] = repository
self._save_repositories()
self.logger.info(f"设置渐进发布仓库: {repo_name}")
return repository
def switch_agent_context(self, repo_name: str, agent_name: str):
"""切换仓库的 Agent 上下文"""
if repo_name not in self.repositories:
raise ValueError(f"仓库 {repo_name} 不存在")
repository = self.repositories[repo_name]
# 设置 Git 配置
self.identity_manager.setup_git_config(agent_name, repository.local_path)
# 设置 SSH 密钥
identity = self.identity_manager.get_agent_identity(agent_name)
if identity:
self._setup_ssh_agent(identity.ssh_key_path)
repository.current_agent = agent_name
self._save_repositories()
self.logger.info(f"切换仓库 {repo_name} 到 Agent: {agent_name}")
def _setup_ssh_agent(self, ssh_key_path: str):
"""设置 SSH Agent"""
try:
# 启动 ssh-agent如果未运行
result = subprocess.run([
"ssh-add", "-l"
], capture_output=True, text=True)
if result.returncode != 0:
# 启动 ssh-agent
result = subprocess.run([
"ssh-agent", "-s"
], capture_output=True, text=True)
if result.returncode == 0:
# 解析环境变量
for line in result.stdout.split('\n'):
if 'SSH_AUTH_SOCK' in line:
sock = line.split('=')[1].split(';')[0]
os.environ['SSH_AUTH_SOCK'] = sock
elif 'SSH_AGENT_PID' in line:
pid = line.split('=')[1].split(';')[0]
os.environ['SSH_AGENT_PID'] = pid
# 添加 SSH 密钥
subprocess.run(["ssh-add", ssh_key_path])
except Exception as e:
self.logger.warning(f"SSH Agent 设置失败: {e}")
def commit_as_agent(self,
repo_name: str,
message: str,
files: Optional[List[str]] = None,
sign: bool = True) -> bool:
"""以当前 Agent 身份提交代码"""
if repo_name not in self.repositories:
raise ValueError(f"仓库 {repo_name} 不存在")
repository = self.repositories[repo_name]
repo_path = Path(repository.local_path)
try:
# 添加文件
if files:
for file in files:
subprocess.run(["git", "add", file], cwd=repo_path)
else:
subprocess.run(["git", "add", "."], cwd=repo_path)
# 提交
commit_cmd = ["git", "commit", "-m", message]
if sign:
commit_cmd.append("-S")
result = subprocess.run(commit_cmd, cwd=repo_path, capture_output=True, text=True)
if result.returncode == 0:
self.logger.info(f"Agent {repository.current_agent} 提交成功: {message}")
return True
else:
self.logger.error(f"提交失败: {result.stderr}")
return False
except Exception as e:
self.logger.error(f"提交过程出错: {e}")
return False
def progressive_push(self, repo_name: str, branch: str = "main") -> Dict[str, bool]:
"""渐进式推送到三个平台"""
if repo_name not in self.repositories:
raise ValueError(f"仓库 {repo_name} 不存在")
repository = self.repositories[repo_name]
repo_path = Path(repository.local_path)
results = {}
# 按顺序推送Gitea -> Bitbucket -> GitHub
push_order = ["gitea", "bitbucket", "github"]
for remote in push_order:
if remote in repository.remotes:
try:
result = subprocess.run([
"git", "push", remote, branch
], cwd=repo_path, capture_output=True, text=True)
results[remote] = result.returncode == 0
if result.returncode == 0:
self.logger.info(f"推送到 {remote} 成功")
else:
self.logger.error(f"推送到 {remote} 失败: {result.stderr}")
# 如果某个平台失败,停止后续推送
break
except Exception as e:
self.logger.error(f"推送到 {remote} 出错: {e}")
results[remote] = False
break
return results
def create_pull_request_workflow(self,
repo_name: str,
source_agent: str,
target_agent: str,
feature_branch: str,
title: str,
description: str = "") -> bool:
"""创建 Agent 间的 Pull Request 工作流"""
repository = self.repositories[repo_name]
repo_path = Path(repository.local_path)
try:
# 1. 切换到源 Agent
self.switch_agent_context(repo_name, source_agent)
# 2. 创建功能分支
subprocess.run([
"git", "checkout", "-b", feature_branch
], cwd=repo_path)
# 3. 推送功能分支
subprocess.run([
"git", "push", "-u", "gitea", feature_branch
], cwd=repo_path)
# 4. 这里可以集成 API 调用来创建实际的 PR
# 具体实现取决于使用的 Git 平台
self.logger.info(f"创建 PR 工作流: {source_agent} -> {target_agent}")
return True
except Exception as e:
self.logger.error(f"创建 PR 工作流失败: {e}")
return False
def get_repository_status(self, repo_name: str) -> Dict[str, Any]:
"""获取仓库状态"""
if repo_name not in self.repositories:
raise ValueError(f"仓库 {repo_name} 不存在")
repository = self.repositories[repo_name]
repo_path = Path(repository.local_path)
status = {
"current_agent": repository.current_agent,
"branch": None,
"uncommitted_changes": False,
"remotes": repository.remotes
}
try:
# 获取当前分支
result = subprocess.run([
"git", "branch", "--show-current"
], cwd=repo_path, capture_output=True, text=True)
if result.returncode == 0:
status["branch"] = result.stdout.strip()
# 检查未提交的更改
result = subprocess.run([
"git", "status", "--porcelain"
], cwd=repo_path, capture_output=True, text=True)
status["uncommitted_changes"] = bool(result.stdout.strip())
except Exception as e:
self.logger.error(f"获取仓库状态失败: {e}")
return status

237
agents/identity_manager.py Normal file
View File

@ -0,0 +1,237 @@
"""
Agent Identity Management System
管理多个 AI Agent 的身份信息包括 SSH/GPG 密钥Git 配置等
"""
import os
import json
import subprocess
from pathlib import Path
from typing import Dict, List, Optional
from dataclasses import dataclass, asdict
import logging
@dataclass
class AgentIdentity:
"""Agent 身份信息"""
name: str
email: str
ssh_key_path: str
gpg_key_id: Optional[str] = None
git_username: str = ""
description: str = ""
repositories: List[str] = None
def __post_init__(self):
if self.repositories is None:
self.repositories = []
if not self.git_username:
self.git_username = self.name.lower().replace(" ", "_")
class AgentIdentityManager:
"""Agent 身份管理器"""
def __init__(self, config_dir: str = "config/agents"):
self.config_dir = Path(config_dir)
self.config_dir.mkdir(parents=True, exist_ok=True)
self.identities_file = self.config_dir / "identities.json"
self.ssh_keys_dir = self.config_dir / "ssh_keys"
self.gpg_keys_dir = self.config_dir / "gpg_keys"
# 创建必要的目录
self.ssh_keys_dir.mkdir(exist_ok=True)
self.gpg_keys_dir.mkdir(exist_ok=True)
self.logger = logging.getLogger(__name__)
self._load_identities()
def _load_identities(self):
"""加载已有的身份信息"""
if self.identities_file.exists():
with open(self.identities_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.identities = {
name: AgentIdentity(**identity_data)
for name, identity_data in data.items()
}
else:
self.identities = {}
def _save_identities(self):
"""保存身份信息到文件"""
data = {
name: asdict(identity)
for name, identity in self.identities.items()
}
with open(self.identities_file, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def create_agent_identity(self,
name: str,
email: str,
description: str = "",
generate_keys: bool = True) -> AgentIdentity:
"""创建新的 Agent 身份"""
if name in self.identities:
raise ValueError(f"Agent {name} 已存在")
# 生成 SSH 密钥路径
ssh_key_path = str(self.ssh_keys_dir / f"{name.lower().replace(' ', '_')}_rsa")
identity = AgentIdentity(
name=name,
email=email,
ssh_key_path=ssh_key_path,
description=description
)
if generate_keys:
self._generate_ssh_key(identity)
self._generate_gpg_key(identity)
self.identities[name] = identity
self._save_identities()
self.logger.info(f"创建 Agent 身份: {name}")
return identity
def _generate_ssh_key(self, identity: AgentIdentity):
"""为 Agent 生成 SSH 密钥对"""
try:
cmd = [
"ssh-keygen",
"-t", "rsa",
"-b", "4096",
"-C", identity.email,
"-f", identity.ssh_key_path,
"-N", "" # 无密码
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"SSH 密钥生成失败: {result.stderr}")
# 设置正确的权限
os.chmod(identity.ssh_key_path, 0o600)
os.chmod(f"{identity.ssh_key_path}.pub", 0o644)
self.logger.info(f"{identity.name} 生成 SSH 密钥: {identity.ssh_key_path}")
except Exception as e:
self.logger.error(f"SSH 密钥生成失败: {e}")
raise
def _generate_gpg_key(self, identity: AgentIdentity):
"""为 Agent 生成 GPG 密钥"""
try:
# GPG 密钥生成配置
gpg_config = f"""
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: {identity.name}
Name-Email: {identity.email}
Expire-Date: 0
%no-protection
%commit
"""
# 写入临时配置文件
config_file = self.gpg_keys_dir / f"{identity.git_username}_gpg_config"
with open(config_file, 'w') as f:
f.write(gpg_config)
# 生成 GPG 密钥
cmd = ["gpg", "--batch", "--generate-key", str(config_file)]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
self.logger.warning(f"GPG 密钥生成失败: {result.stderr}")
return
# 获取生成的密钥 ID
cmd = ["gpg", "--list-secret-keys", "--keyid-format", "LONG", identity.email]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
# 解析密钥 ID
lines = result.stdout.split('\n')
for line in lines:
if 'sec' in line and 'rsa4096/' in line:
key_id = line.split('rsa4096/')[1].split(' ')[0]
identity.gpg_key_id = key_id
break
# 清理临时文件
config_file.unlink()
self.logger.info(f"{identity.name} 生成 GPG 密钥: {identity.gpg_key_id}")
except Exception as e:
self.logger.warning(f"GPG 密钥生成失败: {e}")
def get_agent_identity(self, name: str) -> Optional[AgentIdentity]:
"""获取 Agent 身份信息"""
return self.identities.get(name)
def list_agents(self) -> List[str]:
"""列出所有 Agent"""
return list(self.identities.keys())
def setup_git_config(self, agent_name: str, repo_path: str = "."):
"""为指定仓库设置 Agent 的 Git 配置"""
identity = self.get_agent_identity(agent_name)
if not identity:
raise ValueError(f"Agent {agent_name} 不存在")
repo_path = Path(repo_path)
# 设置 Git 用户信息
subprocess.run([
"git", "config", "--local", "user.name", identity.name
], cwd=repo_path)
subprocess.run([
"git", "config", "--local", "user.email", identity.email
], cwd=repo_path)
# 设置 GPG 签名
if identity.gpg_key_id:
subprocess.run([
"git", "config", "--local", "user.signingkey", identity.gpg_key_id
], cwd=repo_path)
subprocess.run([
"git", "config", "--local", "commit.gpgsign", "true"
], cwd=repo_path)
self.logger.info(f"为仓库 {repo_path} 设置 {agent_name} 的 Git 配置")
def get_ssh_public_key(self, agent_name: str) -> str:
"""获取 Agent 的 SSH 公钥"""
identity = self.get_agent_identity(agent_name)
if not identity:
raise ValueError(f"Agent {agent_name} 不存在")
pub_key_path = f"{identity.ssh_key_path}.pub"
if not os.path.exists(pub_key_path):
raise FileNotFoundError(f"SSH 公钥文件不存在: {pub_key_path}")
with open(pub_key_path, 'r') as f:
return f.read().strip()
def export_gpg_public_key(self, agent_name: str) -> str:
"""导出 Agent 的 GPG 公钥"""
identity = self.get_agent_identity(agent_name)
if not identity or not identity.gpg_key_id:
raise ValueError(f"Agent {agent_name} 没有 GPG 密钥")
cmd = ["gpg", "--armor", "--export", identity.gpg_key_id]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"GPG 公钥导出失败: {result.stderr}")
return result.stdout

167
agents/setup_agents.sh Normal file
View File

@ -0,0 +1,167 @@
#!/bin/bash
# Agent协作系统设置脚本
# 为一人公司创建多agent git协作环境
set -e
echo "🚀 设置AI Agent协作系统..."
# 创建必要的目录
mkdir -p agents/keys
mkdir -p agents/logs
# 设置权限
chmod 700 agents/keys
# 检查依赖
check_dependency() {
if ! command -v $1 &> /dev/null; then
echo "❌ 需要安装: $1"
exit 1
fi
}
check_dependency "git"
check_dependency "ssh-keygen"
echo "✅ 依赖检查通过"
# 初始化agent身份管理器
echo "🤖 初始化agent身份..."
python3 agents/agent_identity_manager.py
# 创建git hooks模板
cat > agents/pre-commit-hook << 'EOF'
#!/bin/bash
# Agent提交前的钩子
echo "🔍 检查agent身份..."
AGENT_NAME=$(git config user.name)
if [[ -z "$AGENT_NAME" ]]; then
echo "❌ 未设置agent身份请先使用agent协作系统"
exit 1
fi
echo "✅ 当前agent: $AGENT_NAME"
EOF
chmod +x agents/pre-commit-hook
# 创建快速切换脚本
cat > agents/switch_agent.sh << 'EOF'
#!/bin/bash
# 快速切换agent身份
if [[ $# -eq 0 ]]; then
echo "用法: ./switch_agent.sh <agent名称>"
echo "可用agents:"
python3 -c "
import sys
sys.path.append('agents')
from agent_identity_manager import AgentIdentityManager
manager = AgentIdentityManager()
for agent in manager.list_agents():
print(f' - {agent[\"name\"]} ({agent[\"role\"]})')
"
exit 1
fi
AGENT_NAME=$1
echo "🔄 切换到agent: $AGENT_NAME"
python3 -c "
import sys
sys.path.append('agents')
from agent_identity_manager import AgentIdentityManager
manager = AgentIdentityManager()
try:
manager.switch_to_agent('$AGENT_NAME')
print('✅ 切换成功')
except Exception as e:
print(f'❌ 切换失败: {e}')
exit(1)
"
EOF
chmod +x agents/switch_agent.sh
# 创建agent提交脚本
cat > agents/commit_as_agent.sh << 'EOF'
#!/bin/bash
# 以指定agent身份提交
if [[ $# -lt 2 ]]; then
echo "用法: ./commit_as_agent.sh <agent名称> \"提交信息\" [文件...]"
exit 1
fi
AGENT_NAME=$1
MESSAGE=$2
shift 2
FILES=$@
echo "📝 Agent $AGENT_NAME 正在提交..."
python3 -c "
import sys
sys.path.append('agents')
from agent_identity_manager import AgentIdentityManager
manager = AgentIdentityManager()
try:
manager.commit_as_agent('$AGENT_NAME', '$MESSAGE', '$FILES'.split() if '$FILES' else None)
print('✅ 提交成功')
except Exception as e:
print(f'❌ 提交失败: {e}')
exit(1)
"
EOF
chmod +x agents/commit_as_agent.sh
# 创建统计脚本
cat > agents/stats.sh << 'EOF'
#!/bin/bash
# 查看agent统计信息
echo "📊 Agent协作统计"
echo "=================="
python3 -c "
import sys
sys.path.append('agents')
from agent_identity_manager import AgentIdentityManager
manager = AgentIdentityManager()
for agent in manager.list_agents():
name = agent['name']
stats = manager.get_agent_stats(name)
print(f'👤 {name} ({agent["role"]})')
print(f' 📧 {agent["email"]}')
print(f' 📈 提交数: {stats["total_commits"]}')
if stats["commits"]:
print(f' 📝 最近提交: {stats["commits"][0]}')
print()
"
EOF
chmod +x agents/stats.sh
echo "🎉 设置完成!"
echo ""
echo "📋 使用说明:"
echo "1. 查看agent列表: ./agents/stats.sh"
echo "2. 切换agent: ./agents/switch_agent.sh <agent名称>"
echo "3. agent提交: ./agents/commit_as_agent.sh <agent名称> \"消息\""
echo "4. 查看统计: ./agents/stats.sh"
echo ""
echo "🔑 SSH公钥位置:"
for key in agents/keys/*_rsa.pub; do
if [[ -f "$key" ]]; then
agent_name=$(basename "$key" _rsa.pub)
echo " $agent_name: $key"
fi
done
echo ""
echo "💡 下一步:"
echo "1. 将SSH公钥添加到GitHub/Gitea/Bitbucket"
echo "2. 测试agent切换和提交功能"
echo "3. 开始真正的多agent协作开发"