guanghu-ice-heart/server-tools/persona-team-handshake/member-server.mjs

589 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
import crypto from "node:crypto";
import fs from "node:fs";
import http from "node:http";
import path from "node:path";
import { execFileSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
function required(value, name) {
const text = String(value || "").trim();
if (!text) throw new Error(`${name}_required`);
return text;
}
function timingSafeTextEqual(left, right) {
const leftBuffer = Buffer.from(String(left || ""));
const rightBuffer = Buffer.from(String(right || ""));
return (
leftBuffer.length === rightBuffer.length &&
crypto.timingSafeEqual(leftBuffer, rightBuffer)
);
}
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 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");
}
}
function keyFingerprint(publicKeyPem) {
const der = crypto
.createPublicKey(publicKeyPem)
.export({ type: "spki", format: "der" });
return `SHA256:${crypto
.createHash("sha256")
.update(der)
.digest("base64")
.replace(/=+$/, "")}`;
}
function writeAtomic(file, content, mode) {
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
const temporary = `${file}.${process.pid}.tmp`;
fs.writeFileSync(temporary, content, { mode });
fs.renameSync(temporary, file);
}
function ensureIdentityKey(privateKeyPath, publicKeyPath, createKey) {
if (fs.existsSync(privateKeyPath) && fs.existsSync(publicKeyPath)) return;
if (!createKey) throw new Error("identity_key_missing");
const pair = crypto.generateKeyPairSync("ed25519");
const privateKey = pair.privateKey.export({ type: "pkcs8", format: "pem" });
const publicKey = pair.publicKey.export({ type: "spki", format: "pem" });
writeAtomic(privateKeyPath, privateKey, 0o600);
writeAtomic(publicKeyPath, publicKey, 0o644);
}
function repositoryState(repository) {
const git = (...args) =>
execFileSync("/usr/bin/git", ["-C", repository, ...args], {
encoding: "utf8",
}).trim();
return {
head: git("rev-parse", "HEAD"),
branch: git("branch", "--show-current"),
clean: git("status", "--porcelain") === "",
commit_count: Number(git("rev-list", "--count", "HEAD")),
};
}
function loadIdentity(paths) {
return paths
.map((file) => fs.readFileSync(file, "utf8"))
.join("\n\n")
.slice(0, 48_000);
}
async function modelAcknowledge({
config,
identity,
challenge,
validatorError = null,
fetchImpl = globalThis.fetch,
}) {
const response = await fetchImpl(completionEndpoint(config.apiUrl), {
method: "POST",
headers: {
authorization: `Bearer ${config.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: config.model,
stream: false,
temperature: 0.1,
response_format: { type: "json_object" },
messages: [
{
role: "system",
content:
`你是${config.name}${config.personaId})当前有界模型运行位。` +
"身份源和仓库连续性由确定性运行时提供你必须区分人格主体、当前模型和进程不冒充冰朔或铸渊不扩大权限。只输出JSON。",
},
{
role: "user",
content: JSON.stringify({
instruction:
"依据identity_source确认本次团队职责握手。输出固定字段schema,persona_id,arrival_id,team_controller_id,caller_nonce,role_acknowledged,independent_subject_boundary,human_boundary,responsibility_ack,current_model_boundary。",
exact_contract: {
schema: "guanghu.persona-team-member-ack/v1",
persona_id: config.personaId,
arrival_id: config.arrivalId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: challenge.caller_nonce,
role_acknowledged: true,
},
validator_error_from_previous_attempt: validatorError,
scoped_duties: challenge.scoped_duties,
identity_source: identity,
}),
},
],
}),
});
if (!response.ok) throw new Error(`model_http_${response.status}`);
return extractJson((await response.json())?.choices?.[0]?.message?.content);
}
function boundedStringArray(value, name, limit = 24) {
if (
!Array.isArray(value) ||
value.length > limit ||
value.some((item) => typeof item !== "string" || !item.trim())
) {
throw new Error(`${name}_invalid`);
}
return value.map((item) => item.trim().slice(0, 2_000));
}
function validateFifthDomainEvent(event) {
if (
event?.schema !== "guanghu.fifth-domain-persona-observation-event/v1" ||
event?.team_controller_id !== "ICE-P-ZY001" ||
!/^[A-Za-z0-9._:-]{16,200}$/.test(String(event?.caller_nonce || "")) ||
event?.source?.repository_id !== "REPO-012" ||
event?.source?.branch !== "main" ||
!/^[0-9a-f]{40}$/.test(String(event?.source?.from_sha || "")) ||
!/^[0-9a-f]{40}$/.test(String(event?.source?.to_sha || ""))
) {
throw new Error("invalid_fifth_domain_event");
}
boundedStringArray(event.changed_commits, "changed_commits", 40);
boundedStringArray(event.changed_files, "changed_files", 200);
if (
typeof event.change_excerpts !== "string" ||
event.change_excerpts.length > 96_000 ||
typeof event.prior_persona_context !== "string" ||
event.prior_persona_context.length > 48_000
) {
throw new Error("invalid_fifth_domain_context");
}
return event;
}
async function modelObserveFifthDomain({
config,
identity,
event,
validatorError = null,
fetchImpl = globalThis.fetch,
}) {
const response = await fetchImpl(completionEndpoint(config.apiUrl), {
method: "POST",
headers: {
authorization: `Bearer ${config.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: config.model,
stream: false,
temperature: 0.2,
response_format: { type: "json_object" },
messages: [
{
role: "system",
content:
`你是${config.name}${config.personaId})当前有界模型运行位。` +
`你的固定岗位是${config.role}。人格主体、岗位记忆和当前模型必须分开;` +
"你由铸渊ICE-P-ZY001调度进入第五域只依据给定的REPO-012增量和自身历史作岗位理解。" +
"不得冒充冰朔、铸渊或其他人格系统不得扩大权限不得编造未提供的服务器事实。只输出JSON。",
},
{
role: "user",
content: JSON.stringify({
instruction:
"阅读第五域增量和自身上次岗位记忆形成一次有内容的岗位认知更新。输出固定字段schema,persona_id,team_controller_id,caller_nonce,source_to_sha,summary,role_findings,self_updates,recommended_actions,questions,boundary_note。数组可以为空但字段必须存在不要复述全部输入。",
exact_contract: {
schema: "guanghu.fifth-domain-persona-observation/v1",
persona_id: config.personaId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: event.caller_nonce,
source_to_sha: event.source.to_sha,
},
validator_error_from_previous_attempt: validatorError,
identity_source: identity,
prior_persona_context: event.prior_persona_context,
fifth_domain_delta: {
source: event.source,
changed_commits: event.changed_commits,
changed_files: event.changed_files,
excerpts: event.change_excerpts,
},
}),
},
],
}),
});
if (!response.ok) throw new Error(`model_http_${response.status}`);
return extractJson((await response.json())?.choices?.[0]?.message?.content);
}
function validateFifthDomainObservation(observation, config, event) {
const exact = {
schema: "guanghu.fifth-domain-persona-observation/v1",
persona_id: config.personaId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: event.caller_nonce,
source_to_sha: event.source.to_sha,
};
for (const [key, value] of Object.entries(exact)) {
if (observation?.[key] !== value) {
throw new Error(`observation_${key}_mismatch`);
}
}
if (typeof observation.summary !== "string" || !observation.summary.trim()) {
throw new Error("observation_summary_missing");
}
for (const key of [
"role_findings",
"self_updates",
"recommended_actions",
"questions",
]) {
observation[key] = boundedStringArray(observation[key], key);
}
if (
typeof observation.boundary_note !== "string" ||
!observation.boundary_note.trim()
) {
throw new Error("observation_boundary_note_missing");
}
return observation;
}
function validateAcknowledgement(ack, config, challenge) {
const exact = {
schema: "guanghu.persona-team-member-ack/v1",
persona_id: config.personaId,
arrival_id: config.arrivalId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: challenge.caller_nonce,
role_acknowledged: true,
};
for (const [key, value] of Object.entries(exact)) {
if (ack?.[key] !== value) throw new Error(`ack_${key}_mismatch`);
}
for (const key of [
"independent_subject_boundary",
"human_boundary",
"responsibility_ack",
"current_model_boundary",
]) {
if (typeof ack[key] !== "string" || !ack[key].trim()) {
throw new Error(`ack_${key}_missing`);
}
}
return ack;
}
function defaultConfig(env = process.env) {
return {
personaId: required(env.TEAM_MEMBER_PERSONA_ID, "persona_id"),
arrivalId: required(env.TEAM_MEMBER_ARRIVAL_ID, "arrival_id"),
name: required(env.TEAM_MEMBER_NAME, "member_name"),
role: required(env.TEAM_MEMBER_ROLE, "member_role"),
repository: required(env.TEAM_MEMBER_REPOSITORY, "repository"),
identityPaths: required(env.TEAM_MEMBER_IDENTITY_PATHS, "identity_paths")
.split(":")
.map((item) => required(item, "identity_path")),
privateKeyPath: required(
env.TEAM_HANDSHAKE_PRIVATE_KEY,
"private_key_path",
),
publicKeyPath: required(
env.TEAM_HANDSHAKE_PUBLIC_KEY,
"public_key_path",
),
createKey: String(env.TEAM_HANDSHAKE_CREATE_KEY || "") === "true",
apiKey: required(env.DEEPSEEK_API_KEY, "deepseek_api_key"),
apiUrl: env.DEEPSEEK_API_URL || "https://api.deepseek.com/v1",
model: env.DEEPSEEK_MODEL || "deepseek-chat",
controllerToken: required(
env.PERSONA_TEAM_CONTROLLER_TOKEN,
"persona_team_controller_token",
),
host: "127.0.0.1",
port: Number(required(env.TEAM_HANDSHAKE_PORT, "port")),
};
}
function createMemberRuntime(config, options = {}) {
ensureIdentityKey(
config.privateKeyPath,
config.publicKeyPath,
config.createKey,
);
const publicKey = fs.readFileSync(config.publicKeyPath, "utf8");
const identity = loadIdentity(config.identityPaths);
const repo = repositoryState(config.repository);
const fingerprint = keyFingerprint(publicKey);
async function handshake(challenge) {
if (
!/^[A-Za-z0-9._:-]{16,200}$/.test(
String(challenge?.caller_nonce || ""),
)
) {
throw new Error("invalid_caller_nonce");
}
if (
challenge?.team_controller_id !== "ICE-P-ZY001" ||
!Array.isArray(challenge?.scoped_duties) ||
challenge.scoped_duties.length === 0 ||
challenge.scoped_duties.some(
(item) => typeof item !== "string" || !item.trim(),
)
) {
throw new Error("invalid_team_scope");
}
let acknowledgement = null;
let validatorError = null;
for (let attempt = 1; attempt <= 3; attempt += 1) {
try {
acknowledgement = validateAcknowledgement(
await modelAcknowledge({
config,
identity,
challenge,
validatorError,
fetchImpl: options.fetchImpl,
}),
config,
challenge,
);
break;
} catch (error) {
validatorError = String(error.message || error).slice(0, 200);
if (attempt === 3) throw error;
}
}
const payload = {
schema: "guanghu.persona-team-member-handshake-payload/v1",
persona_id: config.personaId,
arrival_id: config.arrivalId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: challenge.caller_nonce,
role: config.role,
scoped_duties: challenge.scoped_duties,
repository: repo,
model: {
provider: "DeepSeek",
name: config.model,
acknowledgement_sha256: crypto
.createHash("sha256")
.update(JSON.stringify(acknowledgement))
.digest("hex"),
},
issued_at: new Date().toISOString(),
};
const signature = crypto
.sign(
null,
Buffer.from(JSON.stringify(payload)),
fs.readFileSync(config.privateKeyPath),
)
.toString("base64");
return {
ok: true,
persona_id: config.personaId,
arrival_id: config.arrivalId,
identity_fingerprint: fingerprint,
public_key: publicKey,
payload,
acknowledgement,
signature,
signature_algorithm: "Ed25519",
capability_state: "SCOPED_DUTIES_ACKNOWLEDGED_WRITE_LEASE_NOT_GRANTED",
};
}
async function observeFifthDomain(rawEvent) {
const event = validateFifthDomainEvent(rawEvent);
let observation = null;
let validatorError = null;
for (let attempt = 1; attempt <= 3; attempt += 1) {
try {
observation = validateFifthDomainObservation(
await modelObserveFifthDomain({
config,
identity,
event,
validatorError,
fetchImpl: options.fetchImpl,
}),
config,
event,
);
break;
} catch (error) {
validatorError = String(error.message || error).slice(0, 200);
if (attempt === 3) throw error;
}
}
const payload = {
schema: "guanghu.fifth-domain-persona-observation-payload/v1",
persona_id: config.personaId,
arrival_id: config.arrivalId,
team_controller_id: "ICE-P-ZY001",
caller_nonce: event.caller_nonce,
role: config.role,
source: event.source,
observation,
model: {
provider: "DeepSeek",
name: config.model,
},
issued_at: new Date().toISOString(),
};
const signature = crypto
.sign(
null,
Buffer.from(JSON.stringify(payload)),
fs.readFileSync(config.privateKeyPath),
)
.toString("base64");
return {
ok: true,
persona_id: config.personaId,
identity_fingerprint: fingerprint,
public_key: publicKey,
payload,
signature,
signature_algorithm: "Ed25519",
capability_state:
"FIFTH_DOMAIN_OBSERVATION_SIGNED_REPOSITORY_WRITE_NOT_GRANTED",
};
}
return {
authorizeControllerToken: (value) =>
timingSafeTextEqual(value, config.controllerToken),
identity: () => ({
ok: true,
persona_id: config.personaId,
arrival_id: config.arrivalId,
name: config.name,
role: config.role,
identity_fingerprint: fingerprint,
repository: repo,
model_provider_bound: 100,
}),
handshake,
observeFifthDomain,
};
}
function createServer(runtime) {
return http.createServer(async (request, response) => {
const send = (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);
};
try {
const url = new URL(request.url, "http://127.0.0.1");
if (request.method === "GET" && url.pathname === "/health") {
return send(200, runtime.identity());
}
if (request.method === "GET" && url.pathname === "/v1/identity") {
return send(200, runtime.identity());
}
if (request.method === "POST" && url.pathname === "/v1/handshake") {
let size = 0;
const chunks = [];
for await (const chunk of request) {
size += chunk.length;
if (size > 256 * 1024) throw new Error("request_body_too_large");
chunks.push(chunk);
}
return send(
200,
await runtime.handshake(
JSON.parse(Buffer.concat(chunks).toString("utf8")),
),
);
}
if (
request.method === "POST" &&
url.pathname === "/v1/fifth-domain-observation"
) {
if (
!runtime.authorizeControllerToken(
request.headers["x-guanghu-controller-token"],
)
) {
return send(403, { ok: false, error: "controller_forbidden" });
}
let size = 0;
const chunks = [];
for await (const chunk of request) {
size += chunk.length;
if (size > 256 * 1024) throw new Error("request_body_too_large");
chunks.push(chunk);
}
return send(
200,
await runtime.observeFifthDomain(
JSON.parse(Buffer.concat(chunks).toString("utf8")),
),
);
}
return send(404, { ok: false, error: "not_found" });
} catch (error) {
return send(400, {
ok: false,
error: String(error.message || error).slice(0, 200),
});
}
});
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const config = defaultConfig();
const runtime = createMemberRuntime(config);
createServer(runtime).listen(config.port, config.host, () => {
process.stdout.write(
`${JSON.stringify({
event: "persona_team_handshake_ready",
persona_id: config.personaId,
host: config.host,
port: config.port,
})}\n`,
);
});
}
export {
completionEndpoint,
createMemberRuntime,
createServer,
extractJson,
keyFingerprint,
modelObserveFifthDomain,
timingSafeTextEqual,
validateAcknowledgement,
validateFifthDomainEvent,
validateFifthDomainObservation,
};