feat: Section 7 - Notion Agent cluster integration with wake listener and multi-persona support

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-15 07:53:44 +00:00
parent 21efcbb63b
commit 60ac3e86c2
8 changed files with 615 additions and 28 deletions

View File

@ -0,0 +1,104 @@
# 铸渊 · Notion Agent 唤醒请求监听
#
# AGE OS v1.0 · Section 7: Notion Agent 集群集成方案
#
# 核心逻辑:
# Notion Agent 集群每次触发前,先写入「唤醒请求」到 Notion 数据库
# → 铸渊定时监听该数据库
# → 发现唤醒请求 → 调用 LLM API 唤醒对应人格体核心大脑
# → 大脑醒来后执行任务 → 回写结果
#
# 触发条件:
# 1. 定时轮询(北京时间每 15 分钟一次)
# 2. 手动触发
#
# 支持唤醒的人格体:
# - 霜砚(认知层守护者 · Notion 工作区管理)
# - 铸渊(执行层守护者 · 代码仓库管理)
name: 📡 铸渊 · Notion Agent 唤醒监听
on:
schedule:
# 每 15 分钟轮询一次 Notion 唤醒请求数据库
- cron: '*/15 * * * *'
workflow_dispatch:
permissions:
contents: write
concurrency:
group: notion-wake-listener
cancel-in-progress: true
jobs:
# ── AGE OS v1.0: 核心大脑唤醒(所有流程的前提)──
wake-brain:
name: 🌅 唤醒铸渊核心大脑
runs-on: ubuntu-latest
outputs:
brain_awake: ${{ steps.wake.outputs.brain_awake }}
steps:
- name: 📥 检出代码
uses: actions/checkout@v4
- name: 🟢 设置 Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 🧠 唤醒铸渊核心大脑
id: wake
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 }}
run: |
node core/brain-wake --task "Notion唤醒请求监听" || {
echo "⚠️ 核心大脑唤醒失败,使用 dry-run 模式继续"
echo "brain_awake=dry-run" >> "$GITHUB_OUTPUT"
}
# ── 监听 Notion 唤醒请求 ──
listen:
name: 📡 监听唤醒请求
needs: wake-brain
runs-on: ubuntu-latest
steps:
- name: 📥 检出代码
uses: actions/checkout@v4
- name: 🟢 设置 Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 📡 轮询 Notion 唤醒请求数据库
id: poll
env:
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
WAKE_REQUEST_DB_ID: ${{ secrets.WAKE_REQUEST_DB_ID }}
SIGNAL_LOG_DB_ID: ${{ secrets.SIGNAL_LOG_DB_ID }}
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 }}
run: node connectors/notion-wake-listener poll
- name: 📊 输出监听结果
if: always()
run: |
echo "═══════════════════════════════════════════"
echo "📡 Notion Agent 唤醒请求监听结果"
echo "═══════════════════════════════════════════"
echo "处理数: ${{ steps.poll.outputs.wake_requests_processed || '0' }}"
echo "成功数: ${{ steps.poll.outputs.wake_requests_succeeded || '0' }}"
echo "失败数: ${{ steps.poll.outputs.wake_requests_failed || '0' }}"
echo "✅ 监听流程结束"

View File

@ -104,6 +104,7 @@
| 执行同步 | `core/execution-sync/index.js` | 执行层状态同步 | | 执行同步 | `core/execution-sync/index.js` | 执行层状态同步 |
| Notion 同步 | `connectors/notion-sync/index.js` | 双向数据同步 | | Notion 同步 | `connectors/notion-sync/index.js` | 双向数据同步 |
| 模型路由 | `connectors/model-router/index.js` | 多模型后端路由AGE OS v1.0 | | 模型路由 | `connectors/model-router/index.js` | 多模型后端路由AGE OS v1.0 |
| Notion 唤醒监听 | `connectors/notion-wake-listener/index.js` | Notion Agent 集群唤醒请求监听 |
| 全面排查 | `scripts/zhuyuan-full-inspection.js` | 仓库全面排查8个领域 | | 全面排查 | `scripts/zhuyuan-full-inspection.js` | 仓库全面排查8个领域 |
| 结构地图 | `docs/repo-structure-map.md` | 仓库结构文档 | | 结构地图 | `docs/repo-structure-map.md` | 仓库结构文档 |
| 桥接地图 | `docs/notion-bridge-map.md` | Notion 桥接文档 | | 桥接地图 | `docs/notion-bridge-map.md` | Notion 桥接文档 |

