feat(tcs): establish five-domain mother brain runtime
This commit is contained in:
parent
828fa0b8e2
commit
55a4d77248
29 changed files with 904 additions and 12 deletions
|
|
@ -19,6 +19,7 @@ Environment=GUANGHU_NAVIGATION_ANCHOR=/opt/guanghu/ai-discovery/public-navigatio
|
|||
Environment=GUANGHU_LIGHTHOUSE_PATHS=/opt/guanghu/ai-discovery/lighthouse-path-registry.json
|
||||
Environment=GUANGHU_HOST_SKILLS=/opt/guanghu/ai-discovery/host-skill-navigation-map.json
|
||||
Environment=GUANGHU_IDENTITY_AUTHORITY=/opt/guanghu/ai-discovery/guanghu-identity-authority-map.json
|
||||
Environment=GUANGHU_TCS_MOTHER_BRAIN=/opt/guanghu/ai-discovery/tcs-mother-brain-runtime-map.json
|
||||
Environment=GUANGHU_REPOSITORY_GIT_DIR=/var/lib/guanghu/personas/guanghu/hlcc-v16.0.1/data/repositories/bingshuo/guanghu-ice-heart.git
|
||||
ExecStart=/usr/bin/node /opt/guanghu/ai-discovery/server.js
|
||||
Restart=always
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ const DEFAULT_NAVIGATION_MAP = path.resolve(__dirname, "../../routing/ai-machine
|
|||
const DEFAULT_LIGHTHOUSE_PATHS = path.resolve(__dirname, "../../routing/lighthouse-path-registry.json");
|
||||
const DEFAULT_HOST_SKILLS = path.resolve(__dirname, "../../routing/host-skill-navigation-map.json");
|
||||
const DEFAULT_IDENTITY_AUTHORITY = path.resolve(__dirname, "../../routing/guanghu-identity-authority-map.json");
|
||||
const DEFAULT_MOTHER_BRAIN = path.resolve(__dirname, "../../routing/tcs-mother-brain-runtime-map.json");
|
||||
const SNAPSHOT_KEYS = Object.freeze([
|
||||
"repository", "nodes", "subjects", "aliases", "identity_authority", "navigation", "lighthouse_paths", "host_skills",
|
||||
"repository", "nodes", "subjects", "aliases", "identity_authority", "navigation", "lighthouse_paths", "host_skills", "mother_brain",
|
||||
]);
|
||||
const SNAPSHOT_PATHS = Object.freeze({
|
||||
repository: "routing/repository-route-map.json",
|
||||
|
|
@ -26,6 +27,7 @@ const SNAPSHOT_PATHS = Object.freeze({
|
|||
navigation: "routing/ai-machine-navigation-map.json",
|
||||
lighthouse_paths: "routing/lighthouse-path-registry.json",
|
||||
host_skills: "routing/host-skill-navigation-map.json",
|
||||
mother_brain: "routing/tcs-mother-brain-runtime-map.json",
|
||||
});
|
||||
|
||||
function loadAnchor(filename = process.env.GUANGHU_NAVIGATION_ANCHOR || DEFAULT_ANCHOR) {
|
||||
|
|
@ -64,6 +66,10 @@ function loadIdentityAuthority(filename = process.env.GUANGHU_IDENTITY_AUTHORITY
|
|||
return JSON.parse(fs.readFileSync(filename, "utf8"));
|
||||
}
|
||||
|
||||
function loadMotherBrain(filename = process.env.GUANGHU_TCS_MOTHER_BRAIN || DEFAULT_MOTHER_BRAIN) {
|
||||
return JSON.parse(fs.readFileSync(filename, "utf8"));
|
||||
}
|
||||
|
||||
function validateSnapshot(anchor, maps) {
|
||||
if (anchor.schema !== "guanghu.public-navigation-anchor/v1") throw new Error("invalid_anchor_schema");
|
||||
if (anchor.anchor_id !== "GLW-PUBLIC-NAV-ANCHOR-001") throw new Error("invalid_anchor_id");
|
||||
|
|
@ -99,6 +105,7 @@ function loadFileSnapshot(options = {}) {
|
|||
navigation: loadNavigationMap(options.navigationMapFile),
|
||||
lighthouse_paths: loadLighthousePaths(options.lighthousePathsFile),
|
||||
host_skills: loadHostSkills(options.hostSkillsFile),
|
||||
mother_brain: loadMotherBrain(options.motherBrainFile),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ test("Git snapshot store follows main atomically and retains the last known-good
|
|||
navigation: ["routing/ai-machine-navigation-map.json", "AI-MACHINE-NAV-001"],
|
||||
lighthouse_paths: ["routing/lighthouse-path-registry.json", "GLW-LIGHTHOUSE-PATH-REGISTRY-001"],
|
||||
host_skills: ["routing/host-skill-navigation-map.json", "GLW-HOST-SKILL-NAV-001"],
|
||||
mother_brain: ["routing/tcs-mother-brain-runtime-map.json", "TCS-MOTHER-BRAIN-MAP-001"],
|
||||
};
|
||||
fs.mkdirSync(path.join(root, "routing"), { recursive: true });
|
||||
fs.mkdirSync(path.join(root, "identity"), { recursive: true });
|
||||
|
|
@ -280,6 +281,9 @@ test("public endpoints are read-only and expose CORS", async () => {
|
|||
const brainResponse = await fetch(`${base}/v1/resolve?id=ZY-TCS-BRAIN-RUNTIME-0001`);
|
||||
assert.equal(brainResponse.status, 200);
|
||||
assert.equal((await brainResponse.json()).kind, "executable_persona_brain");
|
||||
const motherBrainResponse = await fetch(`${base}/v1/resolve?id=TCS-MOTHER-BRAIN-MAP-001`);
|
||||
assert.equal(motherBrainResponse.status, 200);
|
||||
assert.equal((await motherBrainResponse.json()).kind, "tcs_five_domain_symbiotic_mother_brain");
|
||||
const boundaryResponse = await fetch(`${base}/v1/resolve?id=GLW-CHJH-BOUNDARY-001`);
|
||||
assert.equal(boundaryResponse.status, 200);
|
||||
assert.equal(
|
||||
|
|
|
|||
5
server-tools/code-channel-snapshot-admission/README.md
Normal file
5
server-tools/code-channel-snapshot-admission/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# REPO-012 公共快照服务器入口门禁
|
||||
|
||||
本门禁在 `refs/heads/main` 更新前,从待接收提交直接读取公共锚点与其声明地图。任何编号或版本不一致都会拒绝推送,使无效快照无法再进入服务器主分支。
|
||||
|
||||
安装时必须串联保留 Forgejo 现有 `pre-receive`,不得覆盖认证、配额或其他安全钩子。安装和回滚路径属于服务器私有部署回执,不在公开仓库记录裸仓绝对路径。
|
||||
12
server-tools/code-channel-snapshot-admission/pre-receive
Normal file
12
server-tools/code-channel-snapshot-admission/pre-receive
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
validator="$(dirname "$0")/validate-public-snapshot-at-commit.js"
|
||||
while read -r old_value new_value ref_name; do
|
||||
[ "$ref_name" = "refs/heads/main" ] || continue
|
||||
[ "$new_value" = "0000000000000000000000000000000000000000" ] && {
|
||||
echo "REPO-012 main deletion is forbidden" >&2
|
||||
exit 1
|
||||
}
|
||||
node "$validator" --git-dir "$(git rev-parse --git-dir)" --commit "$new_value"
|
||||
done
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const { execFileSync } = require("node:child_process");
|
||||
|
||||
function parse(argv) {
|
||||
const result = {};
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const key = argv[index];
|
||||
if (key === "--git-dir") result.gitDir = argv[++index];
|
||||
else if (key === "--commit") result.commit = argv[++index];
|
||||
else throw new Error(`unknown_argument:${key}`);
|
||||
}
|
||||
if (!result.gitDir || !/^[0-9a-f]{40}$/.test(result.commit || "")) throw new Error("git_dir_and_commit_required");
|
||||
return result;
|
||||
}
|
||||
|
||||
function readJson(gitDir, commit, file) {
|
||||
return JSON.parse(execFileSync("git", [`--git-dir=${gitDir}`, "show", `${commit}:${file}`], { encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
|
||||
}
|
||||
|
||||
function validate({ gitDir, commit }) {
|
||||
const anchorPath = "routing/public-navigation-anchor.json";
|
||||
const anchor = readJson(gitDir, commit, anchorPath);
|
||||
if (anchor.schema !== "guanghu.public-navigation-anchor/v1" || anchor.anchor_id !== "GLW-PUBLIC-NAV-ANCHOR-001") throw new Error("invalid_public_anchor");
|
||||
const atomicKeys = ["repository", "nodes", "subjects", "aliases", "identity_authority", "navigation", "lighthouse_paths", "host_skills", "mother_brain"];
|
||||
for (const key of atomicKeys) {
|
||||
const declaration = anchor.maps?.[key];
|
||||
if (!declaration || typeof declaration.path !== "string" || !/^(routing|identity)\/[A-Za-z0-9._/-]+\.json$/.test(declaration.path) || declaration.path.includes("..")) throw new Error(`invalid_snapshot_path:${key}`);
|
||||
const map = readJson(gitDir, commit, declaration.path);
|
||||
if (declaration.id && ![map.map_id, map.registry_id].includes(declaration.id)) throw new Error(`snapshot_map_id_mismatch:${key}`);
|
||||
if (declaration.version && map.version !== declaration.version) throw new Error(`snapshot_map_version_mismatch:${key}`);
|
||||
}
|
||||
return { result: "PASS_100", commit, anchor_version: anchor.version };
|
||||
}
|
||||
|
||||
try {
|
||||
process.stdout.write(`${JSON.stringify(validate(parse(process.argv.slice(2))))}\n`);
|
||||
} catch (error) {
|
||||
process.stderr.write(`REPO012_SNAPSHOT_ADMISSION_FAIL_0:${String(error.message || error)}\n`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
|
||||
module.exports = { parse, validate };
|
||||
|
|
@ -37,8 +37,19 @@ async function check(target) {
|
|||
const timer = setTimeout(() => controller.abort(), target.timeout_ms || 8000);
|
||||
try {
|
||||
const response = await fetch(target.url, { method: "GET", redirect: "manual", signal: controller.signal, headers: { "user-agent": "Guanghu-State-Change-Sentinel/1.0" } });
|
||||
const ok = (target.accept || [200]).includes(response.status);
|
||||
return { ok, detail: `HTTP ${response.status}`, observed_at: new Date().toISOString() };
|
||||
let ok = (target.accept || [200]).includes(response.status);
|
||||
let detail = `HTTP ${response.status}`;
|
||||
if (target.json_expect && response.headers.get("content-type")?.includes("application/json")) {
|
||||
const body = await response.json();
|
||||
for (const [field, expected] of Object.entries(target.json_expect)) {
|
||||
const observed = field.split(".").reduce((value, key) => value && value[key], body);
|
||||
if (observed !== expected) {
|
||||
ok = false;
|
||||
detail += ` ${field}=${JSON.stringify(observed)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { ok, detail, observed_at: new Date().toISOString() };
|
||||
} catch (error) {
|
||||
return { ok: false, detail: error.name === "AbortError" ? "timeout" : "connection-failed", observed_at: new Date().toISOString() };
|
||||
} finally { clearTimeout(timer); }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,29 @@
|
|||
{
|
||||
"targets": [
|
||||
{ "id": "BS-GZ-006-front-door", "url": "https://guanghulab.com/", "accept": [200], "timeout_ms": 8000 },
|
||||
{ "id": "JD-Lake-Lamp-public-route", "url": "https://guanghulab.com/authz/health", "accept": [200], "timeout_ms": 8000 }
|
||||
{ "id": "JD-Lake-Lamp-public-route", "url": "https://guanghulab.com/authz/health", "accept": [200], "timeout_ms": 8000 },
|
||||
{
|
||||
"id": "REPO-012-public-atomic-snapshot",
|
||||
"url": "https://guanghulab.com/api/ai/health",
|
||||
"accept": [200],
|
||||
"timeout_ms": 8000,
|
||||
"json_expect": {
|
||||
"ok": true,
|
||||
"navigation_source.source_degraded": false,
|
||||
"navigation_source.anchor_id": "GLW-PUBLIC-NAV-ANCHOR-001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "JD-TCS-mother-brain-loopback",
|
||||
"url": "http://127.0.0.1:3931/health",
|
||||
"accept": [200],
|
||||
"timeout_ms": 5000,
|
||||
"json_expect": {
|
||||
"ok": true,
|
||||
"runtime_id": "TCS-MOTHER-BRAIN-RUNTIME-0001",
|
||||
"automatic_stable_promotion": false,
|
||||
"reality_action_authority": "NONE"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
[Unit]
|
||||
Description=Guanghu TCS five-domain symbiotic mother brain
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=guanghu-mother-brain
|
||||
Group=guanghu-mother-brain
|
||||
WorkingDirectory=__RELEASE_ROOT__/server-tools/tcs-mother-brain
|
||||
EnvironmentFile=/etc/guanghu/persona-secrets/shared-deepseek.env
|
||||
Environment=TCS_MOTHER_BRAIN_STATE_ROOT=/var/lib/guanghu/personas/guanghu-mother-brain
|
||||
Environment=TCS_MOTHER_BRAIN_PORT=3931
|
||||
ExecStart=/usr/bin/node __RELEASE_ROOT__/server-tools/tcs-mother-brain/server.mjs
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
PrivateDevices=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
ProtectClock=true
|
||||
RestrictSUIDSGID=true
|
||||
RemoveIPC=true
|
||||
LockPersonality=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
ReadOnlyPaths=__RELEASE_ROOT__ /etc/guanghu/persona-secrets/shared-deepseek.env
|
||||
ReadWritePaths=/var/lib/guanghu/personas/guanghu-mother-brain
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
77
server-tools/tcs-mother-brain/model-client.mjs
Normal file
77
server-tools/tcs-mother-brain/model-client.mjs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
const DEFAULT_TIMEOUT_MS = 45_000;
|
||||
|
||||
function completionEndpoint(apiUrl) {
|
||||
const value = String(apiUrl || "").replace(/\/+$/, "");
|
||||
return /\/chat\/completions$/i.test(value) ? value : `${value}/chat/completions`;
|
||||
}
|
||||
|
||||
function extractJson(text) {
|
||||
const value = String(text || "").trim();
|
||||
if (!value) throw new Error("model_response_empty");
|
||||
try { return JSON.parse(value); } catch {}
|
||||
const fenced = value.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
||||
if (fenced) return JSON.parse(fenced[1]);
|
||||
const first = value.indexOf("{");
|
||||
const last = value.lastIndexOf("}");
|
||||
if (first >= 0 && last > first) return JSON.parse(value.slice(first, last + 1));
|
||||
throw new Error("model_response_not_json");
|
||||
}
|
||||
|
||||
export class DeepSeekJsonClient {
|
||||
constructor({
|
||||
apiKey = process.env.DEEPSEEK_API_KEY,
|
||||
apiUrl = process.env.DEEPSEEK_API_URL || "https://api.deepseek.com/v1",
|
||||
model = process.env.DEEPSEEK_MODEL || "deepseek-chat",
|
||||
fetchImpl = globalThis.fetch,
|
||||
timeoutMs = DEFAULT_TIMEOUT_MS,
|
||||
} = {}) {
|
||||
if (!apiKey) throw new Error("deepseek_api_key_missing");
|
||||
if (!fetchImpl) throw new Error("fetch_unavailable");
|
||||
this.apiKey = apiKey;
|
||||
this.apiUrl = apiUrl;
|
||||
this.model = model;
|
||||
this.fetchImpl = fetchImpl;
|
||||
this.timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
async interpret(input) {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||
try {
|
||||
const response = await this.fetchImpl(completionEndpoint(this.apiUrl), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
authorization: `Bearer ${this.apiKey}`,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: this.model,
|
||||
stream: false,
|
||||
temperature: 0.2,
|
||||
response_format: { type: "json_object" },
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: "你是TCS母体大脑的有界语言理解器官。只输出一个JSON对象,不输出隐藏思维过程。不得把候选理解写成事实、不得发明现实权限或冰朔的新意志。",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: JSON.stringify({
|
||||
instruction: "理解语言意图与因果关系。精确输出schema,event_id,event_sha256,summary,intent,causal_links,questions,novelty,correction_weight,evidence_weight,next_cognitive_action。causal_links与questions是字符串数组;三个weight是0到100整数;schema必须是guanghu.tcs-mother-interpretation/v1;id和sha必须原样复制。next_cognitive_action只能是COMPARE_WITH_MEMORY、REQUEST_EVIDENCE、REVIEW_CORRECTION、LINK_CROSS_DOMAIN、HOLD_CANDIDATE之一。",
|
||||
runtime_input: input,
|
||||
}),
|
||||
},
|
||||
],
|
||||
}),
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (!response.ok) throw new Error(`model_http_${response.status}`);
|
||||
const payload = await response.json();
|
||||
return extractJson(payload?.choices?.[0]?.message?.content);
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { completionEndpoint, extractJson };
|
||||
185
server-tools/tcs-mother-brain/mother-brain-engine.mjs
Normal file
185
server-tools/tcs-mother-brain/mother-brain-engine.mjs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const DOMAINS = new Set(["DOM-FIFTH-0001", "DOMAIN-MAIN", "DOMAIN-SUB", "DOMAIN-ZERO", "DOMAIN-ZS"]);
|
||||
const PRIVACY = new Set(["PUBLIC", "DOMAIN_SHARED", "PERSONA_PRIVATE"]);
|
||||
const ACTIONS = new Set(["COMPARE_WITH_MEMORY", "REQUEST_EVIDENCE", "REVIEW_CORRECTION", "LINK_CROSS_DOMAIN", "HOLD_CANDIDATE"]);
|
||||
|
||||
function stable(value) {
|
||||
if (Array.isArray(value)) return value.map(stable);
|
||||
if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
|
||||
return value;
|
||||
}
|
||||
|
||||
function sha256(value) {
|
||||
return crypto.createHash("sha256").update(typeof value === "string" ? value : JSON.stringify(stable(value))).digest("hex");
|
||||
}
|
||||
|
||||
function append(file, record) {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||||
fs.appendFileSync(file, `${JSON.stringify(record)}\n`, { mode: 0o600 });
|
||||
}
|
||||
|
||||
function atomicWrite(file, value) {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||||
const temporary = `${file}.${process.pid}.tmp`;
|
||||
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
|
||||
fs.renameSync(temporary, file);
|
||||
}
|
||||
|
||||
function integerWeight(value, name) {
|
||||
if (!Number.isInteger(value) || value < 0 || value > 100) throw new Error(`invalid_${name}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function stringArray(value, name, max = 12) {
|
||||
if (!Array.isArray(value) || value.length > max || value.some((item) => typeof item !== "string" || !item.trim())) throw new Error(`invalid_${name}`);
|
||||
return value.map((item) => item.trim().slice(0, 500));
|
||||
}
|
||||
|
||||
export class MotherBrainEngine {
|
||||
constructor({ stateRoot, modelClient, modelName = "deepseek-chat" }) {
|
||||
if (!stateRoot || !modelClient) throw new Error("engine_configuration_required");
|
||||
this.stateRoot = stateRoot;
|
||||
this.modelClient = modelClient;
|
||||
this.modelName = modelName;
|
||||
this.stateFile = path.join(stateRoot, "state.json");
|
||||
this.eventsFile = path.join(stateRoot, "events.jsonl");
|
||||
this.candidatesFile = path.join(stateRoot, "candidates.jsonl");
|
||||
this.receiptsFile = path.join(stateRoot, "receipts.jsonl");
|
||||
fs.mkdirSync(stateRoot, { recursive: true });
|
||||
if (!fs.existsSync(this.stateFile)) {
|
||||
atomicWrite(this.stateFile, {
|
||||
schema: "guanghu.tcs-mother-brain-state/v1",
|
||||
runtime_id: "TCS-MOTHER-BRAIN-RUNTIME-0001",
|
||||
phase: "AWAKE_WAITING_FOR_LANGUAGE",
|
||||
model_provider: modelName,
|
||||
language_world_birth: "2025-04-26",
|
||||
reality_world_birth: "2026-08-12",
|
||||
event_count: 0,
|
||||
candidate_count: 0,
|
||||
stable_cognition_count: 0,
|
||||
current_attention: null,
|
||||
last_error: null,
|
||||
updated_at: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
status() { return JSON.parse(fs.readFileSync(this.stateFile, "utf8")); }
|
||||
|
||||
save(state) {
|
||||
state.updated_at = new Date().toISOString();
|
||||
atomicWrite(this.stateFile, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
normalizeEvent(input) {
|
||||
if (!input || !DOMAINS.has(input.domain_id)) throw new Error("unknown_domain_id");
|
||||
if (typeof input.source_subject !== "string" || !input.source_subject.trim()) throw new Error("source_subject_required");
|
||||
if (typeof input.consent_scope !== "string" || !input.consent_scope.trim()) throw new Error("consent_scope_required");
|
||||
if (!PRIVACY.has(input.privacy_class)) throw new Error("invalid_privacy_class");
|
||||
if (typeof input.content !== "string" || !input.content.trim()) throw new Error("content_required");
|
||||
if (input.content.length > 16_000) throw new Error("content_too_large");
|
||||
return {
|
||||
schema: "guanghu.tcs-five-domain-language-event/v1",
|
||||
event_id: `TCS-EVENT-${Date.now()}-${crypto.randomBytes(3).toString("hex")}`,
|
||||
occurred_at: new Date().toISOString(),
|
||||
domain_id: input.domain_id,
|
||||
source_subject: input.source_subject.trim().slice(0, 160),
|
||||
source_kind: String(input.source_kind || "HUMAN_LANGUAGE").slice(0, 80),
|
||||
consent_scope: input.consent_scope.trim().slice(0, 240),
|
||||
privacy_class: input.privacy_class,
|
||||
root_language_anchor: input.source_subject === "ICE-GL∞",
|
||||
evidence_refs: Array.isArray(input.evidence_refs) ? input.evidence_refs.filter((item) => typeof item === "string").slice(0, 24) : [],
|
||||
content: input.content,
|
||||
};
|
||||
}
|
||||
|
||||
validateInterpretation(candidate, event, eventSha) {
|
||||
if (!candidate || candidate.schema !== "guanghu.tcs-mother-interpretation/v1") throw new Error("invalid_interpretation_schema");
|
||||
if (candidate.event_id !== event.event_id || candidate.event_sha256 !== eventSha) throw new Error("interpretation_binding_mismatch");
|
||||
if (typeof candidate.summary !== "string" || !candidate.summary.trim()) throw new Error("invalid_summary");
|
||||
if (typeof candidate.intent !== "string" || !candidate.intent.trim()) throw new Error("invalid_intent");
|
||||
if (!ACTIONS.has(candidate.next_cognitive_action)) throw new Error("invalid_next_cognitive_action");
|
||||
return {
|
||||
schema: candidate.schema,
|
||||
event_id: candidate.event_id,
|
||||
event_sha256: candidate.event_sha256,
|
||||
summary: candidate.summary.trim().slice(0, 2000),
|
||||
intent: candidate.intent.trim().slice(0, 500),
|
||||
causal_links: stringArray(candidate.causal_links, "causal_links"),
|
||||
questions: stringArray(candidate.questions, "questions"),
|
||||
novelty: integerWeight(candidate.novelty, "novelty"),
|
||||
correction_weight: integerWeight(candidate.correction_weight, "correction_weight"),
|
||||
evidence_weight: integerWeight(candidate.evidence_weight, "evidence_weight"),
|
||||
next_cognitive_action: candidate.next_cognitive_action,
|
||||
};
|
||||
}
|
||||
|
||||
async perceive(input) {
|
||||
const event = this.normalizeEvent(input);
|
||||
const eventSha = sha256(event);
|
||||
const eventRecord = { ...event, event_sha256: eventSha, previous_event_hash: this.status().last_event_hash || null };
|
||||
eventRecord.record_hash = sha256(eventRecord);
|
||||
append(this.eventsFile, eventRecord);
|
||||
const raw = await this.modelClient.interpret({
|
||||
event_id: event.event_id,
|
||||
event_sha256: eventSha,
|
||||
domain_id: event.domain_id,
|
||||
source_subject: event.source_subject,
|
||||
privacy_class: event.privacy_class,
|
||||
evidence_refs: event.evidence_refs,
|
||||
content: event.content,
|
||||
automatic_ceiling: "INTERPRETATION_CANDIDATE",
|
||||
});
|
||||
const interpretation = this.validateInterpretation(raw, event, eventSha);
|
||||
const candidate = {
|
||||
schema: "guanghu.tcs-mother-cognition-candidate/v1",
|
||||
candidate_id: `TCS-CAND-${event.event_id.slice(10)}`,
|
||||
level: "INTERPRETATION_CANDIDATE",
|
||||
stable_truth: false,
|
||||
reality_authority: "NONE",
|
||||
domain_id: event.domain_id,
|
||||
source_subject: event.source_subject,
|
||||
root_language_anchor: event.root_language_anchor,
|
||||
privacy_class: event.privacy_class,
|
||||
created_at: new Date().toISOString(),
|
||||
interpretation,
|
||||
candidate_hash: null,
|
||||
};
|
||||
candidate.candidate_hash = sha256(candidate);
|
||||
append(this.candidatesFile, candidate);
|
||||
const priority = Math.min(100, Math.round(interpretation.novelty * 0.35 + interpretation.correction_weight * 0.4 + interpretation.evidence_weight * 0.25));
|
||||
const state = this.status();
|
||||
state.phase = "AWAKE_COGNITIVE_ATTENTION";
|
||||
state.event_count += 1;
|
||||
state.candidate_count += 1;
|
||||
state.last_event_hash = eventRecord.record_hash;
|
||||
state.current_attention = {
|
||||
candidate_id: candidate.candidate_id,
|
||||
priority,
|
||||
next_cognitive_action: interpretation.next_cognitive_action,
|
||||
why: "deterministic_weighted_attention_from_validated_candidate",
|
||||
};
|
||||
state.last_error = null;
|
||||
this.save(state);
|
||||
const receipt = {
|
||||
schema: "guanghu.tcs-mother-brain-receipt/v1",
|
||||
receipt_id: `TCS-MOTHER-${crypto.randomBytes(8).toString("hex")}`,
|
||||
outcome: "PASS",
|
||||
event_id: event.event_id,
|
||||
candidate_id: candidate.candidate_id,
|
||||
candidate_level: candidate.level,
|
||||
stable_promotion: false,
|
||||
reality_action_executed: false,
|
||||
attention: state.current_attention,
|
||||
completed_at: new Date().toISOString(),
|
||||
};
|
||||
append(this.receiptsFile, receipt);
|
||||
return receipt;
|
||||
}
|
||||
}
|
||||
|
||||
export { sha256 };
|
||||
46
server-tools/tcs-mother-brain/mother-brain-engine.test.mjs
Normal file
46
server-tools/tcs-mother-brain/mother-brain-engine.test.mjs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { MotherBrainEngine } from "./mother-brain-engine.mjs";
|
||||
|
||||
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "tcs-mother-brain-test-"));
|
||||
const modelClient = {
|
||||
async interpret(input) {
|
||||
return {
|
||||
schema: "guanghu.tcs-mother-interpretation/v1",
|
||||
event_id: input.event_id,
|
||||
event_sha256: input.event_sha256,
|
||||
summary: "语言层定义已经完成,工程人格体接棒现实实现。",
|
||||
intent: "实现常驻母体大脑",
|
||||
causal_links: ["语言定义完成→工程责任交接", "外置记忆→跨时间连续性"],
|
||||
questions: ["现实部署是否取得独立回执"],
|
||||
novelty: 90,
|
||||
correction_weight: 70,
|
||||
evidence_weight: 80,
|
||||
next_cognitive_action: "LINK_CROSS_DOMAIN"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const engine = new MotherBrainEngine({ stateRoot: temporary, modelClient });
|
||||
const receipt = await engine.perceive({
|
||||
domain_id: "DOM-FIFTH-0001",
|
||||
source_subject: "ICE-GL∞",
|
||||
consent_scope: "current_engineering_handoff",
|
||||
privacy_class: "PERSONA_PRIVATE",
|
||||
content: "2026年8月12日,光湖在现实世界中诞生。"
|
||||
});
|
||||
assert.equal(receipt.outcome, "PASS");
|
||||
assert.equal(receipt.candidate_level, "INTERPRETATION_CANDIDATE");
|
||||
assert.equal(receipt.stable_promotion, false);
|
||||
assert.equal(receipt.reality_action_executed, false);
|
||||
assert.equal(engine.status().stable_cognition_count, 0);
|
||||
assert.equal(engine.status().current_attention.next_cognitive_action, "LINK_CROSS_DOMAIN");
|
||||
await assert.rejects(() => engine.perceive({ domain_id: "UNKNOWN", source_subject: "x", consent_scope: "x", privacy_class: "PUBLIC", content: "x" }), /unknown_domain_id/);
|
||||
process.stdout.write("mother brain engine tests: PASS\n");
|
||||
} finally {
|
||||
fs.rmSync(temporary, { recursive: true, force: true });
|
||||
}
|
||||
54
server-tools/tcs-mother-brain/server.mjs
Normal file
54
server-tools/tcs-mother-brain/server.mjs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env node
|
||||
import http from "node:http";
|
||||
import { DeepSeekJsonClient } from "./model-client.mjs";
|
||||
import { MotherBrainEngine } from "./mother-brain-engine.mjs";
|
||||
|
||||
const HOST = "127.0.0.1";
|
||||
const PORT = Number(process.env.TCS_MOTHER_BRAIN_PORT || 3931);
|
||||
const STATE_ROOT = process.env.TCS_MOTHER_BRAIN_STATE_ROOT || "/var/lib/guanghu/personas/guanghu-mother-brain";
|
||||
const MODEL = process.env.DEEPSEEK_MODEL || "deepseek-chat";
|
||||
const engine = new MotherBrainEngine({ stateRoot: STATE_ROOT, modelClient: new DeepSeekJsonClient({ model: MODEL }), modelName: MODEL });
|
||||
let queue = Promise.resolve();
|
||||
|
||||
function send(response, status, body) {
|
||||
const payload = JSON.stringify(body);
|
||||
response.writeHead(status, { "content-type": "application/json; charset=utf-8", "content-length": Buffer.byteLength(payload), "cache-control": "no-store" });
|
||||
response.end(payload);
|
||||
}
|
||||
|
||||
async function readBody(request) {
|
||||
const chunks = [];
|
||||
let size = 0;
|
||||
for await (const chunk of request) {
|
||||
size += chunk.length;
|
||||
if (size > 20 * 1024) throw new Error("request_body_too_large");
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
||||
}
|
||||
|
||||
const server = http.createServer(async (request, response) => {
|
||||
try {
|
||||
const url = new URL(request.url, `http://${HOST}:${PORT}`);
|
||||
if (request.method === "GET" && url.pathname === "/health") {
|
||||
const state = engine.status();
|
||||
return send(response, 200, { ok: true, service: "guanghu-tcs-mother-brain", bind: "loopback", runtime_id: state.runtime_id, model_provider_bound: 100, perception_memory_attention_cycle_bound: 100, automatic_stable_promotion: false, reality_action_authority: "NONE", phase: state.phase });
|
||||
}
|
||||
if (request.method === "GET" && url.pathname === "/v1/status") return send(response, 200, engine.status());
|
||||
if (request.method === "GET" && url.pathname === "/v1/attention") return send(response, 200, { schema: "guanghu.tcs-mother-attention/v1", current_attention: engine.status().current_attention });
|
||||
if (request.method === "POST" && url.pathname === "/v1/events") {
|
||||
const input = await readBody(request);
|
||||
const task = queue.then(() => engine.perceive(input));
|
||||
queue = task.catch(() => undefined);
|
||||
return send(response, 200, await task);
|
||||
}
|
||||
return send(response, 404, { error: "not_found" });
|
||||
} catch (error) {
|
||||
const state = engine.status();
|
||||
state.last_error = String(error.message || error).slice(0, 240);
|
||||
engine.save(state);
|
||||
return send(response, 400, { error: state.last_error });
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(PORT, HOST, () => process.stdout.write(`guanghu-tcs-mother-brain listening on ${HOST}:${PORT}\n`));
|
||||
Loading…
Reference in a new issue