Files
edict/scripts/sync_agent_config.py
cft0808 5b46f67603 🏛️ init: 三省六部 OpenClaw Multi-Agent Orchestration System
Features:
- 9 specialized agents (中书省·门下省·尚书省 + 六部)
- Real-time dashboard with 6 tabs (Overview/Kanban/History/Timeline/Models/Skills)
- Model configuration with live-apply via local API server
- One-click install script
- Data sync pipeline (15s refresh loop)
- Full audit trail via flow_log
2026-02-23 22:34:55 +08:00

96 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""
同步 openclaw.json 中的 agent 配置 → data/agent_config.json
支持自动发现 agent workspace 下的 Skills 目录
"""
import json, pathlib, datetime
# Auto-detect project root (parent of scripts/)
BASE = pathlib.Path(__file__).parent.parent
DATA = BASE / 'data'
OPENCLAW_CFG = pathlib.Path.home() / '.openclaw' / 'openclaw.json'
ID_LABEL = {
'zhongshu': {'label': '中书省', 'role': '中书令', 'duty': '起草任务令与优先级', 'emoji': '📜'},
'menxia': {'label': '门下省', 'role': '侍中', 'duty': '审议与退回机制', 'emoji': '🔍'},
'shangshu': {'label': '尚书省', 'role': '尚书令', 'duty': '派单与升级裁决', 'emoji': '📮'},
'libu': {'label': '礼部', 'role': '礼部尚书', 'duty': '文档/汇报/规范', 'emoji': '📝'},
'hubu': {'label': '户部', 'role': '户部尚书', 'duty': '资源/预算/成本', 'emoji': '💰'},
'bingbu': {'label': '兵部', 'role': '兵部尚书', 'duty': '应急与巡检', 'emoji': '⚔️'},
'xingbu': {'label': '刑部', 'role': '刑部尚书', 'duty': '合规/审计/红线', 'emoji': '⚖️'},
'gongbu': {'label': '工部', 'role': '工部尚书', 'duty': '工程交付与自动化', 'emoji': '🔧'},
}
KNOWN_MODELS = [
{'id': 'anthropic/claude-sonnet-4-6', 'label': 'Claude Sonnet 4.6', 'provider': 'Anthropic'},
{'id': 'anthropic/claude-opus-4-5', 'label': 'Claude Opus 4.5', 'provider': 'Anthropic'},
{'id': 'anthropic/claude-haiku-3-5', 'label': 'Claude Haiku 3.5', 'provider': 'Anthropic'},
{'id': 'openai/gpt-4o', 'label': 'GPT-4o', 'provider': 'OpenAI'},
{'id': 'openai/gpt-4o-mini', 'label': 'GPT-4o Mini', 'provider': 'OpenAI'},
{'id': 'openai-codex/gpt-5.3-codex', 'label': 'GPT-5.3 Codex', 'provider': 'OpenAI Codex'},
{'id': 'google/gemini-2.0-flash', 'label': 'Gemini 2.0 Flash', 'provider': 'Google'},
{'id': 'google/gemini-2.5-pro', 'label': 'Gemini 2.5 Pro', 'provider': 'Google'},
]
def get_skills(workspace: str):
skills_dir = pathlib.Path(workspace) / 'skills'
skills = []
if skills_dir.exists():
for d in sorted(skills_dir.iterdir()):
if d.is_dir():
md = d / 'SKILL.md'
desc = ''
if md.exists():
for line in md.read_text(encoding='utf-8', errors='ignore').splitlines():
line = line.strip()
if line and not line.startswith('#'):
desc = line[:100]
break
skills.append({'name': d.name, 'path': str(md), 'exists': md.exists(), 'description': desc})
return skills
def main():
cfg = {}
try:
cfg = json.loads(OPENCLAW_CFG.read_text())
except Exception as e:
print(f'[WARN] cannot read openclaw.json: {e}')
return
agents_cfg = cfg.get('agents', {})
default_model = agents_cfg.get('defaults', {}).get('model', {}).get('primary', 'unknown')
agents_list = agents_cfg.get('list', [])
result = []
for ag in agents_list:
ag_id = ag.get('id', '')
if ag_id not in ID_LABEL:
continue
meta = ID_LABEL[ag_id]
workspace = ag.get('workspace', str(pathlib.Path.home() / f'.openclaw/workspace-{ag_id}'))
result.append({
'id': ag_id,
'label': meta['label'], 'role': meta['role'], 'duty': meta['duty'], 'emoji': meta['emoji'],
'model': ag.get('model', default_model),
'defaultModel': default_model,
'workspace': workspace,
'skills': get_skills(workspace),
'allowAgents': ag.get('subagents', {}).get('allowAgents', []),
})
payload = {
'generatedAt': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'defaultModel': default_model,
'knownModels': KNOWN_MODELS,
'agents': result,
}
DATA.mkdir(exist_ok=True)
(DATA / 'agent_config.json').write_text(json.dumps(payload, ensure_ascii=False, indent=2))
print(f'[sync_agent_config] {len(result)} agents synced')
if __name__ == '__main__':
main()