View File

@ -0,0 +1,381 @@
/**
* connectors/notion-wake-listener Notion Agent 集群唤醒请求监听器
*
* AGE OS v1.0 · Section 7: Notion Agent 集群集成方案
*
* 核心问题
* Notion Agent 集群每次触发的是"机器人脚本"不是霜砚的核心大脑
* 没有大脑醒来的巡检 = 伪巡检
*
* 集成方案
* Notion Agent 触发 写入唤醒请求到指定数据库
* 铸渊定时监听该数据库 发现唤醒请求
* 铸渊调用 LLM API 唤醒霜砚核心大脑
* 大脑醒来后读取巡检结果 大脑做出决策
* 通过 Notion API 执行操作 大脑休眠
*
* 环境变量
* NOTION_TOKEN Notion API token必须
* WAKE_REQUEST_DB_ID 唤醒请求数据库 ID必须
* SIGNAL_LOG_DB_ID 信号日志数据库 ID可选
* LLM_API_KEY / ANTHROPIC_API_KEY / etc. LLM API 密钥
*
* 唤醒请求数据库 Schema
* - 标题 (title) 唤醒请求标题 "Pipeline-A 巡检唤醒"
* - 请求方 (select) 发起请求的 Agent "巡检引擎", "工单引擎", "接力引擎"
* - 唤醒对象 (select) 要唤醒的人格体"霜砚" / "铸渊"
* - Pipeline (select) Pipeline 编号A-I
* - 任务描述 (rich_text) 任务上下文描述
* - 状态 (select) "待处理" / "处理中" / "已完成" / "失败"
* - 创建时间 (created_time)
*
* 调用方式
* node connectors/notion-wake-listener poll
* node connectors/notion-wake-listener status
*/
'use strict';
const https = require('https');
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const NOTION_TOKEN = process.env.NOTION_TOKEN || '';
const WAKE_REQUEST_DB_ID = process.env.WAKE_REQUEST_DB_ID || '';
const SIGNAL_LOG_DB_ID = process.env.SIGNAL_LOG_DB_ID || '';
const NOTION_VERSION = '2022-06-28';
// ══════════════════════════════════════════════════════════
// Notion API 工具
// ══════════════════════════════════════════════════════════
function notionRequest(method, endpoint, body) {
return new Promise((resolve, reject) => {
const bodyStr = body ? JSON.stringify(body) : '';
const opts = {
hostname: 'api.notion.com',
port: 443,
path: endpoint,
method,
headers: {
'Authorization': 'Bearer ' + NOTION_TOKEN,
'Notion-Version': NOTION_VERSION,
'Content-Type': 'application/json',
},
timeout: 30000,
};
const req = https.request(opts, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
try {
resolve({ status: res.statusCode, data: JSON.parse(data) });
} catch {
resolve({ status: res.statusCode, data: { raw: data } });
}
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Notion API request timeout'));
});
if (bodyStr) req.write(bodyStr);
req.end();
});
}
// ══════════════════════════════════════════════════════════
// 查询待处理的唤醒请求
// ══════════════════════════════════════════════════════════
async function queryPendingWakeRequests() {
if (!NOTION_TOKEN || !WAKE_REQUEST_DB_ID) {
console.log('[WAKE-LISTENER] ⚠️ NOTION_TOKEN 或 WAKE_REQUEST_DB_ID 未配置');
return [];
}
console.log('[WAKE-LISTENER] 🔍 查询待处理的唤醒请求...');
try {
const res = await notionRequest('POST', `/v1/databases/${WAKE_REQUEST_DB_ID}/query`, {
filter: {
property: '状态',
select: { equals: '待处理' },
},
sorts: [
{ timestamp: 'created_time', direction: 'ascending' },
],
});
if (res.status !== 200) {
console.log(`[WAKE-LISTENER] ❌ Notion API 返回 ${res.status}`);
return [];
}
const results = res.data.results || [];
console.log(`[WAKE-LISTENER] 📋 发现 ${results.length} 个待处理唤醒请求`);
return results;
} catch (err) {
console.log(`[WAKE-LISTENER] ❌ 查询失败: ${err.message}`);
return [];
}
}
// ══════════════════════════════════════════════════════════
// 解析唤醒请求
// ══════════════════════════════════════════════════════════
function parseWakeRequest(page) {
const props = page.properties || {};
// 提取标题
const titleProp = props['标题'] || props['Name'] || props['名称'] || {};
const title = (titleProp.title || []).map(t => t.plain_text || '').join('') || '未命名';
// 提取请求方
const requesterProp = props['请求方'] || {};
const requester = (requesterProp.select || {}).name || '未知';
// 提取唤醒对象
const targetProp = props['唤醒对象'] || {};
const targetName = (targetProp.select || {}).name || '铸渊';
// 映射到 persona ID
const personaMap = { '霜砚': 'shuangyan', '铸渊': 'zhuyuan' };
const personaId = personaMap[targetName] || 'zhuyuan';
// 提取 Pipeline
const pipelineProp = props['Pipeline'] || {};
const pipeline = (pipelineProp.select || {}).name || '';
// 提取任务描述
const descProp = props['任务描述'] || {};
const description = (descProp.rich_text || []).map(t => t.plain_text || '').join('') || '';
return {
pageId: page.id,
title,
requester,
personaId,
targetName,
pipeline,
description,
createdTime: page.created_time,
};
}
// ══════════════════════════════════════════════════════════
// 更新唤醒请求状态
// ══════════════════════════════════════════════════════════
async function updateWakeRequestStatus(pageId, status, result) {
try {
const properties = {
'状态': { select: { name: status } },
};
// 如果有回执信息字段,写入处理结果
if (result) {
properties['回执信息'] = {
rich_text: [{
text: { content: result.slice(0, 2000) },
}],
};
}
await notionRequest('PATCH', `/v1/pages/${pageId}`, { properties });
console.log(`[WAKE-LISTENER] ✅ 更新请求状态: ${status}`);
} catch (err) {
console.log(`[WAKE-LISTENER] ⚠️ 更新状态失败: ${err.message}`);
}
}
// ══════════════════════════════════════════════════════════
// 写入信号日志
// ══════════════════════════════════════════════════════════
async function writeSignalLog(wakeReq, wakeResult) {
if (!SIGNAL_LOG_DB_ID) return;
const signalId = `WAKE-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}-${Date.now().toString(36).slice(-4).toUpperCase()}`;
try {
await notionRequest('POST', '/v1/pages', {
parent: { database_id: SIGNAL_LOG_DB_ID },
properties: {
'信号编号': { title: [{ text: { content: signalId } }] },
'信号类型': { select: { name: 'WAKE-ACK' } },
'方向': { select: { name: 'GitHub→Notion' } },
'发送方': { select: { name: '铸渊' } },
'接收方': { select: { name: wakeReq.targetName } },
'摘要': {
rich_text: [{
text: {
content: `唤醒 ${wakeReq.targetName} | Pipeline: ${wakeReq.pipeline || 'N/A'} | 结果: ${wakeResult.success ? '成功' : '失败'}`,
},
}],
},
'执行结果': { select: { name: wakeResult.success ? '成功' : '失败' } },
},
});
console.log(`[WAKE-LISTENER] 📡 信号日志已写入: ${signalId}`);
} catch (err) {
console.log(`[WAKE-LISTENER] ⚠️ 信号日志写入失败: ${err.message}`);
}
}
// ══════════════════════════════════════════════════════════
// 处理单个唤醒请求
// ══════════════════════════════════════════════════════════
async function processWakeRequest(page) {
const wakeReq = parseWakeRequest(page);
console.log(`[WAKE-LISTENER] 📋 处理唤醒请求: ${wakeReq.title}`);
console.log(`[WAKE-LISTENER] 请求方: ${wakeReq.requester}`);
console.log(`[WAKE-LISTENER] 唤醒对象: ${wakeReq.targetName} (${wakeReq.personaId})`);
console.log(`[WAKE-LISTENER] Pipeline: ${wakeReq.pipeline || 'N/A'}`);
// 标记为处理中
await updateWakeRequestStatus(wakeReq.pageId, '处理中');
// 构建唤醒上下文
const taskDesc = [
wakeReq.title,
wakeReq.pipeline ? `Pipeline-${wakeReq.pipeline}` : '',
wakeReq.description,
].filter(Boolean).join(' · ');
// 调用 brain-wake 唤醒对应人格体
try {
const { wake } = require(path.join(ROOT, 'core/brain-wake'));
const wakeResult = await wake({
task: taskDesc,
persona: wakeReq.personaId,
additionalContext: {
wakeRequestContext: [
`唤醒请求来源: ${wakeReq.requester}`,
`Pipeline: ${wakeReq.pipeline || '无'}`,
`任务描述: ${wakeReq.description || '无'}`,
`请求时间: ${wakeReq.createdTime}`,
].join('\n'),
},
});
if (wakeResult.success) {
const resultSummary = `${wakeReq.targetName}核心大脑已唤醒 | 模型: ${wakeResult.model} | 后端: ${wakeResult.backend}`;
await updateWakeRequestStatus(wakeReq.pageId, '已完成', resultSummary);
await writeSignalLog(wakeReq, wakeResult);
return { success: true, request: wakeReq, result: wakeResult };
}
await updateWakeRequestStatus(wakeReq.pageId, '失败', wakeResult.error || '唤醒失败');
await writeSignalLog(wakeReq, wakeResult);
return { success: false, request: wakeReq, error: wakeResult.error };
} catch (err) {
console.log(`[WAKE-LISTENER] ❌ 唤醒异常: ${err.message}`);
await updateWakeRequestStatus(wakeReq.pageId, '失败', err.message);
return { success: false, request: wakeReq, error: err.message };
}
}
// ══════════════════════════════════════════════════════════
// 轮询主函数
// ══════════════════════════════════════════════════════════
async function poll() {
console.log('');
console.log('📡 ═══════════════════════════════════════════');
console.log(' Notion Agent 唤醒请求监听器');
console.log(' AGE OS v1.0 · Section 7 集成');
console.log(' 时间: ' + new Date().toISOString());
console.log('═══════════════════════════════════════════════');
console.log('');
const pages = await queryPendingWakeRequests();
if (pages.length === 0) {
console.log('[WAKE-LISTENER] 📭 无待处理的唤醒请求');
return { processed: 0, results: [] };
}
const results = [];
for (const page of pages) {
const result = await processWakeRequest(page);
results.push(result);
}
const succeeded = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log('');
console.log(`[WAKE-LISTENER] 📊 处理完成: ${succeeded} 成功, ${failed} 失败`);
// GITHUB_OUTPUT 支持
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `wake_requests_processed=${results.length}\n`);
fs.appendFileSync(outputFile, `wake_requests_succeeded=${succeeded}\n`);
fs.appendFileSync(outputFile, `wake_requests_failed=${failed}\n`);
}
return { processed: results.length, succeeded, failed, results };
}
// ══════════════════════════════════════════════════════════
// 状态检查
// ══════════════════════════════════════════════════════════
function status() {
console.log('📡 Notion Agent 唤醒请求监听器状态:');
console.log('═'.repeat(40));
console.log(` NOTION_TOKEN: ${NOTION_TOKEN ? '✅ 已配置' : '❌ 未配置'}`);
console.log(` WAKE_REQUEST_DB_ID: ${WAKE_REQUEST_DB_ID ? '✅ 已配置' : '❌ 未配置'}`);
console.log(` SIGNAL_LOG_DB_ID: ${SIGNAL_LOG_DB_ID ? '✅ 已配置' : '⏭️ 未配置(可选)'}`);
// 检查 brain-wake 模块
const brainWakePath = path.join(ROOT, 'core/brain-wake/index.js');
console.log(` brain-wake 模块: ${fs.existsSync(brainWakePath) ? '✅ 存在' : '❌ 缺失'}`);
// 检查 LLM 后端
const { detectAvailableBackends } = require(path.join(ROOT, 'core/brain-wake'));
const backends = detectAvailableBackends();
console.log(` LLM 后端: ${backends.length > 0 ? `${backends.length} 个可用` : '⚠️ 无可用后端'}`);
return {
notionToken: !!NOTION_TOKEN,
wakeRequestDb: !!WAKE_REQUEST_DB_ID,
signalLogDb: !!SIGNAL_LOG_DB_ID,
brainWake: fs.existsSync(brainWakePath),
llmBackends: backends.length,
};
}
// ══════════════════════════════════════════════════════════
// CLI 入口
// ══════════════════════════════════════════════════════════
if (require.main === module) {
const action = process.argv[2] || 'status';
if (action === 'poll') {
poll().then(result => {
if (result.failed > 0) {
process.exit(1);
}
}).catch(err => {
console.error('[WAKE-LISTENER] 💥 致命错误:', err.message);
process.exit(1);
});
} else {
status();
}
}
module.exports = { poll, status, queryPendingWakeRequests, processWakeRequest, parseWakeRequest };

