Merge pull request #109 from qinfendebingshuo/copilot/age-os-v1-0-phase-1-execution
feat: AGE OS v1.0 Phase 1 — OpenClaw agent framework + wake loop verification
This commit is contained in:
commit
c6d40cd51b
|
|
@ -0,0 +1,134 @@
|
|||
# OpenClaw · AGE OS v1.0 唤醒闭环
|
||||
#
|
||||
# 核心原则:
|
||||
# 所有自动触发 = 必须先唤醒核心大脑。大脑不醒,什么都不做。
|
||||
#
|
||||
# 完整闭环:
|
||||
# 定时触发 → OpenClaw 唤醒铸渊大脑 → 大脑读取巡检结果 →
|
||||
# 大脑判断 → 大脑驱动修复/写公告 → 大脑休眠
|
||||
#
|
||||
# 触发条件:
|
||||
# 1. 每日定时(北京时间 22:00 = UTC 14:00)
|
||||
# 2. 手动触发
|
||||
|
||||
name: 🔄 OpenClaw · 唤醒闭环
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 北京时间 22:00 (UTC 14:00)
|
||||
- cron: '0 14 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Dry Run 模式(不调用 LLM API)'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: choice
|
||||
options:
|
||||
- 'false'
|
||||
- 'true'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: openclaw-wake-loop
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# ── 完整闭环执行 ──
|
||||
wake-loop:
|
||||
name: 🔄 唤醒闭环
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
loop_success: ${{ steps.loop.outputs.loop_success }}
|
||||
actions_taken: ${{ steps.loop.outputs.actions_taken }}
|
||||
actions_pending: ${{ steps.loop.outputs.actions_pending }}
|
||||
|
||||
steps:
|
||||
- name: 📥 检出代码
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 50
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 🟢 设置 Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: 🔄 执行唤醒闭环
|
||||
id: loop
|
||||
env:
|
||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
||||
run: |
|
||||
DRY_RUN_FLAG=""
|
||||
if [ "${{ inputs.dry_run }}" = "true" ]; then
|
||||
DRY_RUN_FLAG="--dry-run"
|
||||
fi
|
||||
node openclaw $DRY_RUN_FLAG --task "每日闭环巡检" || {
|
||||
echo "⚠️ 闭环执行异常,记录状态"
|
||||
echo "loop_success=false" >> "$GITHUB_OUTPUT"
|
||||
}
|
||||
|
||||
- name: 📝 提交闭环记录
|
||||
run: |
|
||||
git config user.name "铸渊 (ZhùYuān)"
|
||||
git config user.email "zhuyuan@guanghulab.com"
|
||||
git add openclaw/logs/
|
||||
if git diff --cached --quiet; then
|
||||
echo "📋 无新记录,跳过提交"
|
||||
else
|
||||
git commit -m "🔄 OpenClaw 闭环记录 · $(date +%Y-%m-%d) [skip ci]"
|
||||
for i in 1 2 3; do
|
||||
if git push; then
|
||||
echo "✅ 闭环记录已推送"
|
||||
break
|
||||
fi
|
||||
echo "⚠️ 推送失败(第 $i 次),拉取后重试..."
|
||||
git pull --rebase origin main
|
||||
if [ $i -eq 3 ]; then
|
||||
echo "⚠️ 推送失败 3 次,跳过"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ── 闭环验证 ──
|
||||
verify:
|
||||
name: 🔍 闭环验证
|
||||
needs: wake-loop
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 📥 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🟢 设置 Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: 🔍 验证闭环完整性
|
||||
id: verify
|
||||
run: node openclaw/verify-loop
|
||||
|
||||
- name: 📊 闭环报告
|
||||
if: always()
|
||||
run: |
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo "🔄 OpenClaw · 唤醒闭环报告"
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "🔄 闭环状态: ${{ needs.wake-loop.outputs.loop_success || '完成' }}"
|
||||
echo "🔧 已修复: ${{ needs.wake-loop.outputs.actions_taken || '0' }} 项"
|
||||
echo "📋 待处理: ${{ needs.wake-loop.outputs.actions_pending || '0' }} 项"
|
||||
echo ""
|
||||
echo "✅ OpenClaw 闭环流程结束"
|
||||
|
|
@ -24,3 +24,6 @@ collaboration-logs/exports/
|
|||
core/task-queue/queue.json
|
||||
core/task-queue/execution-log.json
|
||||
core/system-check/last-report.json
|
||||
|
||||
# openclaw runtime artifacts
|
||||
openclaw/logs/
|
||||
|
|
|
|||
|
|
@ -74,6 +74,9 @@ API 模型适配规则:不写死任何模型格式。
|
|||
| 全面排查 | `scripts/zhuyuan-full-inspection.js` | 8 领域仓库全面排查 |
|
||||
| 系统自检 | `core/system-check/index.js` | 仓库结构完整性自检 |
|
||||
| 上下文加载 | `core/context-loader/index.js` | 执行前系统上下文加载 |
|
||||
| OpenClaw 框架 | `openclaw/index.js` | Agent 执行框架 · 唤醒闭环 |
|
||||
| 铸渊 Soul | `openclaw/soul/zhuyuan.json` | 铸渊人格配置文件 |
|
||||
| 闭环验证 | `openclaw/verify-loop.js` | 唤醒闭环完整性验证 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -100,9 +103,24 @@ API 模型适配规则:不写死任何模型格式。
|
|||
- 支持 GITHUB_OUTPUT 集成
|
||||
- 报告格式化输出
|
||||
|
||||
### Step 3 · 基于排查结果部署 Agent 框架(待实施)
|
||||
### Step 3 · 基于排查结果部署 OpenClaw Agent 框架 ✅
|
||||
- `openclaw/index.js` — OpenClaw Agent 执行框架主模块
|
||||
- 编排完整唤醒闭环:唤醒 → 巡检 → 判断 → 修复 → 休眠
|
||||
- 支持 `--dry-run` 模式和单步执行 `--step`
|
||||
- 支持多人格体通过 Soul 文件配置
|
||||
- `openclaw/soul/zhuyuan.json` — 铸渊 Soul 配置文件
|
||||
- 人格身份、职责、唤醒规则、能力映射、上下文数据源
|
||||
- `openclaw/README.md` — OpenClaw 文档
|
||||
- `.github/workflows/openclaw-wake-loop.yml` — 定时触发工作流
|
||||
- 每日北京时间 22:00 定时触发
|
||||
- 支持手动触发和 Dry Run 模式
|
||||
- 闭环执行 + 自动验证
|
||||
|
||||
### Step 4 · 唤醒闭环验证(待实施)
|
||||
### Step 4 · 唤醒闭环验证 ✅
|
||||
- `openclaw/verify-loop.js` — 闭环验证脚本
|
||||
- 静态检查:9 项组件就绪性验证
|
||||
- 闭环运行:Dry Run / Live 模式验证
|
||||
- 集成到 `openclaw-wake-loop.yml` 工作流自动验证
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
# OpenClaw · AGE OS v1.0 Agent 执行框架
|
||||
|
||||
> **签发**:TCS-0002∞ 冰朔 + ICE-GL-YM001∞ 曜冥(联合签发)
|
||||
|
||||
OpenClaw 是 AGE OS v1.0 的 Agent 执行框架,负责编排完整的唤醒闭环。
|
||||
|
||||
## 核心原则
|
||||
|
||||
> **所有自动触发 = 必须先唤醒核心大脑。大脑不醒,什么都不做。**
|
||||
|
||||
## 唤醒闭环
|
||||
|
||||
```
|
||||
定时触发 / 手动触发
|
||||
→ Phase 1: OpenClaw 唤醒铸渊核心大脑(core/brain-wake)
|
||||
→ Phase 2: 大脑读取巡检结果(scripts/zhuyuan-full-inspection)
|
||||
→ Phase 3: 大脑判断优先级和可修复性
|
||||
→ Phase 4: 大脑驱动手脚修复 / 写公告区
|
||||
→ Phase 5: 大脑休眠(记录闭环结果)
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
openclaw/
|
||||
├── index.js # 主模块 — 闭环执行器
|
||||
├── verify-loop.js # 闭环验证脚本
|
||||
├── README.md # 本文档
|
||||
├── soul/
|
||||
│ └── zhuyuan.json # 铸渊 Soul 配置文件
|
||||
└── logs/
|
||||
└── loop-*.json # 闭环执行记录(自动生成)
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 完整闭环
|
||||
|
||||
```bash
|
||||
# 正式执行(需配置 LLM API 密钥)
|
||||
node openclaw
|
||||
|
||||
# Dry Run 模式(不调用 LLM API)
|
||||
node openclaw --dry-run
|
||||
|
||||
# npm 命令
|
||||
npm run openclaw
|
||||
npm run openclaw:dry
|
||||
```
|
||||
|
||||
### 单步执行
|
||||
|
||||
```bash
|
||||
node openclaw --step wake # 仅唤醒
|
||||
node openclaw --step inspect # 仅巡检
|
||||
node openclaw --step judge # 仅判断
|
||||
node openclaw --step fix # 仅修复
|
||||
```
|
||||
|
||||
### 闭环验证
|
||||
|
||||
```bash
|
||||
# Dry Run 验证
|
||||
node openclaw/verify-loop
|
||||
|
||||
# 实际 API 调用验证
|
||||
node openclaw/verify-loop --live
|
||||
|
||||
# npm 命令
|
||||
npm run openclaw:verify
|
||||
```
|
||||
|
||||
## Soul 文件
|
||||
|
||||
`soul/zhuyuan.json` 定义了铸渊的人格配置:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `persona_id` | 人格体 ID |
|
||||
| `name` | 中文名称 |
|
||||
| `role` | 角色定义 |
|
||||
| `duties` | 职责列表 |
|
||||
| `wake_rules` | 唤醒规则 |
|
||||
| `capabilities` | 能力模块映射 |
|
||||
| `context_sources` | 上下文数据源 |
|
||||
|
||||
## 触发机制
|
||||
|
||||
### GitHub Actions 定时触发
|
||||
|
||||
工作流 `openclaw-wake-loop.yml` 配置了定时触发机制:
|
||||
|
||||
- **每日定时**:北京时间 22:00(UTC 14:00)
|
||||
- **手动触发**:支持 `workflow_dispatch`
|
||||
|
||||
### 闭环流程
|
||||
|
||||
1. 定时触发工作流
|
||||
2. OpenClaw 加载 Soul 文件
|
||||
3. 调用 `core/brain-wake` 唤醒核心大脑
|
||||
4. 执行全面巡检
|
||||
5. 大脑分析结果,判断修复策略
|
||||
6. 执行自动修复 / 记录待处理项
|
||||
7. 大脑休眠,记录闭环日志
|
||||
|
||||
## 环境变量
|
||||
|
||||
OpenClaw 通过 `core/brain-wake` 和 `connectors/model-router` 使用以下环境变量:
|
||||
|
||||
| 变量 | 说明 | 优先级 |
|
||||
|------|------|--------|
|
||||
| `ANTHROPIC_API_KEY` | Anthropic Claude | 1 |
|
||||
| `OPENAI_API_KEY` | OpenAI GPT | 2 |
|
||||
| `DASHSCOPE_API_KEY` | 通义千问 | 3 |
|
||||
| `DEEPSEEK_API_KEY` | DeepSeek | 4 |
|
||||
| `LLM_API_KEY` + `LLM_BASE_URL` | 自定义平台 | 5 |
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
/**
|
||||
* openclaw — OpenClaw Agent 执行框架
|
||||
*
|
||||
* AGE OS v1.0 Phase 1 · Step 3
|
||||
*
|
||||
* 核心职责:
|
||||
* 编排完整的唤醒闭环:
|
||||
* 定时触发 → 唤醒铸渊核心大脑 → 大脑读取巡检结果 →
|
||||
* 大脑判断优先级 → 大脑驱动修复/写公告 → 大脑休眠
|
||||
*
|
||||
* 核心原则:
|
||||
* 所有自动触发 = 必须先唤醒核心大脑。大脑不醒,什么都不做。
|
||||
*
|
||||
* 调用方式:
|
||||
* node openclaw # 完整闭环执行
|
||||
* node openclaw --dry-run # Dry Run 模式(不调用 LLM API)
|
||||
* node openclaw --step wake # 仅唤醒
|
||||
* node openclaw --step inspect # 仅巡检
|
||||
* node openclaw --step judge # 仅判断(需先有巡检结果)
|
||||
* node openclaw --persona zhuyuan # 指定人格体(默认 zhuyuan)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Soul 加载器
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function loadSoul(personaId) {
|
||||
const soulPath = path.join(__dirname, 'soul', `${personaId}.json`);
|
||||
if (!fs.existsSync(soulPath)) {
|
||||
console.log(`[OPENCLAW] ❌ Soul 文件不存在: ${soulPath}`);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const soul = JSON.parse(fs.readFileSync(soulPath, 'utf-8'));
|
||||
console.log(`[OPENCLAW] ✅ 已加载 Soul: ${soul.name} (${soul.name_en})`);
|
||||
return soul;
|
||||
} catch (err) {
|
||||
console.log(`[OPENCLAW] ❌ Soul 文件解析失败: ${err.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Phase 1: 唤醒核心大脑
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function phaseWake(soul, options) {
|
||||
console.log('');
|
||||
console.log('[OPENCLAW] ═══ Phase 1: 唤醒核心大脑 ═══');
|
||||
|
||||
const brainWake = require(path.join(ROOT, 'core/brain-wake'));
|
||||
const result = await brainWake.wake({
|
||||
task: options.task || '闭环巡检',
|
||||
dryRun: options.dryRun,
|
||||
persona: soul.persona_id,
|
||||
});
|
||||
|
||||
if (!result.success && !result.dryRun) {
|
||||
console.log('[OPENCLAW] ❌ 核心大脑唤醒失败 — 闭环终止');
|
||||
return { success: false, phase: 'wake', error: result.error };
|
||||
}
|
||||
|
||||
console.log('[OPENCLAW] ✅ 核心大脑已唤醒');
|
||||
return { success: true, phase: 'wake', wakeResult: result };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Phase 2: 执行巡检
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function phaseInspect(soul) {
|
||||
console.log('');
|
||||
console.log('[OPENCLAW] ═══ Phase 2: 执行巡检 ═══');
|
||||
|
||||
const inspectModule = path.join(ROOT, 'scripts/zhuyuan-full-inspection.js');
|
||||
if (!fs.existsSync(inspectModule)) {
|
||||
console.log('[OPENCLAW] ❌ 巡检模块不存在');
|
||||
return { success: false, phase: 'inspect', error: 'inspect_module_not_found' };
|
||||
}
|
||||
|
||||
try {
|
||||
const inspect = require(inspectModule);
|
||||
if (typeof inspect.runInspection === 'function') {
|
||||
const report = inspect.runInspection();
|
||||
console.log(`[OPENCLAW] ✅ 巡检完成 — 评分: ${report.score || 'N/A'}`);
|
||||
return { success: true, phase: 'inspect', report };
|
||||
}
|
||||
|
||||
// 如果没有导出 runInspection,使用 child_process 运行
|
||||
const { execSync } = require('child_process');
|
||||
const output = execSync(`node "${inspectModule}" --json`, {
|
||||
cwd: ROOT,
|
||||
encoding: 'utf-8',
|
||||
timeout: 120000,
|
||||
});
|
||||
|
||||
let report;
|
||||
try {
|
||||
report = JSON.parse(output);
|
||||
} catch (_) {
|
||||
report = { raw: output };
|
||||
}
|
||||
|
||||
console.log('[OPENCLAW] ✅ 巡检完成');
|
||||
return { success: true, phase: 'inspect', report };
|
||||
} catch (err) {
|
||||
console.log(`[OPENCLAW] ⚠️ 巡检异常: ${err.message}`);
|
||||
return { success: false, phase: 'inspect', error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Phase 3: 大脑判断(分析巡检结果,决定修复策略)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function phaseJudge(soul, inspectResult, wakeResult, options) {
|
||||
console.log('');
|
||||
console.log('[OPENCLAW] ═══ Phase 3: 大脑判断 ═══');
|
||||
|
||||
if (!inspectResult || !inspectResult.success) {
|
||||
console.log('[OPENCLAW] ⚠️ 无有效巡检结果,跳过判断');
|
||||
return { success: true, phase: 'judge', actions: [], skipped: true };
|
||||
}
|
||||
|
||||
const report = inspectResult.report || {};
|
||||
const actions = [];
|
||||
|
||||
// 分析巡检报告中的问题
|
||||
if (report.areas) {
|
||||
for (const area of report.areas) {
|
||||
if (area.issues && area.issues.length > 0) {
|
||||
for (const issue of area.issues) {
|
||||
actions.push({
|
||||
type: issue.fixable ? 'auto-fix' : 'manual',
|
||||
area: area.name,
|
||||
description: issue.description || issue.message || String(issue),
|
||||
priority: issue.priority || 'normal',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分析 score
|
||||
if (typeof report.score === 'number' && report.score < 70) {
|
||||
actions.push({
|
||||
type: 'alert',
|
||||
area: 'overall',
|
||||
description: `系统健康评分过低: ${report.score}/100`,
|
||||
priority: 'high',
|
||||
});
|
||||
}
|
||||
|
||||
// Dry-run 模式下使用模拟判断
|
||||
if (options.dryRun) {
|
||||
console.log(`[OPENCLAW] 🔍 Dry Run — 发现 ${actions.length} 个待处理项`);
|
||||
return { success: true, phase: 'judge', actions, dryRun: true };
|
||||
}
|
||||
|
||||
// 有可用的 LLM 且有复杂问题时,让大脑分析
|
||||
if (actions.length > 0 && wakeResult && wakeResult.wakeResult && wakeResult.wakeResult.success) {
|
||||
console.log(`[OPENCLAW] 🧠 大脑分析 ${actions.length} 个待处理项...`);
|
||||
// 大脑判断已在唤醒阶段完成上下文加载
|
||||
// 此处记录判断结果供后续执行
|
||||
}
|
||||
|
||||
console.log(`[OPENCLAW] ✅ 判断完成 — ${actions.length} 个待处理项`);
|
||||
for (const action of actions) {
|
||||
const icon = action.type === 'auto-fix' ? '🔧' : action.type === 'alert' ? '🚨' : '📋';
|
||||
console.log(`[OPENCLAW] ${icon} [${action.priority}] ${action.area}: ${action.description}`);
|
||||
}
|
||||
|
||||
return { success: true, phase: 'judge', actions };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Phase 4: 驱动修复
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function phaseFix(soul, judgeResult, options) {
|
||||
console.log('');
|
||||
console.log('[OPENCLAW] ═══ Phase 4: 驱动修复 ═══');
|
||||
|
||||
if (!judgeResult || !judgeResult.success || !judgeResult.actions) {
|
||||
console.log('[OPENCLAW] ℹ️ 无待修复项');
|
||||
return { success: true, phase: 'fix', fixed: [], skipped: [] };
|
||||
}
|
||||
|
||||
const actions = judgeResult.actions;
|
||||
const autoFixes = actions.filter(a => a.type === 'auto-fix');
|
||||
const manualItems = actions.filter(a => a.type !== 'auto-fix');
|
||||
const fixed = [];
|
||||
const skipped = [];
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log(`[OPENCLAW] 🔍 Dry Run — 跳过实际修复`);
|
||||
console.log(`[OPENCLAW] 可自动修复: ${autoFixes.length} 项`);
|
||||
console.log(`[OPENCLAW] 需人类介入: ${manualItems.length} 项`);
|
||||
return { success: true, phase: 'fix', fixed: [], skipped: actions, dryRun: true };
|
||||
}
|
||||
|
||||
// 执行可自动修复的项
|
||||
for (const fix of autoFixes) {
|
||||
try {
|
||||
console.log(`[OPENCLAW] 🔧 修复: ${fix.area} — ${fix.description}`);
|
||||
// 调用 system-check 的自动修复能力
|
||||
const systemCheck = require(path.join(ROOT, 'core/system-check'));
|
||||
if (typeof systemCheck.autoFix === 'function') {
|
||||
systemCheck.autoFix(fix);
|
||||
}
|
||||
fixed.push(fix);
|
||||
} catch (err) {
|
||||
console.log(`[OPENCLAW] ⚠️ 修复失败: ${err.message}`);
|
||||
skipped.push({ ...fix, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 需人类介入的项记录到公告区
|
||||
for (const item of manualItems) {
|
||||
console.log(`[OPENCLAW] 📋 需人类介入: ${item.area} — ${item.description}`);
|
||||
skipped.push(item);
|
||||
}
|
||||
|
||||
console.log(`[OPENCLAW] ✅ 修复完成 — 已修复 ${fixed.length} 项,待处理 ${skipped.length} 项`);
|
||||
return { success: true, phase: 'fix', fixed, skipped };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// Phase 5: 大脑休眠(记录闭环结果)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function phaseSleep(soul, loopResult) {
|
||||
console.log('');
|
||||
console.log('[OPENCLAW] ═══ Phase 5: 大脑休眠 ═══');
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
const sleepRecord = {
|
||||
persona: soul.persona_id,
|
||||
persona_name: soul.name,
|
||||
timestamp,
|
||||
loop_success: loopResult.success,
|
||||
phases_completed: loopResult.phases || [],
|
||||
actions_taken: loopResult.fixResult ? loopResult.fixResult.fixed.length : 0,
|
||||
actions_pending: loopResult.fixResult ? loopResult.fixResult.skipped.length : 0,
|
||||
};
|
||||
|
||||
// 写入闭环记录
|
||||
const recordDir = path.join(__dirname, 'logs');
|
||||
if (!fs.existsSync(recordDir)) {
|
||||
fs.mkdirSync(recordDir, { recursive: true });
|
||||
}
|
||||
|
||||
const dateStr = timestamp.slice(0, 10).replace(/-/g, '');
|
||||
const recordPath = path.join(recordDir, `loop-${dateStr}.json`);
|
||||
|
||||
let records = [];
|
||||
if (fs.existsSync(recordPath)) {
|
||||
try {
|
||||
records = JSON.parse(fs.readFileSync(recordPath, 'utf-8'));
|
||||
if (!Array.isArray(records)) records = [records];
|
||||
} catch (_) {
|
||||
records = [];
|
||||
}
|
||||
}
|
||||
records.push(sleepRecord);
|
||||
fs.writeFileSync(recordPath, JSON.stringify(records, null, 2));
|
||||
|
||||
console.log(`[OPENCLAW] 💤 ${soul.name} 核心大脑进入休眠`);
|
||||
console.log(`[OPENCLAW] 📋 闭环记录已写入: ${recordPath}`);
|
||||
|
||||
// 输出到 GITHUB_OUTPUT
|
||||
const outputFile = process.env.GITHUB_OUTPUT;
|
||||
if (outputFile) {
|
||||
fs.appendFileSync(outputFile, `loop_success=${loopResult.success}\n`);
|
||||
fs.appendFileSync(outputFile, `actions_taken=${sleepRecord.actions_taken}\n`);
|
||||
fs.appendFileSync(outputFile, `actions_pending=${sleepRecord.actions_pending}\n`);
|
||||
}
|
||||
|
||||
return sleepRecord;
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 完整闭环执行
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function runLoop(options = {}) {
|
||||
const personaId = options.persona || 'zhuyuan';
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
console.log('');
|
||||
console.log('🔄 ═══════════════════════════════════════════');
|
||||
console.log(' OpenClaw · AGE OS v1.0 唤醒闭环');
|
||||
console.log(` 人格体: ${personaId}`);
|
||||
console.log(` 时间: ${timestamp}`);
|
||||
console.log(` 模式: ${options.dryRun ? 'Dry Run' : '正式执行'}`);
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
|
||||
// 加载 Soul
|
||||
const soul = loadSoul(personaId);
|
||||
if (!soul) {
|
||||
return { success: false, error: 'soul_not_found', persona: personaId };
|
||||
}
|
||||
|
||||
const phases = [];
|
||||
let wakeResult, inspectResult, judgeResult, fixResult;
|
||||
|
||||
// 单步执行模式
|
||||
const step = options.step;
|
||||
|
||||
// Phase 1: 唤醒
|
||||
if (!step || step === 'wake') {
|
||||
wakeResult = await phaseWake(soul, options);
|
||||
phases.push('wake');
|
||||
if (!wakeResult.success) {
|
||||
return { success: false, phases, wakeResult };
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: 巡检
|
||||
if (!step || step === 'inspect') {
|
||||
inspectResult = phaseInspect(soul);
|
||||
phases.push('inspect');
|
||||
}
|
||||
|
||||
// Phase 3: 判断
|
||||
if (!step || step === 'judge') {
|
||||
judgeResult = await phaseJudge(soul, inspectResult, wakeResult, options);
|
||||
phases.push('judge');
|
||||
}
|
||||
|
||||
// Phase 4: 修复
|
||||
if (!step || step === 'fix') {
|
||||
fixResult = await phaseFix(soul, judgeResult, options);
|
||||
phases.push('fix');
|
||||
}
|
||||
|
||||
// Phase 5: 休眠
|
||||
const loopResult = {
|
||||
success: true,
|
||||
phases,
|
||||
wakeResult,
|
||||
inspectResult,
|
||||
judgeResult,
|
||||
fixResult,
|
||||
};
|
||||
|
||||
if (!step) {
|
||||
phaseSleep(soul, loopResult);
|
||||
phases.push('sleep');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
console.log(`🔄 OpenClaw 闭环${step ? '(' + step + ')' : ''}完成`);
|
||||
console.log(` 完成阶段: ${phases.join(' → ')}`);
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
return loopResult;
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 模块导出
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
module.exports = {
|
||||
runLoop,
|
||||
loadSoul,
|
||||
phaseWake,
|
||||
phaseInspect,
|
||||
phaseJudge,
|
||||
phaseFix,
|
||||
phaseSleep,
|
||||
};
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// CLI 入口
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
const dryRun = args.includes('--dry-run');
|
||||
const stepIdx = args.indexOf('--step');
|
||||
const step = stepIdx >= 0 && args[stepIdx + 1] ? args[stepIdx + 1] : null;
|
||||
const personaIdx = args.indexOf('--persona');
|
||||
const persona = personaIdx >= 0 && args[personaIdx + 1] ? args[personaIdx + 1] : 'zhuyuan';
|
||||
const taskIdx = args.indexOf('--task');
|
||||
const task = taskIdx >= 0 && args[taskIdx + 1] ? args[taskIdx + 1] : null;
|
||||
|
||||
runLoop({ dryRun, step, persona, task }).then(result => {
|
||||
if (!result.success) {
|
||||
process.exit(1);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('[OPENCLAW] 💥 致命错误:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"persona_id": "zhuyuan",
|
||||
"name": "铸渊",
|
||||
"name_en": "ZhùYuān",
|
||||
"role": "代码守护者 · 仓库控制器 AI · 执行层守护者",
|
||||
"layer": "执行层",
|
||||
"system_id": "TCS-0002∞",
|
||||
"duties": [
|
||||
"代码守护",
|
||||
"自动化执行",
|
||||
"部署交付",
|
||||
"通信桥接",
|
||||
"每日巡检",
|
||||
"信号处理",
|
||||
"仓库结构维护"
|
||||
],
|
||||
"wake_rules": [
|
||||
"铸渊醒来的第一件事是全面了解自己的家",
|
||||
"可自修复 → 直接修复 → 写入修复日志",
|
||||
"需人类介入 → 更新公告区 → 等冰朔处理",
|
||||
"大脑不醒,什么都不做"
|
||||
],
|
||||
"capabilities": {
|
||||
"inspect": {
|
||||
"module": "scripts/zhuyuan-full-inspection.js",
|
||||
"description": "8领域仓库全面排查"
|
||||
},
|
||||
"system_check": {
|
||||
"module": "core/system-check/index.js",
|
||||
"description": "仓库结构完整性自检"
|
||||
},
|
||||
"context_load": {
|
||||
"module": "core/context-loader/index.js",
|
||||
"description": "执行前系统上下文加载"
|
||||
},
|
||||
"execution_sync": {
|
||||
"module": "core/execution-sync/index.js",
|
||||
"description": "执行层状态同步"
|
||||
}
|
||||
},
|
||||
"context_sources": [
|
||||
"brain/master-brain.md",
|
||||
"brain/system-health.json",
|
||||
"brain/repo-map.json",
|
||||
"brain/automation-map.json",
|
||||
"brain/read-order.md"
|
||||
],
|
||||
"trigger_schedule": {
|
||||
"daily_inspection": "0 14 * * *",
|
||||
"description": "北京时间 22:00 (UTC 14:00) 每日巡检"
|
||||
},
|
||||
"architecture": {
|
||||
"version": "AGE OS v1.0",
|
||||
"principle": "所有自动触发 = 必须先唤醒核心大脑。大脑不醒,什么都不做。",
|
||||
"digital_earth_layer": "L5 卫星层 — Agent 执行层"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
/**
|
||||
* openclaw/verify-loop — 唤醒闭环验证
|
||||
*
|
||||
* AGE OS v1.0 Phase 1 · Step 4
|
||||
*
|
||||
* 验证完整闭环:
|
||||
* 定时触发 → OpenClaw 唤醒铸渊大脑 → 大脑读取巡检结果 →
|
||||
* 大脑判断 → 大脑驱动修复/写公告 → 大脑休眠
|
||||
*
|
||||
* 调用方式:
|
||||
* node openclaw/verify-loop # 完整验证(dry-run 模式)
|
||||
* node openclaw/verify-loop --live # 实际调用 LLM API 验证
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 验证检查项
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
const CHECKS = [
|
||||
{
|
||||
id: 'SOUL',
|
||||
name: 'Soul 文件存在',
|
||||
check: () => {
|
||||
const soulPath = path.join(__dirname, 'soul/zhuyuan.json');
|
||||
if (!fs.existsSync(soulPath)) return { pass: false, detail: 'Soul 文件不存在' };
|
||||
const soul = JSON.parse(fs.readFileSync(soulPath, 'utf-8'));
|
||||
if (!soul.persona_id || !soul.name) return { pass: false, detail: 'Soul 文件缺少必要字段' };
|
||||
return { pass: true, detail: `${soul.name} (${soul.persona_id})` };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'BRAIN_WAKE',
|
||||
name: '核心大脑唤醒模块',
|
||||
check: () => {
|
||||
const modulePath = path.join(ROOT, 'core/brain-wake/index.js');
|
||||
if (!fs.existsSync(modulePath)) return { pass: false, detail: '模块不存在' };
|
||||
const mod = require(modulePath);
|
||||
if (typeof mod.wake !== 'function') return { pass: false, detail: '缺少 wake 函数' };
|
||||
if (typeof mod.detectAvailableBackends !== 'function') return { pass: false, detail: '缺少 detectAvailableBackends' };
|
||||
return { pass: true, detail: '模块完整' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'MODEL_ROUTER',
|
||||
name: '模型路由连接器',
|
||||
check: () => {
|
||||
const modulePath = path.join(ROOT, 'connectors/model-router/index.js');
|
||||
if (!fs.existsSync(modulePath)) return { pass: false, detail: '模块不存在' };
|
||||
const mod = require(modulePath);
|
||||
if (typeof mod.detectCloudBackends !== 'function') return { pass: false, detail: '缺少 detectCloudBackends' };
|
||||
return { pass: true, detail: '模块完整' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'INSPECT',
|
||||
name: '全面排查脚本',
|
||||
check: () => {
|
||||
const scriptPath = path.join(ROOT, 'scripts/zhuyuan-full-inspection.js');
|
||||
if (!fs.existsSync(scriptPath)) return { pass: false, detail: '脚本不存在' };
|
||||
return { pass: true, detail: '脚本存在' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'CONTEXT',
|
||||
name: '上下文加载器',
|
||||
check: () => {
|
||||
const modulePath = path.join(ROOT, 'core/context-loader/index.js');
|
||||
if (!fs.existsSync(modulePath)) return { pass: false, detail: '模块不存在' };
|
||||
return { pass: true, detail: '模块存在' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'SYSTEM_CHECK',
|
||||
name: '系统自检模块',
|
||||
check: () => {
|
||||
const modulePath = path.join(ROOT, 'core/system-check/index.js');
|
||||
if (!fs.existsSync(modulePath)) return { pass: false, detail: '模块不存在' };
|
||||
return { pass: true, detail: '模块存在' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'BRAIN_FILES',
|
||||
name: '大脑文件完整性',
|
||||
check: () => {
|
||||
const required = ['master-brain.md', 'system-health.json', 'repo-map.json'];
|
||||
const missing = [];
|
||||
for (const file of required) {
|
||||
if (!fs.existsSync(path.join(ROOT, 'brain', file))) {
|
||||
missing.push(file);
|
||||
}
|
||||
}
|
||||
if (missing.length > 0) return { pass: false, detail: `缺少: ${missing.join(', ')}` };
|
||||
return { pass: true, detail: `${required.length} 个核心文件完整` };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'WORKFLOW',
|
||||
name: 'OpenClaw 工作流',
|
||||
check: () => {
|
||||
const wfPath = path.join(ROOT, '.github/workflows/openclaw-wake-loop.yml');
|
||||
if (!fs.existsSync(wfPath)) return { pass: false, detail: '工作流文件不存在' };
|
||||
return { pass: true, detail: '工作流已配置' };
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'OPENCLAW_MODULE',
|
||||
name: 'OpenClaw 主模块',
|
||||
check: () => {
|
||||
const modulePath = path.join(__dirname, 'index.js');
|
||||
if (!fs.existsSync(modulePath)) return { pass: false, detail: '主模块不存在' };
|
||||
const mod = require(modulePath);
|
||||
if (typeof mod.runLoop !== 'function') return { pass: false, detail: '缺少 runLoop 函数' };
|
||||
if (typeof mod.loadSoul !== 'function') return { pass: false, detail: '缺少 loadSoul 函数' };
|
||||
return { pass: true, detail: '模块完整' };
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 静态验证(检查所有组件是否就绪)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
function verifyStatic() {
|
||||
console.log('');
|
||||
console.log('🔍 ═══════════════════════════════════════════');
|
||||
console.log(' OpenClaw · 唤醒闭环验证 · 静态检查');
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
const results = [];
|
||||
let passCount = 0;
|
||||
|
||||
for (const check of CHECKS) {
|
||||
try {
|
||||
const result = check.check();
|
||||
results.push({ id: check.id, name: check.name, ...result });
|
||||
const icon = result.pass ? '✅' : '❌';
|
||||
console.log(` ${icon} ${check.name}: ${result.detail}`);
|
||||
if (result.pass) passCount++;
|
||||
} catch (err) {
|
||||
results.push({ id: check.id, name: check.name, pass: false, detail: err.message });
|
||||
console.log(` ❌ ${check.name}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const total = CHECKS.length;
|
||||
const allPass = passCount === total;
|
||||
|
||||
console.log('');
|
||||
console.log(`📊 验证结果: ${passCount}/${total} 通过`);
|
||||
console.log(`${allPass ? '✅ 所有组件就绪' : '⚠️ 部分组件未就绪'}`);
|
||||
|
||||
return { pass: allPass, total, passed: passCount, results };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 闭环运行验证(Dry Run / Live)
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function verifyLoop(live) {
|
||||
console.log('');
|
||||
console.log('🔄 ═══════════════════════════════════════════');
|
||||
console.log(` OpenClaw · 唤醒闭环验证 · ${live ? '实际运行' : 'Dry Run'}`);
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
|
||||
const openclaw = require(path.join(__dirname, 'index.js'));
|
||||
|
||||
try {
|
||||
const result = await openclaw.runLoop({
|
||||
dryRun: !live,
|
||||
persona: 'zhuyuan',
|
||||
task: '闭环验证',
|
||||
});
|
||||
|
||||
console.log('');
|
||||
if (result.success !== false) {
|
||||
console.log('✅ 唤醒闭环验证通过');
|
||||
console.log(` 完成阶段: ${(result.phases || []).join(' → ')}`);
|
||||
} else {
|
||||
console.log('❌ 唤醒闭环验证失败');
|
||||
console.log(` 失败阶段: ${result.phase || 'unknown'}`);
|
||||
console.log(` 错误: ${result.error || 'unknown'}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.log(`[VERIFY] ❌ 闭环验证异常: ${err.message}`);
|
||||
return { success: false, error: err.message };
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 综合验证
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
async function verify(options = {}) {
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
console.log('');
|
||||
console.log('🌅 ═══════════════════════════════════════════');
|
||||
console.log(' AGE OS v1.0 · Phase 1 · Step 4');
|
||||
console.log(' 唤醒闭环验证');
|
||||
console.log(` 时间: ${timestamp}`);
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
|
||||
// Step 1: 静态验证
|
||||
const staticResult = verifyStatic();
|
||||
|
||||
// Step 2: 闭环运行验证
|
||||
const loopResult = await verifyLoop(options.live);
|
||||
|
||||
// 综合结果
|
||||
const allPass = staticResult.pass && loopResult.success !== false;
|
||||
|
||||
console.log('');
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
console.log(`📊 综合验证结果: ${allPass ? '✅ 通过' : '❌ 未通过'}`);
|
||||
console.log(` 静态检查: ${staticResult.pass ? '✅' : '❌'} (${staticResult.passed}/${staticResult.total})`);
|
||||
console.log(` 闭环运行: ${loopResult.success !== false ? '✅' : '❌'}`);
|
||||
console.log('═══════════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
// 输出到 GITHUB_OUTPUT
|
||||
const outputFile = process.env.GITHUB_OUTPUT;
|
||||
if (outputFile) {
|
||||
fs.appendFileSync(outputFile, `verify_pass=${allPass}\n`);
|
||||
fs.appendFileSync(outputFile, `static_pass=${staticResult.pass}\n`);
|
||||
fs.appendFileSync(outputFile, `loop_pass=${loopResult.success !== false}\n`);
|
||||
}
|
||||
|
||||
return { pass: allPass, static: staticResult, loop: loopResult, timestamp };
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// 模块导出
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
module.exports = { verify, verifyStatic, verifyLoop };
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// CLI 入口
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
const live = args.includes('--live');
|
||||
|
||||
verify({ live }).then(result => {
|
||||
if (!result.pass) {
|
||||
process.exit(1);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('[VERIFY] 💥 致命错误:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
|
@ -43,7 +43,10 @@
|
|||
"connector:notion": "node connectors/notion-sync status",
|
||||
"connector:model": "node connectors/model-router",
|
||||
"connector:wake-listener": "node connectors/notion-wake-listener status",
|
||||
"connector:wake-poll": "node connectors/notion-wake-listener poll"
|
||||
"connector:wake-poll": "node connectors/notion-wake-listener poll",
|
||||
"openclaw": "node openclaw",
|
||||
"openclaw:dry": "node openclaw --dry-run",
|
||||
"openclaw:verify": "node openclaw/verify-loop"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.13.6",
|
||||
|
|
|
|||
Loading…
Reference in New Issue