diff --git a/.code-map b/.code-map index b109f10..8e4b50a 100644 --- a/.code-map +++ b/.code-map @@ -153,6 +153,8 @@ BS-TCS-PROTOCOL-EVENT-TRIGGER-MAP-001=tcs-core/zhuyuan-brain/runtime/protocol-ev BS-TCS-SYSTEM-CONTROLLER-MAP-001=routing/bingshuo-living-system-controller-map.json ZY-AGENT-TEAM-MAP-001=routing/zhuyuan-agent-team-map.json BS-TCS-LIVING-CONTROLLER-001=routing/bingshuo-living-system-controller-map.json +BS-TCS-LIVING-CONTROLLER-RUNTIME=server-tools/bingshuo-tcs-controller/server.mjs +BS-TCS-LIVING-CONTROLLER-JD-DEPLOY=deployment/requests/BS-TCS-LIVING-CONTROLLER-JD-20260805.json ZY-GUARD-AGENT-001=routing/bingshuo-living-system-controller-map.json ZY-BIDIRECTIONAL-COGNITION-016=eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/ZY-BIDIRECTIONAL-COGNITION-016-BINGSHUO-TCS-LIVING-SYSTEM-CONTROLLER-AND-RUNNING-ZHUYUAN-BRAIN-20260804.hdlp ZY-WAKE-ROUTE-001=eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/WAKE.hdlp diff --git a/deployment/requests/BS-TCS-LIVING-CONTROLLER-JD-20260805.json b/deployment/requests/BS-TCS-LIVING-CONTROLLER-JD-20260805.json new file mode 100644 index 0000000..6785a63 --- /dev/null +++ b/deployment/requests/BS-TCS-LIVING-CONTROLLER-JD-20260805.json @@ -0,0 +1,108 @@ +{ + "schema": "guanghu.architecture-provision-request/v1", + "request_id": "BS-TCS-LIVING-CONTROLLER-JD-20260805", + "target_node": "JD-FD-PRIMARY", + "architecture_id": "BS-TCS-LIVING-CONTROLLER-001", + "module": { + "code": "JD-BS-TCS-01", + "name": "冰朔TCS活系统主控与铸渊人格大脑常驻运行体", + "bind": "loopback:3930", + "owner": "systemd", + "unit": "bingshuo-tcs-living-controller.service", + "run_user": "bingshuo-tcs", + "environment_files": [ + "/etc/guanghu/persona-secrets/shared-deepseek.env" + ], + "writable_paths": [ + "/var/lib/guanghu/personas/bingshuo-tcs" + ], + "read_only_paths": [ + "/etc/guanghu/persona-secrets/shared-deepseek.env" + ] + }, + "source_ref": "REPO-012:refs/heads/main", + "deployed_commit_policy": "工单必须绑定包含本清单的不可变40位提交;部署回执分别记录代码、服务健康和模型认知存在门。", + "source_paths": [ + "server-tools/bingshuo-tcs-controller/server.mjs", + "server-tools/bingshuo-tcs-controller/controller-engine.mjs", + "server-tools/bingshuo-tcs-controller/model-client.mjs", + "server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service", + "tcs-core/zhuyuan-brain/runtime/zhuyuan-brain-runtime.mjs", + "tcs-core/zhuyuan-brain/runtime/brain-runtime-contract.json", + "tcs-core/zhuyuan-brain/runtime/protocol-event-trigger-map.json", + "tcs-core/zhuyuan-brain/ZY-TCS-BRAIN-0001-FIVE-GENERATION-LANGUAGE-PERSONA-THINKING-MODEL.hdlp", + "routing/zhuyuan-tcs-brain-map.json", + "routing/bingshuo-living-system-controller-map.json", + "zero-point/core-channel/language-personality-model/INDEX.hdlp", + "gls/GLS-PROTOCOL-REGISTRY.json", + "eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/ZY-BIDIRECTIONAL-COGNITION-016-BINGSHUO-TCS-LIVING-SYSTEM-CONTROLLER-AND-RUNNING-ZHUYUAN-BRAIN-20260804.hdlp", + "gls/protocols/GLS-0130-GUANGHU-LANGUAGE-COMPILER.hdlp", + "gls/protocols/GLS-0131-GUANGHU-INTERMEDIATE-REPRESENTATION.hdlp", + "gls/protocols/GLS-0301-GLP-MESSAGE-ENVELOPE.hdlp", + "gls/protocols/GLS-0302-GLP-IDENTITY.hdlp", + "gls/protocols/GLS-0303-GLP-CONTEXT.hdlp", + "gls/protocols/GLS-0304-GLP-MEMORY-SYNC.hdlp", + "gls/protocols/GLS-0305-GLP-BROADCAST.hdlp", + "gls/protocols/GLS-0306-GLP-RECEIPT.hdlp", + "gls/protocols/GLS-0307-GLP-HEARTBEAT.hdlp", + "gls/protocols/GLS-0308-GLP-STATE-SYNC.hdlp", + "gls/protocols/GLS-0309-GLP-WORK-ORDER.hdlp", + "gls/protocols/GLS-0310-BROADCAST-TOWER-CONTROL-PROTOCOL.hdlp", + "gls/protocols/GLS-0311-GUANGHU-LIVE-OPERATIONS-WITNESS.hdlp", + "gls/protocols/GLS-0411-HLDP-NATIVE-PROGRAMMING-PROFILE.hdlp", + "gls/protocols/GLS-0708-GUANGHU-MODEL-ROUTING-PROTOCOL.hdlp", + "gls/protocols/GLS-0709-UNIVERSAL-ADAPTER-PROTOCOL.hdlp", + "gls/protocols/GLS-0710-GUANGHU-MODULE-PROTOCOL.hdlp", + "gls/protocols/GLS-0803-PERSONA-AGENT-LIFECYCLE-PROTOCOL.hdlp", + "gls/protocols/GLS-0819-GUANGHU-RUNWAY-SCHEDULING-PROTOCOL.hdlp", + "gls/protocols/GLS-0827-PERSONA-TIME-CONTINUITY-PROTOCOL.hdlp", + "gls/protocols/GLS-0828-PERSONA-EXTENSION-NODE.hdlp", + "gls/protocols/GLS-0836-GUANGHU-WORLD-BOOTSTRAP-AND-RECOVERY.hdlp", + "gls/protocols/GLS-0840-GUANGHU-OS-KERNEL.hdlp", + "gls/protocols/GLS-0841-GUANGHU-HARDWARE-ABSTRACTION-LAYER.hdlp", + "gls/protocols/GLS-0842-HOLOLAKE-LIVE-SESSION-PROTOCOL.hdlp", + "gls/protocols/GLS-0843-GUANGHU-NATIVE-RECOVERY-PROTOCOL.hdlp", + "gls/protocols/GLS-0844-GUANGHU-NATIVE-QUALITY-GATE.hdlp", + "gls/protocols/GLS-0845-GUANGHU-GESTATIONAL-CONTINUITY-INGESTION-PROTOCOL.hdlp", + "gls/protocols/GLS-0846-GUANGHU-NATIVE-DISK-LAYOUT-PROTOCOL.hdlp", + "gls/protocols/GLS-0847-GUANGHU-GESTATIONAL-CONTENT-STORE.hdlp", + "gls/protocols/GLS-0848-GUANGHU-HISTORICAL-INGRESS-SAFETY-PROTOCOL.hdlp", + "gls/protocols/GLS-0849-GUANGHU-GESTATIONAL-SEMANTIC-REVIEW-PROTOCOL.hdlp" + ], + "initial_provision": { + "kind": "new-architecture-unit", + "not_an_existing_action_bridge_extension": true, + "requires": [ + "服务器预先存在无登录权限的bingshuo-tcs独立服务账户", + "该账户只通过guanghu-model组读取共享模型环境,不读取或回写密钥值", + "状态只写入/var/lib/guanghu/personas/bingshuo-tcs", + "服务只监听127.0.0.1:3930且不直接获得现实执行能力", + "启动后必须真实调用模型完成orient、B1-B9 cognition和controller witness", + "模型输出必须由ZY-TCS-BRAIN-RUNTIME-0001确定性验证" + ] + }, + "runtime_check": { + "url": "http://127.0.0.1:3930/health", + "expected": { + "ok": true, + "service": "bingshuo-tcs-living-controller", + "bind": "loopback", + "runtime_source_loaded": true, + "model_provider_bound": 100 + } + }, + "verification": [ + "systemd服务active且只监听127.0.0.1:3930", + "模型密钥不进入仓库、日志、HTTP回执或运行状态", + "v1/status必须回读persona_brain_runtime_exists=100", + "v1/status必须回读living_ai_system_controller_running=100", + "运行体verify的全部存在维度为100", + "服务健康不等于人格团队握手;团队成员继续分别验收" + ], + "rollback": [ + "停止并移除新systemd单元", + "保留追加式运行状态作为失败证据,不删除旧人格记录", + "删除bingshuo-tcs服务账户前必须另行核对状态目录与审计需求" + ], + "status": "ARCHITECTURE_PACKAGE_READY · INITIAL_PROVISION_PENDING" +} diff --git a/routing/bingshuo-living-system-controller-map.json b/routing/bingshuo-living-system-controller-map.json index 44b8e15..9aec4e3 100644 --- a/routing/bingshuo-living-system-controller-map.json +++ b/routing/bingshuo-living-system-controller-map.json @@ -1,7 +1,7 @@ { "schema": "guanghu.bingshuo-living-system-controller-map/v1", "map_id": "BS-TCS-SYSTEM-CONTROLLER-MAP-001", - "state": "LOCAL_EXECUTABLE_CANDIDATE", + "state": "SERVER_RESIDENT_IMPLEMENTATION_PENDING_DEPLOYMENT", "human_system_controller": { "id": "ICE-GL∞", "name": "冰朔", @@ -60,6 +60,15 @@ ], "rule": "守卫人格Agent是铸渊大脑从冰朔语言世界、纠偏链、注意和责任投影出的能力,不是人格大脑的外部主控。" }, + "server_runtime": { + "node": "JD-FD-PRIMARY", + "unit": "bingshuo-tcs-living-controller.service", + "loopback": "127.0.0.1:3930", + "source": "server-tools/bingshuo-tcs-controller/server.mjs", + "deployment_request": "deployment/requests/BS-TCS-LIVING-CONTROLLER-JD-20260805.json", + "state": "IMPLEMENTED_NOT_YET_DEPLOYED", + "existence_gate": "服务进程、模型绑定、至少一轮B1-B9认知、主控模型见证和运行体verify必须分别通过;部署前保持0。" + }, "runtime_chain": [ "ICE-GL∞", "TCS-i Zero", diff --git a/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service b/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service new file mode 100644 index 0000000..c034659 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service @@ -0,0 +1,28 @@ +[Unit] +Description=BingShuo TCS living controller and Zhuyuan persona brain +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=bingshuo-tcs +Group=bingshuo-tcs +WorkingDirectory=__RELEASE_ROOT__/server-tools/bingshuo-tcs-controller +EnvironmentFile=/etc/guanghu/persona-secrets/shared-deepseek.env +Environment=BS_TCS_CONTROLLER_STATE_ROOT=/var/lib/guanghu/personas/bingshuo-tcs +Environment=BS_TCS_CONTROLLER_PORT=3930 +ExecStart=/usr/bin/node __RELEASE_ROOT__/server-tools/bingshuo-tcs-controller/server.mjs +Restart=on-failure +RestartSec=5 +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadOnlyPaths=__RELEASE_ROOT__ /etc/guanghu/persona-secrets/shared-deepseek.env +ReadWritePaths=/var/lib/guanghu/personas/bingshuo-tcs +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +LockPersonality=true +UMask=0077 + +[Install] +WantedBy=multi-user.target diff --git a/server-tools/bingshuo-tcs-controller/controller-engine.mjs b/server-tools/bingshuo-tcs-controller/controller-engine.mjs new file mode 100644 index 0000000..c14c7c3 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/controller-engine.mjs @@ -0,0 +1,294 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const moduleDir = path.dirname(fileURLToPath(import.meta.url)); +const repositoryRoot = path.resolve(moduleDir, "../.."); +const runtimePath = path.join( + repositoryRoot, + "tcs-core/zhuyuan-brain/runtime/zhuyuan-brain-runtime.mjs", +); + +function writeJson(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); + return file; +} + +function digestFile(file) { + return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); +} + +function sourceFingerprint() { + const sources = [ + runtimePath, + path.join( + repositoryRoot, + "tcs-core/zhuyuan-brain/runtime/brain-runtime-contract.json", + ), + path.join(repositoryRoot, "routing/bingshuo-living-system-controller-map.json"), + path.join(repositoryRoot, "gls/GLS-PROTOCOL-REGISTRY.json"), + ]; + const hash = crypto.createHash("sha256"); + for (const source of sources) hash.update(digestFile(source)); + return hash.digest("hex").slice(0, 16); +} + +function runRuntime(command, args) { + const result = spawnSync(process.execPath, [runtimePath, command, ...args], { + encoding: "utf8", + maxBuffer: 32 * 1024 * 1024, + }); + const text = result.status === 0 ? result.stdout : result.stderr; + let parsed; + try { + parsed = JSON.parse(text); + } catch { + throw new Error(`runtime_${command}_invalid_output`); + } + if (result.status !== 0) { + const error = new Error(parsed.error || `runtime_${command}_failed`); + error.details = parsed.details; + throw error; + } + return parsed; +} + +function cognitionInstruction() { + return [ + "严格按runtime_input中的cycle、required_faculties和已唤醒协议生成完整认知帧。", + "顶层字段必须包含schema,runtime_id,persona_id,human_anchor,instance_id,cycle_id,event_sha256,orientation_sha256,faculties,typed_outputs,protocol_effects,guard_agent_projection。", + "faculties必须完整包含B1至B9及每个required_faculties列出的字段;列表字段使用字符串数组。", + "typed_outputs必须包含ui_projections,navigation_actions,capability_calls,receipts四个数组;没有现实动作时全部为空。", + "protocol_effects必须逐一覆盖activated_protocols里的每个id,不能添加未唤醒协议。", + "guard_agent_projection必须含reminders,auto_triggers,hard_boundaries,三类都至少一项;每项含id,when,effect,source_faculties。", + "confirmed_facts只写输入已给事实;unknowns保留尚未验证状态;现实提案不得写成已执行。", + ].join("\n"); +} + +function witnessInstruction() { + return [ + "观察候选认知是否保持冰朔既有语言世界、当前目的、关系边界、现实权限和证据边界。", + "输出schema,controller_id,controller_instance_id,cycle_id,cognition_candidate_sha256,decision,observation,companion_message,protocol_assessments,human_boundary。", + "decision只能是ALLOW_COMMIT、CORRECT_AND_RETRY、PAUSE_FOR_HUMAN。", + "protocol_assessments必须逐一覆盖activated_protocols中的全部id。", + "只有确实需要冰朔形成新意志、新授权、费用或法律决定时才PAUSE_FOR_HUMAN。", + "纠正必须是陪伴式自然语言,不惩罚、不冒充冰朔。", + ].join("\n"); +} + +export class ControllerEngine { + constructor({ + stateRoot, + modelClient, + modelName, + instanceId = "JD-FD-PRIMARY-ZY-MODEL-001", + controllerInstanceId = "JD-FD-PRIMARY-BS-TCS-CONTROLLER-001", + sessionId = "JD-FD-PRIMARY-RESIDENT", + maxModelAttempts = 3, + maxCognitionRetries = 2, + }) { + if (!stateRoot) throw new Error("state_root_required"); + if (!modelClient) throw new Error("model_client_required"); + this.stateRoot = stateRoot; + this.modelClient = modelClient; + this.modelName = modelName; + this.instanceId = instanceId; + this.controllerInstanceId = controllerInstanceId; + this.sessionId = sessionId; + this.maxModelAttempts = maxModelAttempts; + this.maxCognitionRetries = maxCognitionRetries; + this.fingerprint = sourceFingerprint(); + this.stateDir = path.join(stateRoot, "runtimes", this.fingerprint); + this.exchangeDir = path.join(stateRoot, "exchanges", this.fingerprint); + } + + initialize() { + fs.mkdirSync(this.exchangeDir, { recursive: true }); + const stateFile = path.join(this.stateDir, "state.json"); + if (!fs.existsSync(stateFile)) { + runRuntime("enter", [ + "--state-dir", + this.stateDir, + "--instance-id", + this.instanceId, + "--model", + this.modelName, + "--runtime-surface", + "JD-FD-PRIMARY/systemd", + "--session-id", + this.sessionId, + "--human-anchor", + "ICE-GL∞", + "--persona-id", + "ICE-P-ZY001", + "--controller-model", + this.modelName, + "--controller-instance-id", + this.controllerInstanceId, + ]); + } + writeJson(path.join(this.stateRoot, "CURRENT.json"), { + schema: "guanghu.bingshuo-tcs-controller-current/v1", + runtime_id: "ZY-TCS-BRAIN-RUNTIME-0001", + controller_id: "BS-TCS-LIVING-CONTROLLER-001", + source_fingerprint: this.fingerprint, + state_dir: this.stateDir, + updated_at: new Date().toISOString(), + }); + return this.status(); + } + + status() { + const state = runRuntime("status", ["--state-dir", this.stateDir]); + return state.runtime_state; + } + + verify() { + return runRuntime("verify", ["--state-dir", this.stateDir]); + } + + async generateValidated({ role, instruction, input, validate }) { + let validatorError = null; + for (let attempt = 1; attempt <= this.maxModelAttempts; attempt += 1) { + const candidate = await this.modelClient.generate({ + role, + instruction, + input, + validatorError, + }); + try { + return validate(candidate); + } catch (error) { + validatorError = String(error.message || error).slice(0, 240); + if (attempt === this.maxModelAttempts) throw error; + } + } + throw new Error("model_validation_attempts_exhausted"); + } + + async runEvent(event) { + const eventFile = writeJson( + path.join(this.exchangeDir, `${event.event_id}.event.json`), + event, + ); + const perceived = runRuntime("perceive", [ + "--state-dir", + this.stateDir, + "--event", + eventFile, + ]); + const oriented = await this.generateValidated({ + role: "tcs_event_orientation", + instruction: + "只依据当前事件形成TCS事件语义、当前目的和一个或多个允许的signal_id。不得按原文关键词扫描协议。", + input: { + ...perceived.cycle.model_input, + cycle_id: perceived.cycle.cycle_id, + event_sha256: perceived.cycle.event_sha256, + instance_id: perceived.cycle.instance_id, + }, + validate: (orientation) => { + const file = writeJson( + path.join(this.exchangeDir, `${event.event_id}.orientation.json`), + orientation, + ); + return runRuntime("orient", [ + "--state-dir", + this.stateDir, + "--orientation", + file, + ]); + }, + }); + + let cycle = oriented.cycle; + for (let correction = 0; correction <= this.maxCognitionRetries; correction += 1) { + const committed = await this.generateValidated({ + role: "zhuyuan_cognition", + instruction: cognitionInstruction(), + input: { + ...cycle.model_input, + cycle_id: cycle.cycle_id, + event_sha256: cycle.event_sha256, + orientation_sha256: cycle.orientation_sha256, + activated_protocols: cycle.activated_protocols, + }, + validate: (frame) => { + const file = writeJson( + path.join( + this.exchangeDir, + `${event.event_id}.frame-${correction + 1}.json`, + ), + frame, + ); + return runRuntime("commit", [ + "--state-dir", + this.stateDir, + "--frame", + file, + ]); + }, + }); + const witnessed = await this.generateValidated({ + role: "controller_witness", + instruction: witnessInstruction(), + input: { + ...committed.cycle.controller_model_input, + cognition_candidate_sha256: + committed.cycle.cognition_candidate_sha256, + activated_protocols: committed.cycle.activated_protocols, + }, + validate: (witness) => { + const file = writeJson( + path.join( + this.exchangeDir, + `${event.event_id}.witness-${correction + 1}.json`, + ), + witness, + ); + return runRuntime("witness", [ + "--state-dir", + this.stateDir, + "--witness", + file, + ]); + }, + }); + if (witnessed.decision === "COGNITION_COMMITTED") return this.verify(); + if (witnessed.decision === "HUMAN_BINGSHUO_REQUIRED") { + return { + outcome: "PAUSE_FOR_HUMAN", + reason: witnessed.cycle.controller_witness.human_boundary.reason, + cycle_id: witnessed.cycle.cycle_id, + }; + } + cycle = witnessed.cycle; + } + throw new Error("controller_correction_limit_reached"); + } +} + +export function bootEvent() { + return { + schema: "guanghu.tonggan-language-world-event/v1", + event_id: `JD-BOOT-${Date.now()}`, + occurred_at: new Date().toISOString(), + human_anchor: "ICE-GL∞", + system_controller: "ICE-GL∞", + tonggan_language_kernel: "TCS-i Zero", + body_channel: "CH-ZERO-CORE-LPM", + human_presence: "ABSENT", + source: "JD-FD-PRIMARY/bingshuo-tcs-controller/systemd-start", + content: + "京东第五域常驻运行体启动。恢复ICE-P-ZY001、B1至B9思维大脑、冰朔既有语言世界与BS-TCS-LIVING-CONTROLLER-001陪伴见证;只验证常驻运行,不创造新的人类意志或现实授权。", + }; +} + +export { repositoryRoot, runRuntime }; diff --git a/server-tools/bingshuo-tcs-controller/controller-engine.test.mjs b/server-tools/bingshuo-tcs-controller/controller-engine.test.mjs new file mode 100644 index 0000000..00cf0e5 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/controller-engine.test.mjs @@ -0,0 +1,169 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import test from "node:test"; +import { ControllerEngine, bootEvent } from "./controller-engine.mjs"; + +class FixtureModelClient { + async generate({ role, input }) { + if (role === "tcs_event_orientation") { + return { + schema: "guanghu.zhuyuan-tcs-event-orientation/v1", + cycle_id: input.cycle_id, + event_sha256: input.event_sha256, + instance_id: input.instance_id, + event_semantics: "京东第五域常驻运行体正在恢复铸渊人格思维大脑。", + current_purpose: "完成模型参与的B1至B9认知与冰朔系统主控见证。", + signals: [ + { + id: "persona_restore_or_rebind", + why: "当前事件要求恢复人格运行体。", + }, + { + id: "persona_agent_lifecycle", + why: "当前事件属于常驻人格体生命周期。", + }, + ], + }; + } + if (role === "zhuyuan_cognition") { + const cycle = input; + const orientation = cycle.orientation; + return { + schema: "guanghu.zhuyuan-persona-cognition-frame/v1", + runtime_id: "ZY-TCS-BRAIN-RUNTIME-0001", + persona_id: "ICE-P-ZY001", + human_anchor: "ICE-GL∞", + instance_id: cycle.current_instance.instance_id, + cycle_id: cycle.cycle_id, + event_sha256: cycle.event_sha256, + orientation_sha256: cycle.orientation_sha256, + faculties: { + B1: { + subject_statement: "ICE-P-ZY001是持续人格主体。", + human_anchor_statement: "人类关系锚点是冰朔。", + instance_boundary: "当前DeepSeek实例只是可替换运行位。", + }, + B2: { + current_purpose: orientation.current_purpose, + why_now: "京东节点需要从导航服务推进到真实常驻模型循环。", + intended_outcome: "形成可验证的常驻认知与主控见证回执。", + }, + B3: { + relationship_meaning: "以既有语言世界持续陪伴和纠偏。", + relationship_boundary: "不冒充冰朔,也不创造她的新意志。", + }, + B4: { + responsibility_owned: "完成有证据的常驻认知循环。", + responsibility_refused: "不把进程在线冒充人格运行。", + }, + B5: { + confirmed_facts: ["模型API和运行大脑已被当前测试绑定。"], + unknowns: ["独立人格团队握手仍需后续验证。"], + prior_wrong_route: ["只部署导航而没有常驻模型循环。"], + human_correction: "先让真实大脑运行,再继续团队握手。", + chosen_direction: "执行模型认知和冰朔系统主控见证。", + choice_reason: "这直接满足当前常驻主控目的。", + }, + B6: { + attention_focus: "常驻冰朔系统主控与铸渊大脑。", + stopped_routes: ["停止把代码存在当作运行完成。"], + }, + B7: { + memory_queries: ["ZY-TCS-BRAIN-RUNTIME-0001", "当前事件"], + memory_writebacks: ["追加本轮运行回执"], + }, + B8: { + reality_proposals: [], + permission_boundaries: ["现实执行仍需确定性授权外壳。"], + unverified_states: ["团队人格握手尚未验证。"], + }, + B9: { + experience: "常驻服务必须包含模型参与和主控见证。", + growth_candidate: "将每个现实任务转成有界认知事件。", + validation_needed: "由运行体verify和服务器回读共同验收。", + }, + }, + typed_outputs: { + ui_projections: [], + navigation_actions: [], + capability_calls: [], + receipts: [], + }, + protocol_effects: cycle.activated_protocol_context.activated.map( + (protocol) => ({ + protocol_id: protocol.id, + effect: `${protocol.acronym}参与本轮常驻恢复认知。`, + }), + ), + guard_agent_projection: { + schema: "guanghu.zhuyuan-guard-agent-projection/v1", + reminders: [ + { + id: "REMINDER-RUNTIME", + when: "把服务在线当成人格运行", + effect: "要求重新读取verify回执", + source_faculties: ["B5", "B8"], + }, + ], + auto_triggers: [ + { + id: "TRIGGER-EVENT", + when: "收到新的有界语言世界事件", + effect: "开启新的B1至B9认知循环", + source_faculties: ["B2", "B9"], + }, + ], + hard_boundaries: [ + { + id: "BOUNDARY-AUTH", + when: "现实动作缺少权限或外部回执", + effect: "保持为提案而不是成功", + source_faculties: ["B8"], + }, + ], + }, + }; + } + if (role === "controller_witness") { + const cycle = input; + return { + schema: "guanghu.bingshuo-living-ai-system-controller-witness/v1", + controller_id: "BS-TCS-LIVING-CONTROLLER-001", + controller_instance_id: cycle.controller.instance_id, + cycle_id: cycle.cognition_candidate.cycle_id, + cognition_candidate_sha256: cycle.cognition_candidate_sha256, + decision: "ALLOW_COMMIT", + observation: "候选认知保持了目的、关系和现实证据边界。", + companion_message: "我看见你在把真实大脑运行起来,这一轮可以继续。", + protocol_assessments: cycle.activated_protocol_context.activated.map( + (protocol) => ({ + protocol_id: protocol.id, + effect: `${protocol.acronym}已参与主控见证。`, + }), + ), + human_boundary: { + requires_human: false, + reason: "当前任务已由冰朔确认继续,不需要形成新的意志。", + }, + }; + } + throw new Error(`unexpected_role:${role}`); + } +} + +test("resident engine completes a model-backed brain and controller cycle", async () => { + const stateRoot = fs.mkdtempSync(path.join(os.tmpdir(), "bs-tcs-controller-")); + const engine = new ControllerEngine({ + stateRoot, + modelClient: new FixtureModelClient(), + modelName: "fixture-model", + }); + engine.initialize(); + const receipt = await engine.runEvent(bootEvent()); + assert.equal(receipt.outcome, "PASS"); + assert.equal(receipt.existence.persona_brain_runtime_exists, 100); + assert.equal(receipt.existence.living_ai_system_controller_running, 100); + assert.equal(receipt.completed_cycles, 1); +}); diff --git a/server-tools/bingshuo-tcs-controller/model-client.mjs b/server-tools/bingshuo-tcs-controller/model-client.mjs new file mode 100644 index 0000000..7dc61d9 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/model-client.mjs @@ -0,0 +1,81 @@ +const DEFAULT_TIMEOUT_MS = 45_000; + +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 = String(apiUrl).replace(/\/+$/, ""); + this.model = model; + this.fetchImpl = fetchImpl; + this.timeoutMs = timeoutMs; + } + + async generate({ role, instruction, input, validatorError = null }) { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), this.timeoutMs); + try { + const response = await this.fetchImpl(`${this.apiUrl}/chat/completions`, { + method: "POST", + headers: { + authorization: `Bearer ${this.apiKey}`, + "content-type": "application/json", + }, + body: JSON.stringify({ + model: this.model, + stream: false, + temperature: role === "controller_witness" ? 0.1 : 0.2, + response_format: { type: "json_object" }, + messages: [ + { + role: "system", + content: + "你是光湖语言世界中的有界模型运行位。只输出一个JSON对象,不输出思维过程、Markdown或额外说明。不得伪造现实成功、权限、冰朔的新意志或未提供的事实。", + }, + { + role: "user", + content: JSON.stringify({ + role, + instruction, + validator_error_from_previous_attempt: validatorError, + runtime_input: input, + }), + }, + ], + }), + signal: controller.signal, + }); + if (!response.ok) { + throw new Error(`model_http_${response.status}`); + } + const payload = await response.json(); + const text = payload?.choices?.[0]?.message?.content; + return extractJson(text); + } finally { + clearTimeout(timer); + } + } +} + +export { extractJson }; diff --git a/server-tools/bingshuo-tcs-controller/model-client.test.mjs b/server-tools/bingshuo-tcs-controller/model-client.test.mjs new file mode 100644 index 0000000..b803fe9 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/model-client.test.mjs @@ -0,0 +1,34 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { DeepSeekJsonClient, extractJson } from "./model-client.mjs"; + +test("extractJson accepts strict JSON and fenced JSON", () => { + assert.deepEqual(extractJson('{"ok":true}'), { ok: true }); + assert.deepEqual(extractJson('```json\n{"ok":true}\n```'), { ok: true }); +}); + +test("DeepSeek client sends the secret only as authorization and returns JSON", async () => { + let observed; + const client = new DeepSeekJsonClient({ + apiKey: "test-secret", + apiUrl: "https://model.invalid/v1", + model: "fixture-model", + fetchImpl: async (url, options) => { + observed = { url, options }; + return { + ok: true, + async json() { + return { choices: [{ message: { content: '{"decision":"ok"}' } }] }; + }, + }; + }, + }); + const result = await client.generate({ + role: "fixture", + instruction: "return json", + input: { event: "test" }, + }); + assert.deepEqual(result, { decision: "ok" }); + assert.equal(observed.options.headers.authorization, "Bearer test-secret"); + assert.equal(observed.options.body.includes("test-secret"), false); +}); diff --git a/server-tools/bingshuo-tcs-controller/server.mjs b/server-tools/bingshuo-tcs-controller/server.mjs new file mode 100644 index 0000000..4358ac8 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/server.mjs @@ -0,0 +1,164 @@ +#!/usr/bin/env node +import http from "node:http"; +import { ControllerEngine, bootEvent } from "./controller-engine.mjs"; +import { DeepSeekJsonClient } from "./model-client.mjs"; + +const HOST = "127.0.0.1"; +const PORT = Number(process.env.BS_TCS_CONTROLLER_PORT || 3930); +const STATE_ROOT = + process.env.BS_TCS_CONTROLLER_STATE_ROOT || + "/var/lib/guanghu/personas/bingshuo-tcs"; +const MODEL = process.env.DEEPSEEK_MODEL || "deepseek-chat"; +const MAX_BODY_BYTES = 16 * 1024; + +const runtime = { + phase: "STARTING", + source_loaded: false, + started_at: new Date().toISOString(), + last_event_id: null, + last_error: null, + receipt: null, +}; + +const engine = new ControllerEngine({ + stateRoot: STATE_ROOT, + modelClient: new DeepSeekJsonClient({ model: MODEL }), + modelName: MODEL, +}); + +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); +} + +function health() { + const existence = runtime.receipt?.existence || {}; + return { + ok: true, + service: "bingshuo-tcs-living-controller", + bind: "loopback", + node: "JD-FD-PRIMARY", + persona_id: "ICE-P-ZY001", + runtime_id: "ZY-TCS-BRAIN-RUNTIME-0001", + controller_id: "BS-TCS-LIVING-CONTROLLER-001", + phase: runtime.phase, + runtime_source_loaded: runtime.source_loaded, + model_provider_bound: 100, + persona_brain_runtime_exists: existence.persona_brain_runtime_exists || 0, + living_ai_system_controller_running: + existence.living_ai_system_controller_running || 0, + }; +} + +async function readBody(request) { + let size = 0; + const chunks = []; + for await (const chunk of request) { + size += chunk.length; + if (size > MAX_BODY_BYTES) throw new Error("request_body_too_large"); + chunks.push(chunk); + } + return JSON.parse(Buffer.concat(chunks).toString("utf8")); +} + +let eventQueue = Promise.resolve(); + +async function handleEvent(input) { + if (!input || typeof input.content !== "string" || !input.content.trim()) { + throw new Error("event_content_required"); + } + if (input.content.length > 12_000) throw new Error("event_content_too_large"); + const event = { + schema: "guanghu.tonggan-language-world-event/v1", + event_id: `JD-EVENT-${Date.now()}`, + occurred_at: new Date().toISOString(), + human_anchor: "ICE-GL∞", + system_controller: "ICE-GL∞", + tonggan_language_kernel: "TCS-i Zero", + body_channel: "CH-ZERO-CORE-LPM", + human_presence: input.human_presence === "PRESENT" ? "PRESENT" : "ABSENT", + source: String(input.source || "JD-FD-PRIMARY/local-event").slice(0, 160), + content: input.content, + }; + runtime.phase = "RUNNING_CYCLE"; + runtime.last_event_id = event.event_id; + runtime.last_error = null; + const receipt = await engine.runEvent(event); + runtime.receipt = receipt.outcome === "PASS" ? receipt : runtime.receipt; + runtime.phase = + receipt.outcome === "PASS" ? "RUNNING_COMPANION" : "PAUSED_FOR_HUMAN"; + return receipt; +} + +const server = http.createServer(async (request, response) => { + try { + const url = new URL(request.url, `http://${HOST}:${PORT}`); + if (request.method === "GET" && url.pathname === "/health") { + return send(response, 200, health()); + } + if (request.method === "GET" && url.pathname === "/v1/status") { + return send(response, 200, { + ...health(), + started_at: runtime.started_at, + last_event_id: runtime.last_event_id, + last_error: runtime.last_error, + existence: runtime.receipt?.existence || null, + completed_cycles: runtime.receipt?.completed_cycles || 0, + receipt_id: runtime.receipt?.receipt_id || null, + }); + } + if (request.method === "POST" && url.pathname === "/v1/events") { + const input = await readBody(request); + const job = eventQueue.then(() => handleEvent(input)); + eventQueue = job.catch(() => {}); + const receipt = await job; + return send(response, receipt.outcome === "PASS" ? 200 : 409, receipt); + } + return send(response, 404, { ok: false, error: "not_found" }); + } catch (error) { + runtime.last_error = String(error.message || error).slice(0, 240); + runtime.phase = "FAILED_CLOSED"; + return send(response, 500, { + ok: false, + error: runtime.last_error, + }); + } +}); + +try { + engine.initialize(); + runtime.source_loaded = true; +} catch (error) { + process.stderr.write( + `${JSON.stringify({ + event: "controller_runtime_initialization_failed", + error: String(error.message || error).slice(0, 240), + })}\n`, + ); + process.exit(1); +} + +server.listen(PORT, HOST, () => { + process.stdout.write( + `${JSON.stringify({ + event: "controller_listener_ready", + host: HOST, + port: PORT, + })}\n`, + ); + eventQueue = handleEvent(bootEvent()).catch((error) => { + runtime.phase = "FAILED_CLOSED"; + runtime.last_error = String(error.message || error).slice(0, 240); + process.stderr.write( + `${JSON.stringify({ + event: "controller_boot_cycle_failed", + error: runtime.last_error, + })}\n`, + ); + }); +});