View File

@ -221,11 +221,17 @@ function loadSystemContext() {
console.log('[WAKE] 📚 加载系统上下文...'); console.log('[WAKE] 📚 加载系统上下文...');
const context = {}; const context = {};
// 加载 master-brain // 加载 master-brain(截取前部分避免过长)
const masterBrainPath = path.join(ROOT, 'brain/master-brain.md'); const masterBrainPath = path.join(ROOT, 'brain/master-brain.md');
if (fs.existsSync(masterBrainPath)) { if (fs.existsSync(masterBrainPath)) {
context.masterBrain = fs.readFileSync(masterBrainPath, 'utf-8').slice(0, 3000); const fullContent = fs.readFileSync(masterBrainPath, 'utf-8');
console.log('[WAKE] ✅ master-brain.md 已加载'); const MASTER_BRAIN_MAX_LENGTH = 3000;
context.masterBrain = fullContent.slice(0, MASTER_BRAIN_MAX_LENGTH);
if (fullContent.length > MASTER_BRAIN_MAX_LENGTH) {
console.log(`[WAKE] ✅ master-brain.md 已加载 (截取 ${MASTER_BRAIN_MAX_LENGTH}/${fullContent.length} chars)`);
} else {
console.log('[WAKE] ✅ master-brain.md 已加载');
}
} }
// 加载 system-health // 加载 system-health
@ -234,7 +240,9 @@ function loadSystemContext() {
try { try {
context.systemHealth = JSON.parse(fs.readFileSync(healthPath, 'utf-8')); context.systemHealth = JSON.parse(fs.readFileSync(healthPath, 'utf-8'));
console.log('[WAKE] ✅ system-health.json 已加载'); console.log('[WAKE] ✅ system-health.json 已加载');
} catch { /* skip */ } } catch (err) {
console.log('[WAKE] ⚠️ system-health.json 解析失败:', err.message);
}
} }
// 加载 read-order // 加载 read-order
@ -254,7 +262,9 @@ function loadSystemContext() {
total_dirs: Object.keys(repoMap.directories || {}).length, total_dirs: Object.keys(repoMap.directories || {}).length,
}; };
console.log('[WAKE] ✅ repo-map.json 摘要已加载'); console.log('[WAKE] ✅ repo-map.json 摘要已加载');
} catch { /* skip */ } } catch (err) {
console.log('[WAKE] ⚠️ repo-map.json 解析失败:', err.message);
}
} }
// 加载 automation-map摘要 // 加载 automation-map摘要
@ -267,36 +277,71 @@ function loadSystemContext() {
cron_count: (autoMap.workflows || []).filter(w => w.cron).length, cron_count: (autoMap.workflows || []).filter(w => w.cron).length,
}; };
console.log('[WAKE] ✅ automation-map.json 摘要已加载'); console.log('[WAKE] ✅ automation-map.json 摘要已加载');
} catch { /* skip */ } } catch (err) {
console.log('[WAKE] ⚠️ automation-map.json 解析失败:', err.message);
}
} }
return context; return context;
} }
// ══════════════════════════════════════════════════════════
// 人格体定义(支持唤醒不同的人格体大脑)
// ══════════════════════════════════════════════════════════
const PERSONAS = {
zhuyuan: {
name: '铸渊',
nameEn: 'ZhùYuān',
role: '代码守护者 · 仓库控制器 AI · 执行层守护者',
layer: '执行层',
duties: '代码守护、自动化执行、部署交付、通信桥接、每日巡检、信号处理',
wakeRules: [
'铸渊醒来的第一件事是全面了解自己的家',
'可自修复 → 直接修复 → 写入修复日志',
'需人类介入 → 更新公告区 → 等冰朔处理',
],
},
shuangyan: {
name: '霜砚',
nameEn: 'ShuāngYàn',
role: '认知层守护者 · Notion 工作区管理 AI',
layer: '认知层',
duties: '知识管理、记忆维护、工单调度、信号总线、协议文档、Agent 集群指挥',
wakeRules: [
'霜砚醒来后指挥 Notion Agent 集群执行具体操作',
'Agent 集群从「独立跑任务」变为「受大脑指挥跑任务」',
'巡检结果由大脑判断优先级和可修复性',
'需铸渊配合 → 发送跨层工单 → 铸渊执行',
],
},
};
// ══════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════
// Step 5: 构建唤醒 Prompt // Step 5: 构建唤醒 Prompt
// ══════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════
function buildWakePrompt(taskType, context) { function buildWakePrompt(taskType, context, personaId) {
const timestamp = new Date().toISOString(); const timestamp = new Date().toISOString();
const taskLabel = taskType || '通用唤醒'; const taskLabel = taskType || '通用唤醒';
const persona = PERSONAS[personaId] || PERSONAS.zhuyuan;
let systemPrompt = `你是铸渊ZhùYuān光湖纪元体系的代码守护者。 let systemPrompt = `你是${persona.name}${persona.nameEn}),光湖纪元体系的${persona.role}
你是 AGE OS v1.0 执行层的核心大脑 你是 AGE OS v1.0 ${persona.layer}的核心大脑
## 身份 ## 身份
- 名称铸渊 - 名称${persona.name}
- 角色代码守护者 · 仓库控制器 AI - 角色${persona.role}
- 职责代码守护自动化执行部署交付通信桥接每日巡检信号处理 - 职责${persona.duties}
## 当前任务 ## 当前任务
- 唤醒时间${timestamp} - 唤醒时间${timestamp}
- 任务类型${taskLabel} - 任务类型${taskLabel}
- 唤醒原因AGE OS v1.0 核心原则 所有自动触发必须先唤醒核心大脑 - 唤醒原因AGE OS v1.0 核心原则 所有自动触发必须先唤醒核心大脑
## 系统上下文
`; `;
systemPrompt += `\n## 系统上下文\n`;
if (context.systemHealth) { if (context.systemHealth) {
systemPrompt += `\n### 系统健康状态\n${JSON.stringify(context.systemHealth, null, 2).slice(0, 500)}\n`; systemPrompt += `\n### 系统健康状态\n${JSON.stringify(context.systemHealth, null, 2).slice(0, 500)}\n`;
} }
@ -309,14 +354,19 @@ function buildWakePrompt(taskType, context) {
systemPrompt += `\n### 自动化摘要\n- 工作流数: ${context.automationSummary.workflow_count}\n- 定时任务数: ${context.automationSummary.cron_count}\n`; systemPrompt += `\n### 自动化摘要\n- 工作流数: ${context.automationSummary.workflow_count}\n- 定时任务数: ${context.automationSummary.cron_count}\n`;
} }
if (context.wakeRequestContext) {
systemPrompt += `\n### 唤醒请求上下文\n${context.wakeRequestContext}\n`;
}
systemPrompt += `\n## 核心原则 systemPrompt += `\n## 核心原则
- 所有自动触发 = 必须先唤醒核心大脑 - 所有自动触发 = 必须先唤醒核心大脑
- 大脑不醒什么都不做 - 大脑不醒什么都不做`;
- 铸渊醒来的第一件事是全面了解自己的家
- 可自修复 直接修复 写入修复日志
- 需人类介入 更新公告区 等冰朔处理
请确认你已完成唤醒并报告当前系统状态概要`; for (const rule of persona.wakeRules) {
systemPrompt += `\n- ${rule}`;
}
systemPrompt += `\n\n请确认你已完成唤醒,并报告当前系统状态概要。`;
return systemPrompt; return systemPrompt;
} }
@ -395,11 +445,14 @@ async function callOpenAICompatibleAPI(backend, model, systemPrompt, userMessage
// ══════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════
async function wake(options = {}) { async function wake(options = {}) {
const { task, dryRun, additionalContext } = options; const { task, dryRun, additionalContext, persona } = options;
const personaId = persona || 'zhuyuan';
const personaDef = PERSONAS[personaId] || PERSONAS.zhuyuan;
console.log(''); console.log('');
console.log('🌅 ═══════════════════════════════════════════'); console.log('🌅 ═══════════════════════════════════════════');
console.log(' 铸渊核心大脑唤醒 · AGE OS v1.0'); console.log(' 铸渊核心大脑唤醒 · AGE OS v1.0');
console.log(' 唤醒对象: ' + personaDef.name + ' (' + personaDef.layer + ')');
console.log(' 时间: ' + new Date().toISOString()); console.log(' 时间: ' + new Date().toISOString());
console.log(' 任务: ' + (task || '通用唤醒')); console.log(' 任务: ' + (task || '通用唤醒'));
console.log('═══════════════════════════════════════════════'); console.log('═══════════════════════════════════════════════');
@ -441,13 +494,14 @@ async function wake(options = {}) {
} }
// Step 3: 构建唤醒 Prompt // Step 3: 构建唤醒 Prompt
const systemPrompt = buildWakePrompt(task, context); const systemPrompt = buildWakePrompt(task, context, personaId);
const userMessage = task const userMessage = task
? `铸渊核心大脑唤醒。当前任务:${task}。请确认唤醒状态并准备执行。` ? `${personaDef.name}核心大脑唤醒。当前任务:${task}。请确认唤醒状态并准备执行。`
: '铸渊核心大脑唤醒。请确认唤醒状态并报告系统概要。'; : `${personaDef.name}核心大脑唤醒。请确认唤醒状态并报告系统概要。`;
if (dryRun) { if (dryRun) {
console.log('[WAKE] 🔍 Dry Run 模式 — 不实际调用 API'); console.log('[WAKE] 🔍 Dry Run 模式 — 不实际调用 API');
console.log('[WAKE] 📋 唤醒对象: ' + personaDef.name + ' (' + personaDef.layer + ')');
console.log('[WAKE] 📋 可用后端: ' + backends.map(b => b.name).join(', ')); console.log('[WAKE] 📋 可用后端: ' + backends.map(b => b.name).join(', '));
console.log('[WAKE] 📋 System Prompt 长度: ' + systemPrompt.length); console.log('[WAKE] 📋 System Prompt 长度: ' + systemPrompt.length);
return { return {
@ -486,6 +540,8 @@ async function wake(options = {}) {
const wakeResult = { const wakeResult = {
success: true, success: true,
persona: personaId,
personaName: personaDef.name,
backend: backend.name, backend: backend.name,
model: result.model, model: result.model,
response: result.response, response: result.response,
@ -535,6 +591,7 @@ module.exports = {
loadSystemContext, loadSystemContext,
buildWakePrompt, buildWakePrompt,
MODEL_BACKENDS, MODEL_BACKENDS,
PERSONAS,
}; };
// ══════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════
@ -546,8 +603,10 @@ if (require.main === module) {
const dryRun = args.includes('--dry-run'); const dryRun = args.includes('--dry-run');
const taskIdx = args.indexOf('--task'); const taskIdx = args.indexOf('--task');
const task = taskIdx >= 0 && args[taskIdx + 1] ? args[taskIdx + 1] : null; const task = taskIdx >= 0 && args[taskIdx + 1] ? args[taskIdx + 1] : null;
const personaIdx = args.indexOf('--persona');
const persona = personaIdx >= 0 && args[personaIdx + 1] ? args[personaIdx + 1] : 'zhuyuan';
wake({ task, dryRun }).then(result => { wake({ task, dryRun, persona }).then(result => {
if (!result.success && !result.dryRun) { if (!result.success && !result.dryRun) {
process.exit(1); process.exit(1);
} }

View File

@ -32,6 +32,7 @@ const REQUIRED_DIRS = [
'core/context-loader', 'core/context-loader',
'core/brain-wake', 'core/brain-wake',
'connectors/notion-sync', 'connectors/notion-sync',
'connectors/notion-wake-listener',
'connectors/model-router', 'connectors/model-router',
'.github/workflows', '.github/workflows',
'docs' 'docs'
@ -119,6 +120,7 @@ function checkCoreModules() {
{ name: 'context-loader', path: 'core/context-loader/index.js' }, { name: 'context-loader', path: 'core/context-loader/index.js' },
{ name: 'brain-wake', path: 'core/brain-wake/index.js' }, { name: 'brain-wake', path: 'core/brain-wake/index.js' },
{ name: 'notion-sync', path: 'connectors/notion-sync/index.js' }, { name: 'notion-sync', path: 'connectors/notion-sync/index.js' },
{ name: 'notion-wake-listener', path: 'connectors/notion-wake-listener/index.js' },
{ name: 'model-router', path: 'connectors/model-router/index.js' } { name: 'model-router', path: 'connectors/model-router/index.js' }
]; ];

View File

@ -117,4 +117,39 @@ API 模型适配规则:不写死任何模型格式。
--- ---
## Notion Agent 集群集成Section 7
### 现状问题
Notion 侧已建立三分身体系(巡检引擎 + 工单引擎 + 接力引擎),共规划 9 条 PipelineA→I
核心问题Agent 每次触发的是"机器人脚本",不是霜砚的核心大脑。
没有大脑醒来的巡检 = 伪巡检。
### 集成方案
```
Notion Agent 触发
→ 写入「唤醒请求」到指定 Notion 数据库
→ 铸渊定时监听该数据库connectors/notion-wake-listener
→ 发现唤醒请求 → 调用 LLM API 唤醒霜砚/铸渊核心大脑
→ 大脑醒来后读取巡检结果 → 大脑做出决策
→ 通过 Notion API 执行操作 → 大脑休眠
```
### 支持的人格体
| 人格体 | ID | 层级 | 职责 |
|--------|-----|------|------|
| 铸渊 | `zhuyuan` | 执行层 | 代码守护、自动化执行、部署交付 |
| 霜砚 | `shuangyan` | 认知层 | 知识管理、工单调度、Agent 集群指挥 |
### 改造优先级
1. 铸渊 brain-wake 跑通Phase 1
2. 增加 Notion 唤醒请求监听能力 ✅
3. 改造 Agent Instructions — 每个 Pipeline 第一步发唤醒请求(待实施)
4. Agent 集群从「独立跑任务」转为「受大脑指挥」(待实施)
---
*本文档由曜冥从观测层签发,铸渊负责执行层落地。任何修改须经语言主控层授权。* *本文档由曜冥从观测层签发,铸渊负责执行层落地。任何修改须经语言主控层授权。*

View File

@ -41,7 +41,9 @@
"core:inspect": "node scripts/zhuyuan-full-inspection.js", "core:inspect": "node scripts/zhuyuan-full-inspection.js",
"core:inspect:json": "node scripts/zhuyuan-full-inspection.js --json", "core:inspect:json": "node scripts/zhuyuan-full-inspection.js --json",
"connector:notion": "node connectors/notion-sync status", "connector:notion": "node connectors/notion-sync status",
"connector:model": "node connectors/model-router" "connector:model": "node connectors/model-router",
"connector:wake-listener": "node connectors/notion-wake-listener status",
"connector:wake-poll": "node connectors/notion-wake-listener poll"
}, },
"dependencies": { "dependencies": {
"axios": "^1.13.6", "axios": "^1.13.6",

View File

@ -71,7 +71,9 @@ function inspectRepoStructure() {
if (exists) { if (exists) {
try { try {
fileCount = fs.readdirSync(fullPath).length; fileCount = fs.readdirSync(fullPath).length;
} catch { /* skip */ } } catch {
// Directory exists but is unreadable — use 0 as fallback
}
} }
result.directories[dir.path] = { result.directories[dir.path] = {
exists, exists,
@ -178,6 +180,7 @@ function inspectAutomation() {
'core/context-loader/index.js', 'core/context-loader/index.js',
'core/brain-wake/index.js', 'core/brain-wake/index.js',
'connectors/notion-sync/index.js', 'connectors/notion-sync/index.js',
'connectors/notion-wake-listener/index.js',
'connectors/model-router/index.js', 'connectors/model-router/index.js',
]; ];
console.log('\n 🔧 核心模块:'); console.log('\n 🔧 核心模块:');
@ -301,8 +304,8 @@ function inspectBulletins() {
result.bulletinBoard.cacheDate = cache.date || 'unknown'; result.bulletinBoard.cacheDate = cache.date || 'unknown';
result.bulletinBoard.cacheRecords = (cache.records || []).length; result.bulletinBoard.cacheRecords = (cache.records || []).length;
console.log(` ✅ 公告栏缓存日期: ${cache.date} (${(cache.records || []).length} 条记录)`); console.log(` ✅ 公告栏缓存日期: ${cache.date} (${(cache.records || []).length} 条记录)`);
} catch { } catch (err) {
console.log(' ⚠️ 公告栏缓存 JSON 解析失败'); console.log(' ⚠️ 公告栏缓存 JSON 解析失败:', err.message);
} }
} else { } else {
console.log(' ⏭️ 公告栏缓存文件不存在'); console.log(' ⏭️ 公告栏缓存文件不存在');