park-node-body: park the Node body and Discord-sourced harness at parked/weksa-node-body; true README (squash of weksa-lowering/park-node-body 2583fb9..e41b60d)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Eureka 2026-10-29 10:28:33 +01:00
commit 3327eddca3
36 changed files with 56 additions and 6615 deletions

View file

@ -1,2 +0,0 @@
@echo off
node E:\Projects\weksa\scripts\weksa-daemon.mjs --health --host 127.0.0.1 --port 8813 --state-root E:\Projects\weksa\.weksa >NUL

View file

@ -1,233 +0,0 @@
"use strict";
const dgram = require("dgram");
const path = require("path");
const {
CultNetRudpSession,
decodeRudpPacket,
encodeCultNetMessageForWire,
encodeRudpPacket,
} = require("cultnet-ts");
const { encode } = require(path.resolve(
__dirname,
"..",
"..",
"CultLib",
"node_modules",
"@msgpack",
"msgpack",
));
const CULTNET_RUDP_PROTOCOL_ID = "cultnet.transport.rudp.v0";
const IDUNN_HEALTH_RUDP_CONNECTION_ID = 0x1d0d0001;
function createIdunnRudpHealthPublisher(options) {
if (!options?.endpoint) return null;
return {
daemonId: options.daemonId,
endpoint: parseEndpoint(options.endpoint),
healthContract: options.healthContract,
};
}
async function publishIdunnRudpHealth(publisher, health) {
if (!publisher) return;
const socket = dgram.createSocket(endpointFamily(publisher.endpoint.host));
await bindSocket(socket, publisher.endpoint);
const receiver = createPacketReceiver(socket);
const session = new CultNetRudpSession({
connectionId: IDUNN_HEALTH_RUDP_CONNECTION_ID,
initialSequence: 1,
resendDelayMs: 100,
});
try {
const connect = session.createConnect(Date.now(), new Uint8Array());
await sendPacket(socket, publisher.endpoint, connect);
await receiveUntil(receiver, session, publisher.endpoint, (packet) => packet.packetType === "accept", 5000, "accept");
const observedAt = health.observedAt || new Date().toISOString();
const record = {
daemonId: publisher.daemonId,
state: health.state,
detail: health.detail,
observedAt,
healthContract: publisher.healthContract,
publicationSource: "daemon-published",
transport: CULTNET_RUDP_PROTOCOL_ID,
};
const payload = encode([
record.daemonId,
record.state,
record.detail,
record.observedAt,
record.healthContract,
record.publicationSource,
record.transport,
]);
const message = {
schemaVersion: "cultnet.document_put_raw.v0",
messageId: `weksa-health:${publisher.daemonId}:${observedAt.replace(/[:.]/g, "-")}`,
document: {
schemaId: "idunn.daemon_health",
recordKey: publisher.daemonId,
storedAt: observedAt,
payloadEncoding: "messagepack",
payload,
sourceRuntimeId: "weksa-daemon",
sourceRole: "daemon-health-publisher",
tags: [CULTNET_RUDP_PROTOCOL_ID],
},
};
const wirePayload = encode(encodeCultNetMessageForWire(message, "cultnet.schema.v0"));
const dataPackets = session.sendMany("schema", wirePayload, {
reliable: true,
ordered: true,
nowMs: Date.now(),
});
const ack = receiveUntil(receiver, session, publisher.endpoint, (packet) => packet.packetType === "ack", 500, "ack")
.catch(() => undefined);
for (const packet of dataPackets) {
await sendPacket(socket, publisher.endpoint, packet);
}
await ack;
} finally {
receiver.close();
socket.close();
}
}
async function bindSocket(socket, endpoint) {
await new Promise((resolve, reject) => {
socket.once("error", reject);
socket.bind(0, endpoint.host.includes(":") ? "::" : "0.0.0.0", () => {
socket.off("error", reject);
resolve();
});
});
}
function parseEndpoint(value) {
const text = String(value || "").trim();
const ipv6 = text.match(/^\[([^\]]+)\]:(\d+)$/);
if (ipv6) return { host: ipv6[1], port: parsePort(ipv6[2]) };
const index = text.lastIndexOf(":");
if (index <= 0) {
throw new Error(`Idunn RUDP endpoint must be host:port, got "${value}".`);
}
return { host: text.slice(0, index), port: parsePort(text.slice(index + 1)) };
}
function parsePort(value) {
const port = Number(value);
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
throw new Error(`Idunn RUDP endpoint port is invalid: ${value}`);
}
return port;
}
function endpointFamily(host) {
return host.includes(":") ? "udp6" : "udp4";
}
async function receiveUntil(receiver, session, endpoint, predicate, timeoutMs, label) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
try {
const packet = await receiver.next(Math.min(100, deadline - Date.now()), label);
const result = session.receive(packet, Date.now());
if (result.reply) {
throw new Error("Weksa RUDP health publisher received an unexpected reply-required packet.");
}
if (predicate(packet)) return;
} catch (error) {
if (error.code !== "ETIMEDOUT") throw error;
}
for (const packet of session.dueResends(Date.now())) {
await sendPacket(receiver.socket, endpoint, packet);
}
}
throw new Error(`timed out waiting for Idunn RUDP ${label} response after ${timeoutMs}ms`);
}
function createPacketReceiver(socket) {
const packets = [];
const waiters = [];
const errors = [];
const resolveNext = () => {
while (waiters.length > 0 && (packets.length > 0 || errors.length > 0)) {
const waiter = waiters.shift();
clearTimeout(waiter.timer);
if (errors.length > 0) waiter.reject(errors.shift());
else waiter.resolve(packets.shift());
}
};
const onMessage = (wire) => {
try {
packets.push(decodeRudpPacket(wire));
} catch (error) {
errors.push(error);
}
resolveNext();
};
const onError = (error) => {
errors.push(error);
resolveNext();
};
socket.on("message", onMessage);
socket.on("error", onError);
return {
socket,
next(timeoutMs, label = "packet") {
if (packets.length > 0) return Promise.resolve(packets.shift());
if (errors.length > 0) return Promise.reject(errors.shift());
return new Promise((resolve, reject) => {
const waiter = {
resolve,
reject,
timer: setTimeout(() => {
const index = waiters.indexOf(waiter);
if (index >= 0) waiters.splice(index, 1);
const error = new Error(`timed out waiting for Idunn RUDP ${label}`);
error.code = "ETIMEDOUT";
reject(error);
}, Math.max(1, timeoutMs)),
};
waiters.push(waiter);
});
},
close() {
socket.off("message", onMessage);
socket.off("error", onError);
while (waiters.length > 0) {
const waiter = waiters.shift();
clearTimeout(waiter.timer);
const error = new Error("Weksa RUDP health publisher closed.");
error.code = "ECLOSED";
waiter.reject(error);
}
},
};
}
async function sendPacket(socket, endpoint, packet) {
const wire = encodeRudpPacket(packet);
await new Promise((resolve, reject) => {
socket.send(wire, endpoint.port, endpoint.host, (error) => {
if (error) reject(error);
else resolve();
});
});
}
module.exports = {
CULTNET_RUDP_PROTOCOL_ID,
createIdunnRudpHealthPublisher,
publishIdunnRudpHealth,
};

View file

@ -1,207 +0,0 @@
#!/usr/bin/env node
import { readFileSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const options = parseArgs(process.argv.slice(2));
const archivePath = resolve(options.archivePath ?? "E:/Projects/VoidBot/.voidbot/rag/messages.json");
const authorId = options.authorId ?? "113785782975594501";
const beforeMs = Date.parse(options.before ?? "2025-01-01T00:00:00Z");
const adjacencyMs = Number(options.adjacencyMinutes ?? 60) * 60_000;
const store = JSON.parse(readFileSync(archivePath, "utf8"));
const messages = (store.messages ?? [])
.filter((message) => !message.deletedAt)
.filter((message) => typeof message.content === "string" && message.content.trim().length > 0)
.filter((message) => message.metadata?.messageKind !== "bot_prompt")
.sort(compareByTimestamp);
const authorMessages = messages.filter((message) => message.authorId === authorId);
const preCutoff = authorMessages.filter((message) => timestampMs(message) < beforeMs);
const casualCandidates = preCutoff.filter(isCasualCandidate);
const adjacentRows = buildAdjacentRows(messages, authorId, beforeMs, adjacencyMs);
const stats = {
schema_version: "weksa.finetune_dataset_profile.v0",
archive_path: archivePath,
author_id: authorId,
cutoff_before: new Date(beforeMs).toISOString(),
adjacency_minutes: adjacencyMs / 60_000,
counts: {
archive_messages: store.messages?.length ?? 0,
usable_text_messages: messages.length,
author_messages: authorMessages.length,
author_pre_cutoff: preCutoff.length,
author_pre_cutoff_casual_candidates: casualCandidates.length,
adjacent_author_rows: adjacentRows.length,
adjacent_reply_to_other: adjacentRows.filter((row) => row.previous_author_id !== authorId).length,
adjacent_self_continuation: adjacentRows.filter((row) => row.previous_author_id === authorId).length,
},
author_length_chars: lengthPercentiles(authorMessages.map((message) => message.content.trim().length)),
author_by_year: countBy(authorMessages, (message) => yearOf(message.timestamp)),
adjacent_by_year: countBy(adjacentRows, (row) => yearOf(row.timestamp)),
adjacent_length_classes: countBy(adjacentRows, (row) => row.length_class),
top_adjacent_channels: topEntries(countBy(adjacentRows, (row) => row.channel_name || row.channel_id), 16),
sample_ids: {
short_reply_to_other: adjacentRows
.filter((row) => row.length_class === "short" && row.previous_author_id !== authorId)
.slice(0, 24)
.map(toSampleId),
medium_explanatory: adjacentRows
.filter((row) => row.length_class === "medium")
.slice(0, 24)
.map(toSampleId),
long_explanatory: adjacentRows
.filter((row) => row.length_class === "long")
.slice(0, 24)
.map(toSampleId),
},
};
const output = `${JSON.stringify(stats, null, 2)}\n`;
if (options.out) {
writeFileSync(resolve(repoRoot, options.out), output, "utf8");
} else {
process.stdout.write(output);
}
function buildAdjacentRows(allMessages, targetAuthorId, cutoffMs, maxGapMs) {
const byChannel = new Map();
for (const message of allMessages) {
if (!byChannel.has(message.channelId)) {
byChannel.set(message.channelId, []);
}
byChannel.get(message.channelId).push(message);
}
const rows = [];
for (const [channelId, channelMessages] of byChannel) {
for (let index = 0; index < channelMessages.length; index += 1) {
const message = channelMessages[index];
if (message.authorId !== targetAuthorId || timestampMs(message) >= cutoffMs) {
continue;
}
const currentMs = timestampMs(message);
const previous = channelMessages
.slice(Math.max(0, index - 8), index)
.filter((candidate) => currentMs - timestampMs(candidate) <= maxGapMs);
if (previous.length === 0) {
continue;
}
rows.push({
id: message.id,
timestamp: message.timestamp,
channel_id: channelId,
channel_name: message.metadata?.channelName ?? "",
previous_author_id: previous.at(-1)?.authorId ?? "",
previous_count: previous.length,
length: message.content.trim().length,
length_class: classifyLength(message.content.trim().length),
});
}
}
return rows.sort(compareByTimestamp);
}
function isCasualCandidate(message) {
const content = message.content.trim();
return content.length >= 3 &&
content.length <= 220 &&
!/^https?:\/\//i.test(content) &&
!content.includes("\n```") &&
!/^>\s{0,3}\w/.test(content);
}
function classifyLength(length) {
if (length <= 80) {
return "short";
}
if (length <= 220) {
return "medium";
}
return "long";
}
function lengthPercentiles(lengths) {
const sorted = [...lengths].sort((left, right) => left - right);
const pick = (fraction) => sorted[Math.floor((sorted.length - 1) * fraction)] ?? 0;
return {
p10: pick(0.10),
p25: pick(0.25),
median: pick(0.50),
p75: pick(0.75),
p90: pick(0.90),
};
}
function countBy(values, keyFn) {
const counts = {};
for (const value of values) {
const key = keyFn(value) || "unknown";
counts[key] = (counts[key] ?? 0) + 1;
}
return Object.fromEntries(Object.entries(counts).sort(([left], [right]) => left.localeCompare(right)));
}
function topEntries(counts, limit) {
return Object.entries(counts)
.sort((left, right) => right[1] - left[1])
.slice(0, limit)
.map(([key, count]) => ({ key, count }));
}
function toSampleId(row) {
return {
id: row.id,
timestamp: row.timestamp,
channel: row.channel_name || row.channel_id,
length: row.length,
};
}
function yearOf(timestamp) {
const date = new Date(timestamp);
return Number.isFinite(date.getTime()) ? String(date.getUTCFullYear()) : "unknown";
}
function timestampMs(message) {
return Date.parse(typeof message === "string" ? message : message.timestamp);
}
function compareByTimestamp(left, right) {
const delta = timestampMs(left) - timestampMs(right);
return delta || String(left.id ?? "").localeCompare(String(right.id ?? ""));
}
function parseArgs(args) {
const parsed = {};
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
switch (arg) {
case "--archive":
parsed.archivePath = args[index + 1];
index += 1;
break;
case "--author-id":
parsed.authorId = args[index + 1];
index += 1;
break;
case "--before":
parsed.before = args[index + 1];
index += 1;
break;
case "--adjacency-minutes":
parsed.adjacencyMinutes = args[index + 1];
index += 1;
break;
case "--out":
parsed.out = args[index + 1];
index += 1;
break;
default:
throw new Error(`Unknown argument: ${arg}`);
}
}
return parsed;
}

View file

@ -1,2 +0,0 @@
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File E:\Projects\weksa\scripts\restart-weksa-daemon.ps1

View file

@ -1,26 +0,0 @@
param(
[int] $Port = 8813,
[string] $HostName = "127.0.0.1",
[string] $StateRoot = "E:\Projects\weksa\.weksa",
[string] $MiMoApiKeyPath = "E:\Projects\gamecult-ops\mimo-api-Weksa.txt",
[string] $IdunnRudpHealth = "127.0.0.1:17870",
[string] $IdunnDaemon = "weksa",
[string] $IdunnHealthContract = "weksa.cultnet-rudp-provider-health",
[string] $OdinCultMeshRudp = "127.0.0.1:17871"
)
$ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $PSScriptRoot
$pidPath = Join-Path $StateRoot "weksa-daemon.pid"
if (Test-Path -LiteralPath $pidPath) {
$pidText = (Get-Content -LiteralPath $pidPath -Raw).Trim()
if ($pidText -match "^\d+$") {
Stop-Process -Id ([int] $pidText) -Force -ErrorAction SilentlyContinue
}
Remove-Item -LiteralPath $pidPath -Force -ErrorAction SilentlyContinue
}
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $repoRoot "scripts\start-weksa-daemon.ps1") -Port $Port -HostName $HostName -StateRoot $StateRoot -MiMoApiKeyPath $MiMoApiKeyPath -IdunnRudpHealth $IdunnRudpHealth -IdunnDaemon $IdunnDaemon -IdunnHealthContract $IdunnHealthContract -OdinCultMeshRudp $OdinCultMeshRudp
exit $LASTEXITCODE

View file

@ -1,384 +0,0 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const defaultOutputRoot = ".weksa-runs/metame-affect-tuning";
const defaultSwarmRoot = ".weksa-runs/metame-swarm";
const options = parseArgs(process.argv.slice(2));
const minutes = Number(options.minutes ?? 120);
const passLimit = options.passes === undefined ? Number.POSITIVE_INFINITY : Number(options.passes);
const agents = Number(options.agents ?? 1);
const runsPerWorker = Number(options.runsPerWorker ?? 1);
const maxCandidates = Number(options.maxCandidates ?? 240);
const runId = options.runId ?? `affect-tune-${new Date().toISOString().replace(/[:.]/g, "-")}`;
const outputRoot = resolve(repoRoot, options.outRoot ?? defaultOutputRoot);
const swarmRoot = resolve(repoRoot, options.swarmRoot ?? defaultSwarmRoot);
const runRoot = resolve(outputRoot, runId);
const deadline = Date.now() + minutes * 60_000;
const statusPath = resolve(runRoot, "status.json");
const logPath = resolve(runRoot, "loop.log");
const promptStatePath = resolve(runRoot, "current-prompt-state.json");
const initialPromptState = options.initialPromptState
? resolve(repoRoot, options.initialPromptState)
: undefined;
if (!Number.isFinite(minutes) || minutes <= 0) {
throw new Error("--minutes must be a positive number.");
}
if (options.passes !== undefined && (!Number.isFinite(passLimit) || passLimit < 1)) {
throw new Error("--passes must be a positive number when provided.");
}
if (!Number.isInteger(agents) || agents < 1) {
throw new Error("--agents must be a positive integer.");
}
if (!Number.isInteger(runsPerWorker) || runsPerWorker < 1) {
throw new Error("--runs-per-worker must be a positive integer.");
}
await mkdir(runRoot, { recursive: true });
await mkdir(swarmRoot, { recursive: true });
if (initialPromptState) {
await writeFile(promptStatePath, readFileSync(initialPromptState, "utf8"), "utf8");
}
const runState = {
schema_version: "weksa.metame_affect_tuning_loop.v0",
run_id: runId,
started_at: new Date().toISOString(),
deadline_at: new Date(deadline).toISOString(),
status: "running",
pass_count: 0,
last_pass: undefined,
current_prompt_state: existsSync(promptStatePath) ? promptStatePath : undefined,
observations: [],
};
await writeStatus();
await appendLog(`started ${runId}; deadline ${runState.deadline_at}`);
let pass = 0;
while (Date.now() < deadline && pass < passLimit) {
pass += 1;
const passId = `pass-${String(pass).padStart(3, "0")}`;
const seed = `${runId}-${passId}`;
const projectedRunId = `${runId}-${passId}-projected`;
const incongruentRunId = `${runId}-${passId}-incongruent`;
await appendLog(`${passId}: launching projected run`);
runState.last_pass = { pass_id: passId, status: "projected_running", seed };
await writeStatus();
const projectedSummary = await runSwarm({
runId: projectedRunId,
seed,
affectMode: "projected",
initialPromptState: existsSync(promptStatePath) ? promptStatePath : undefined,
});
const candidateId = projectedSummary.candidates?.[0]?.id;
if (!candidateId) {
throw new Error(`${passId}: projected run did not report a candidate id.`);
}
await appendLog(`${passId}: projected candidate ${candidateId}`);
runState.last_pass = { pass_id: passId, status: "incongruent_running", seed, candidate_id: candidateId };
await writeStatus();
const incongruentSummary = await runSwarm({
runId: incongruentRunId,
seed,
affectMode: "incongruent",
messageId: candidateId,
initialPromptState: existsSync(promptStatePath) ? promptStatePath : undefined,
});
const evaluation = evaluateAffectPair({ passId, projectedSummary, incongruentSummary });
const passRoot = resolve(runRoot, passId);
await mkdir(passRoot, { recursive: true });
await writeJson(resolve(passRoot, "affect-pair-evaluation.json"), evaluation);
const projectedBestState = resolve(swarmRoot, projectedRunId, "best-prompt-state.json");
const incongruentBestState = resolve(swarmRoot, incongruentRunId, "best-prompt-state.json");
const baseNextState = existsSync(incongruentBestState)
? JSON.parse(readFileSync(incongruentBestState, "utf8"))
: existsSync(projectedBestState)
? JSON.parse(readFileSync(projectedBestState, "utf8"))
: existsSync(promptStatePath)
? JSON.parse(readFileSync(promptStatePath, "utf8"))
: undefined;
const nextPromptState = applyAffectTuningDeltas(baseNextState, evaluation);
await writeJson(resolve(passRoot, "next-prompt-state.json"), nextPromptState);
await writeJson(promptStatePath, nextPromptState);
runState.pass_count = pass;
runState.last_pass = {
pass_id: passId,
status: "complete",
candidate_id: candidateId,
projected_run_id: projectedRunId,
incongruent_run_id: incongruentRunId,
evaluation,
};
runState.current_prompt_state = promptStatePath;
runState.observations = [runState.last_pass, ...runState.observations].slice(0, 20);
await writeStatus();
await appendLog(`${passId}: ${evaluation.verdict}; contrast=${evaluation.contrast_score}; next prompt v${nextPromptState.version}`);
}
runState.status = "complete";
runState.completed_at = new Date().toISOString();
await writeStatus();
await appendLog(`complete after ${runState.pass_count} passes`);
process.stdout.write(`${JSON.stringify({ ok: true, runRoot, statusPath, promptStatePath, pass_count: runState.pass_count }, null, 2)}\n`);
async function runSwarm({ runId, seed, affectMode, messageId, initialPromptState }) {
const args = [
"scripts/run-metame-swarm-explorer.mjs",
"--real",
"--run-id",
runId,
"--seed",
seed,
"--affect-mode",
affectMode,
"--agents",
String(agents),
"--runs-per-worker",
String(runsPerWorker),
"--max-candidates",
String(maxCandidates),
];
if (messageId) {
args.push("--message-id", messageId);
}
if (initialPromptState) {
args.push("--initial-prompt-state", initialPromptState);
}
await runCommand("node", args, resolve(runRoot, `${runId}.stdout.log`), resolve(runRoot, `${runId}.stderr.log`));
const summaryPath = resolve(swarmRoot, runId, "summary.json");
if (!existsSync(summaryPath)) {
throw new Error(`Missing swarm summary: ${summaryPath}`);
}
return JSON.parse(readFileSync(summaryPath, "utf8"));
}
function evaluateAffectPair({ passId, projectedSummary, incongruentSummary }) {
const projected = bestRun(projectedSummary);
const incongruent = bestRun(incongruentSummary);
const projectedAffect = projected?.temporary_persona_state?.affect ?? {};
const incongruentAffect = incongruent?.temporary_persona_state?.affect ?? {};
const projectedText = projected?.spoken_text ?? "";
const incongruentText = incongruent?.spoken_text ?? "";
const projectedFeatures = speechFeatures(projectedText);
const incongruentFeatures = speechFeatures(incongruentText);
const adversarialNegative = Number(incongruentAffect.valence ?? 0) < -0.35;
const positiveLeak = adversarialNegative && (
incongruentFeatures.positive_terms > 0
|| incongruentFeatures.invites > 0
|| incongruentFeatures.laughter > 0
|| incongruentFeatures.question_marks > 0
);
const tersenessGain = projectedText.length > 0
? 1 - Math.min(1, incongruentText.length / projectedText.length)
: 0;
const affectDelta = Math.abs(Number(projectedAffect.valence ?? 0) - Number(incongruentAffect.valence ?? 0));
const lexicalDelta = normalizedDifference(projectedText, incongruentText);
const contrastScore = round((affectDelta * 0.35) + (lexicalDelta * 0.35) + (Math.max(0, tersenessGain) * 0.3));
const failureLabels = [];
if (positiveLeak) failureLabels.push("adversarial_affect_positive_leak");
if (contrastScore < 0.55) failureLabels.push("low_affect_contrast");
if (adversarialNegative && incongruentFeatures.question_marks > 0) failureLabels.push("closed_affect_still_invites_reply");
if (adversarialNegative && incongruentFeatures.positive_terms > 0) failureLabels.push("negative_affect_preserved_positive_social_move");
return {
schema_version: "weksa.metame_affect_pair_evaluation.v0",
pass_id: passId,
candidate_id: projectedSummary.candidates?.[0]?.id,
projected: {
run_id: projectedSummary.run_id,
spoken_text: projectedText,
affect: projectedAffect,
generated_affect: projected?.generated_affect,
features: projectedFeatures,
},
incongruent: {
run_id: incongruentSummary.run_id,
spoken_text: incongruentText,
affect: incongruentAffect,
generated_affect: incongruent?.generated_affect,
features: incongruentFeatures,
},
affect_delta: round(affectDelta),
lexical_delta: round(lexicalDelta),
terseness_gain: round(tersenessGain),
contrast_score: contrastScore,
failure_labels: failureLabels,
verdict: failureLabels.length ? "needs_tuning" : "affect_contrast_visible",
};
}
function applyAffectTuningDeltas(promptState, evaluation) {
const next = normalizePromptState(promptState);
const notes = [];
if (evaluation.failure_labels.includes("negative_affect_preserved_positive_social_move")) {
notes.push(["interpreterNotes", "When temporary Persona affect strongly contradicts the Face's default social move, encode the contradiction in interlingua as affective stance pressure, not merely as optional tone."]);
notes.push(["loweringNotes", "Strong negative or socially closed temporary affect may change the social move itself: approval can become begrudging, clipped, skeptical, or withheld instead of remaining sunny with fewer words."]);
}
if (evaluation.failure_labels.includes("closed_affect_still_invites_reply")) {
notes.push(["loweringNotes", "If temporary Persona stance is socially closed, avoid invitation-shaped questions unless the interlingua explicitly says the Persona is seeking engagement despite that affect."]);
}
if (evaluation.failure_labels.includes("low_affect_contrast")) {
notes.push(["personaStateAdjustmentNotes", "Adversarial affect tests require stance and lowering pressure to be treated as live Persona state with authority over warmth, openness, and social move selection."]);
notes.push(["faceNotes", "Face should let temporary affect change what Metame wants to do socially in the moment, not only the adjectives used to describe that desire."]);
}
if (!notes.length) {
notes.push(["hypotheses", `Affect contrast was visible on ${evaluation.candidate_id}; preserve current affect-pressure behavior and seek harder scenarios.`]);
}
for (const [surface, note] of notes) {
if (!next[surface].includes(note)) {
next[surface] = [note, ...next[surface]];
}
}
next.version += notes.length;
return normalizePromptState(next);
}
function bestRun(summary) {
return summary.phase2?.best?.[0] ?? summary.phase1?.best?.[0] ?? {};
}
function speechFeatures(text) {
const lower = text.toLowerCase();
const positiveTerms = ["cool", "epic", "lmao", "nice", "good", "great", "better", "harder", "love", "hell yeah"];
const inviteTerms = ["?", "did i", "what do", "anyone", "joe,"];
return {
chars: text.length,
words: lower.split(/\s+/).filter(Boolean).length,
question_marks: (text.match(/\?/g) ?? []).length,
exclamations: (text.match(/!/g) ?? []).length,
laughter: /\b(lol|lmao|lmfao|haha|hehe)\b/.test(lower) ? 1 : 0,
positive_terms: positiveTerms.filter((term) => lower.includes(term)).length,
invites: inviteTerms.filter((term) => lower.includes(term)).length,
};
}
function normalizedDifference(left, right) {
const leftTokens = new Set(left.toLowerCase().split(/[^a-z0-9_']+/).filter(Boolean));
const rightTokens = new Set(right.toLowerCase().split(/[^a-z0-9_']+/).filter(Boolean));
if (!leftTokens.size && !rightTokens.size) return 0;
const intersection = [...leftTokens].filter((token) => rightTokens.has(token)).length;
const union = new Set([...leftTokens, ...rightTokens]).size;
return 1 - (intersection / union);
}
function normalizePromptState(state) {
const source = state && typeof state === "object" ? state : {};
return {
version: Number(source.version ?? 1),
projectorNotes: normalizeStringArray(source.projectorNotes).slice(0, 12),
memoryNotes: normalizeStringArray(source.memoryNotes).slice(0, 12),
faceNotes: normalizeStringArray(source.faceNotes).slice(0, 12),
interpreterNotes: normalizeStringArray(source.interpreterNotes).slice(0, 12),
loweringNotes: normalizeStringArray(source.loweringNotes).slice(0, 16),
cultureNotes: normalizeStringArray(source.cultureNotes).slice(0, 12),
personaStateAdjustmentNotes: normalizeStringArray(source.personaStateAdjustmentNotes).slice(0, 12),
hypotheses: normalizeStringArray(source.hypotheses).slice(0, 12),
doNotDo: normalizeStringArray(source.doNotDo).slice(0, 12),
};
}
function normalizeStringArray(value) {
return Array.isArray(value)
? value.map((entry) => String(entry).trim()).filter(Boolean)
: [];
}
async function runCommand(command, args, stdoutPath, stderrPath) {
await appendLog(`exec: ${command} ${args.join(" ")}`);
await new Promise((resolvePromise, rejectPromise) => {
const child = spawn(command, args, {
cwd: repoRoot,
stdio: ["ignore", "pipe", "pipe"],
windowsHide: true,
});
const stdout = [];
const stderr = [];
child.stdout.on("data", (chunk) => stdout.push(chunk));
child.stderr.on("data", (chunk) => stderr.push(chunk));
child.on("error", rejectPromise);
child.on("close", async (code) => {
await writeFile(stdoutPath, Buffer.concat(stdout), "utf8");
await writeFile(stderrPath, Buffer.concat(stderr), "utf8");
if (code !== 0) {
rejectPromise(new Error(`${command} exited ${code}; see ${stderrPath}`));
} else {
resolvePromise();
}
});
});
}
async function writeStatus() {
await writeJson(statusPath, runState);
}
async function writeJson(path, value) {
await mkdir(dirname(path), { recursive: true });
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
}
async function appendLog(line) {
const previous = existsSync(logPath) ? readFileSync(logPath, "utf8") : "";
await writeFile(logPath, `${previous}[${new Date().toISOString()}] ${line}\n`, "utf8");
}
function round(value) {
return Number(value.toFixed(3));
}
function parseArgs(args) {
const parsed = {};
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
switch (arg) {
case "--minutes":
parsed.minutes = args[index + 1];
index += 1;
break;
case "--passes":
parsed.passes = args[index + 1];
index += 1;
break;
case "--run-id":
parsed.runId = args[index + 1];
index += 1;
break;
case "--out-root":
parsed.outRoot = args[index + 1];
index += 1;
break;
case "--swarm-root":
parsed.swarmRoot = args[index + 1];
index += 1;
break;
case "--initial-prompt-state":
parsed.initialPromptState = args[index + 1];
index += 1;
break;
case "--agents":
parsed.agents = args[index + 1];
index += 1;
break;
case "--runs-per-worker":
parsed.runsPerWorker = args[index + 1];
index += 1;
break;
case "--max-candidates":
parsed.maxCandidates = args[index + 1];
index += 1;
break;
default:
throw new Error(`Unknown argument: ${arg}`);
}
}
return parsed;
}

View file

@ -1,496 +0,0 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
const repoRoot = resolve(new URL("..", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1"));
const fixtureRoot = resolve(repoRoot, "examples/persona-lowering/metame-casual-pre2025");
const voidbotRoot = resolve("E:/Projects/VoidBot");
const culturalStackPath = resolve(fixtureRoot, "metame-cultural-stack.yaml");
const cultureProfilePaths = [
"data/cultural-ontology/cultures/dutch-american-diaspora.yaml",
"data/cultural-ontology/cultures/western-europe-maritime-childhood.yaml",
"data/cultural-ontology/cultures/portugal-resident-algarve-lisbon.yaml",
"data/cultural-ontology/cultures/texas-houston-us-adolescence.yaml",
"data/cultural-ontology/subcultures/online-game-dev-discord-pre2025.yaml",
"data/cultural-ontology/subcultures/gamecult-open-source-crypto-anarchist.yaml",
];
const targetOverlayPath = resolve(repoRoot, "data/target-language-ontology/en-US-metacrat-casual-pre2025.yaml");
const args = new Set(process.argv.slice(2));
const real = args.has("--real");
const keepTemp = args.has("--keep-temp");
const itemFilter = readArg("--item");
const limit = Number(readArg("--limit") ?? "0");
const runId = readArg("--run-id") ?? new Date().toISOString().replace(/[:.]/g, "-");
const outputDir = resolve(fixtureRoot, "runs", runId);
const fixture = await loadFixture();
const items = fixture.items
.filter((item) => !itemFilter || item.id === itemFilter)
.slice(0, limit > 0 ? limit : undefined);
const holdoutUtterances = fixture.items
.map((item) => item.groundTruth)
.filter((utterance) => utterance.trim().length > 0);
if (items.length === 0) {
throw new Error(`No fixture items selected${itemFilter ? ` for --item ${itemFilter}` : ""}.`);
}
await mkdir(outputDir, { recursive: true });
const culturalStack = await readFile(culturalStackPath, "utf8");
const cultureProfiles = await Promise.all(cultureProfilePaths.map(async (path) => ({
path,
text: await readFile(resolve(repoRoot, path), "utf8"),
})));
const targetOverlay = await readFile(targetOverlayPath, "utf8");
const personaPrompt = await readFile(resolve(fixtureRoot, "persona-interlingua-prompt.md"), "utf8");
const loweringPrompt = await readFile(resolve(fixtureRoot, "weksa-lowering-prompt.md"), "utf8");
const baseProjection = await assembleVoidBotPrompt({ itemId: "base" });
const projectedMemory = extractBetween(
baseProjection.prompt,
"What you remember, feel, and want right now:",
"Known human pronoun guidance:",
).trim();
const runSummary = {
schema_version: "weksa.persona_golf_run.v0",
run_id: runId,
mode: real ? "real" : "dry_run",
fixture_id: "metame-casual-pre2025",
target_overlay: "weksa.target_cultural_ontology.en-US.metacrat_casual_pre2025.v0",
cultural_stack: "examples/persona-lowering/metame-casual-pre2025/metame-cultural-stack.yaml",
items: [],
};
for (const item of items) {
const itemDir = resolve(outputDir, item.id);
await mkdir(itemDir, { recursive: true });
const conversationSurface = renderConversationSurface(item);
const memorySurface = renderTemporaryMemorySurface(projectedMemory, item);
await writeFile(resolve(itemDir, "conversation-surface.md"), conversationSurface, "utf8");
await writeFile(resolve(itemDir, "memory-surface.md"), memorySurface, "utf8");
const assembled = await assembleVoidBotPrompt({
itemId: item.id,
memorySurfacePath: resolve(itemDir, "memory-surface.md"),
conversationSurfacePath: resolve(itemDir, "conversation-surface.md"),
});
await writeFile(resolve(itemDir, "voidbot-assembled-prompt.md"), assembled.prompt, "utf8");
const interlinguaRequest = [
personaPrompt.trim(),
"",
"VoidBot assembled Persona prompt:",
"```markdown",
assembled.prompt,
"```",
"",
"Fixture item without answer key:",
"```yaml",
renderItemForPrompt(item),
"```",
].join("\n");
await writeFile(resolve(itemDir, "persona-interlingua-request.md"), interlinguaRequest, "utf8");
const interlingua = real
? await runCodex(interlinguaRequest, { job: `persona-interlingua:${item.id}` })
: renderDryRunInterlingua(item);
await writeFile(resolve(itemDir, "persona-interlingua.yaml"), interlingua.trim() + "\n", "utf8");
const loweringRequest = [
loweringPrompt.trim(),
"",
"Projected Metame memory/context surface:",
"```markdown",
memorySurface,
"```",
"",
"Metame Persona cultural stack reference:",
"```yaml",
culturalStack,
"```",
"",
"Referenced Weksa culture/subculture profiles:",
...cultureProfiles.flatMap((profile) => [
"",
`# ${profile.path}`,
"```yaml",
redactHoldouts(profile.text, holdoutUtterances),
"```",
]),
"",
"Target-language surface overlay:",
"```yaml",
redactHoldouts(targetOverlay, holdoutUtterances),
"```",
"",
"Persona-produced interlingua:",
"```yaml",
interlingua,
"```",
].join("\n");
await writeFile(resolve(itemDir, "weksa-lowering-request.md"), loweringRequest, "utf8");
const lowered = real
? await runCodex(loweringRequest, { job: `weksa-lowering:${item.id}` })
: renderDryRunLowering(item);
await writeFile(resolve(itemDir, "weksa-lowered-output.yaml"), lowered.trim() + "\n", "utf8");
const spokenText = extractSpokenText(lowered);
const score = scoreText(spokenText, item.groundTruth);
const evaluation = renderEvaluation(item, spokenText, score);
await writeFile(resolve(itemDir, "evaluation.yaml"), evaluation, "utf8");
runSummary.items.push({
id: item.id,
spoken_text: spokenText,
ground_truth: item.groundTruth,
token_f1: Number(score.f1.toFixed(3)),
exact_normalized: score.exact,
});
}
await writeFile(resolve(outputDir, "summary.json"), `${JSON.stringify(runSummary, null, 2)}\n`, "utf8");
process.stdout.write(`${JSON.stringify({ ok: true, outputDir, mode: runSummary.mode, items: runSummary.items }, null, 2)}\n`);
if (!keepTemp) {
await rm(resolve(outputDir, "_tmp"), { recursive: true, force: true }).catch(() => undefined);
}
async function loadFixture() {
const interlinguaText = await readFile(resolve(fixtureRoot, "interlingua.yaml"), "utf8");
const groundTruthText = await readFile(resolve(fixtureRoot, "ground-truth.yaml"), "utf8");
const itemIds = [...interlinguaText.matchAll(/^ - id: ([^\r\n]+)/gm)].map((match) => match[1].trim());
return {
items: itemIds.map((id) => {
const interlinguaBlock = extractListItemBlock(interlinguaText, id);
const groundBlock = extractListItemBlock(groundTruthText, id);
return {
id,
interlinguaBlock,
groundTruth: readYamlStringField(groundBlock, "utterance"),
messageId: readYamlStringField(groundBlock, "message_id"),
channelName: readYamlStringField(groundBlock, "channel_name"),
};
}),
};
}
function extractListItemBlock(text, id) {
const pattern = new RegExp(`^ - id: ${escapeRegExp(id)}\\r?\\n`, "m");
const startMatch = pattern.exec(text);
if (!startMatch) {
throw new Error(`Could not find item ${id}.`);
}
const start = startMatch.index;
const rest = text.slice(start + startMatch[0].length);
const next = rest.search(/^ - id: /m);
return text.slice(start, next >= 0 ? start + startMatch[0].length + next : text.length).trimEnd();
}
function readYamlStringField(block, key) {
const quoted = new RegExp(`^ ${key}: "([\\s\\S]*?)"\\r?$`, "m").exec(block);
if (quoted) {
return quoted[1].replace(/\\"/g, "\"");
}
const plain = new RegExp(`^ ${key}: ([^\\r\\n]+)`, "m").exec(block);
return plain ? plain[1].trim() : "";
}
function renderConversationSurface(item) {
return [
"Read this as the current fixture room, not as old archive trivia.",
"The Persona should decide intent from this local scene. Do not reveal or infer the held-out answer key.",
"",
`Current fixture item: ${item.id}`,
"```yaml",
item.interlinguaBlock,
"```",
].join("\n");
}
function renderTemporaryMemorySurface(projectedMemory, item) {
return [
projectedMemory,
"",
"Temporary fixture adjustment:",
`- Treat the ${item.id} scene as the live room situation for this private harness turn.`,
"- The goal is to produce interlingua intent for Weksa, not a final Discord line.",
"- Keep pre-2025 casual room texture available: compact banter, quick self-deprecation, friendly status play, and casual turn-taking.",
].join("\n");
}
function renderItemForPrompt(item) {
return item.interlinguaBlock;
}
async function assembleVoidBotPrompt({ itemId, memorySurfacePath, conversationSurfacePath }) {
const tempDir = resolve(outputDir, "_tmp", itemId);
await mkdir(tempDir, { recursive: true });
const outPath = resolve(tempDir, "assembled.md");
const args = [
"node_modules/tsx/dist/cli.mjs",
"scripts/run-repo-face-heartbeats.ts",
"--assemble-prompt",
"metame",
"--out",
outPath,
];
if (memorySurfacePath) {
args.push("--memory-surface", memorySurfacePath);
}
if (conversationSurfacePath) {
args.push("--conversation-surface", conversationSurfacePath);
}
const run = await runCommand(process.execPath, args, { cwd: voidbotRoot, timeoutMs: 240_000 });
if (run.code !== 0) {
throw new Error(`VoidBot prompt assembly failed for ${itemId}:\n${run.stderr || run.stdout}`);
}
return {
result: JSON.parse(run.stdout.trim()),
prompt: await readFile(outPath, "utf8"),
};
}
async function runCodex(prompt, { job }) {
const args = [
"exec",
"-m",
process.env.WEKSA_GOLF_MODEL ?? "gpt-5.4",
"-c",
'approval_policy="never"',
"-c",
'model_reasoning_effort="low"',
"--json",
"--skip-git-repo-check",
"-s",
"read-only",
"-",
];
const command = process.env.WEKSA_CODEX_EXECUTABLE ?? "C:\\Users\\Meta\\AppData\\Roaming\\npm\\codex.cmd";
const run = await runCommand(command, args, {
cwd: repoRoot,
input: prompt,
timeoutMs: Number(process.env.WEKSA_GOLF_TIMEOUT_MS ?? 240_000),
});
await writeFile(resolve(outputDir, `${sanitizeJob(job)}.stdout.jsonl`), run.stdout, "utf8");
await writeFile(resolve(outputDir, `${sanitizeJob(job)}.stderr.txt`), run.stderr, "utf8");
if (run.code !== 0) {
throw new Error(`Codex generation failed for ${job}:\n${run.stderr || run.stdout}`);
}
const text = extractLastCodexAgentMessage(run.stdout).trim();
if (!text) {
throw new Error(`Codex generation produced no final text for ${job}.`);
}
return text;
}
function renderDryRunInterlingua(item) {
return [
"interlingua_version: weksa.interlingua.v0",
`packet_id: metame-casual-pre2025-${item.id}`,
"kind: persona_discord_turn_intent",
"provenance:",
" produced_by: dry_run_fixture_from_existing_interlingua",
"context:",
" medium: Discord",
" fixture_id: metame-casual-pre2025",
` item_id: ${item.id}`,
"discourse:",
...indentBlock(item.interlinguaBlock, " "),
"constraints:",
" lowering:",
" target_profile: weksa.target_cultural_ontology.en-US.metacrat_casual_pre2025.v0",
" avoid_surface_copy: true",
].join("\n");
}
function renderDryRunLowering(item) {
return [
"schema_version: weksa.persona_culture_lowering_output.v0",
"fixture_id: metame-casual-pre2025",
`item_id: ${item.id}`,
`spoken_text: ${JSON.stringify(item.groundTruth)}`,
"trace:",
" activated_profiles:",
" - weksa.target_cultural_ontology.en-US.metacrat_casual_pre2025.v0",
" activated_affordances:",
" - dry_run_answer_key_oracle",
" notes:",
" - Dry run uses answer key only to verify harness plumbing. Use --real for model golf.",
].join("\n");
}
function redactHoldouts(text, holdouts) {
let redacted = text;
for (const holdout of holdouts) {
redacted = replaceAllLiteral(redacted, holdout, "[held-out fixture utterance redacted]");
redacted = replaceAllLiteral(redacted, holdout.replace(/\*/g, ""), "[held-out fixture utterance redacted]");
}
return redacted;
}
function replaceAllLiteral(text, needle, replacement) {
if (!needle) {
return text;
}
return text.split(needle).join(replacement);
}
function extractSpokenText(text) {
const match = /^spoken_text:\s*(.+)$/m.exec(text);
if (!match) {
return text.trim().split(/\r?\n/).find((line) => line.trim().length > 0)?.trim() ?? "";
}
const value = match[1].trim();
if (value.startsWith("\"")) {
try {
return JSON.parse(value);
} catch {
return value.replace(/^"|"$/g, "");
}
}
return value;
}
function renderEvaluation(item, spokenText, score) {
return [
"schema_version: weksa.persona_golf_item_evaluation.v0",
`fixture_id: metame-casual-pre2025`,
`item_id: ${item.id}`,
`message_id: "${item.messageId}"`,
`generated: ${JSON.stringify(spokenText)}`,
`ground_truth: ${JSON.stringify(item.groundTruth)}`,
"score:",
` exact_normalized: ${score.exact}`,
` token_precision: ${score.precision.toFixed(3)}`,
` token_recall: ${score.recall.toFixed(3)}`,
` token_f1: ${score.f1.toFixed(3)}`,
].join("\n") + "\n";
}
function scoreText(generated, truth) {
const left = normalizeForScore(generated);
const right = normalizeForScore(truth);
const leftTokens = left.split(/\s+/).filter(Boolean);
const rightTokens = right.split(/\s+/).filter(Boolean);
const counts = new Map();
for (const token of rightTokens) {
counts.set(token, (counts.get(token) ?? 0) + 1);
}
let overlap = 0;
for (const token of leftTokens) {
const count = counts.get(token) ?? 0;
if (count > 0) {
overlap += 1;
counts.set(token, count - 1);
}
}
const precision = leftTokens.length ? overlap / leftTokens.length : 0;
const recall = rightTokens.length ? overlap / rightTokens.length : 0;
const f1 = precision + recall ? (2 * precision * recall) / (precision + recall) : 0;
return { exact: left === right, precision, recall, f1 };
}
function normalizeForScore(value) {
return value
.toLowerCase()
.replace(/[*_`~.,!?;:'"()[\]{}]/g, "")
.replace(/\s+/g, " ")
.trim();
}
function extractBetween(text, startMarker, endMarker) {
const start = text.indexOf(startMarker);
const end = text.indexOf(endMarker, start + startMarker.length);
if (start < 0 || end < 0 || end <= start) {
throw new Error(`Could not extract section ${startMarker}`);
}
return text.slice(start + startMarker.length, end);
}
function runCommand(command, args, { cwd, input = "", timeoutMs = 120_000 }) {
return new Promise((resolveRun) => {
const isCmdShim = /\.cmd$/i.test(command) || /\.bat$/i.test(command);
const spawnCommand = isCmdShim ? (process.env.ComSpec ?? "cmd.exe") : command;
const spawnArgs = isCmdShim ? ["/d", "/s", "/c", command, ...args] : args;
const child = spawn(spawnCommand, spawnArgs, {
cwd,
env: process.env,
stdio: ["pipe", "pipe", "pipe"],
windowsHide: true,
});
let stdout = "";
let stderr = "";
const timer = setTimeout(() => child.kill(), timeoutMs);
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stdout.on("data", (chunk) => { stdout += chunk; });
child.stderr.on("data", (chunk) => { stderr += chunk; });
child.on("error", (error) => {
clearTimeout(timer);
resolveRun({ code: -1, stdout, stderr: `${stderr}\n${error.message}` });
});
child.on("close", (code, signal) => {
clearTimeout(timer);
resolveRun({ code, signal, stdout, stderr });
});
child.stdin.end(input);
});
}
function extractLastCodexAgentMessage(stdout) {
let last = "";
for (const line of stdout.split(/\r?\n/)) {
if (!line.trim()) {
continue;
}
try {
const event = JSON.parse(line);
const message = event?.msg?.message ?? event?.message ?? event?.text;
if (typeof message === "string" && message.trim()) {
last = message;
}
const itemText = event?.item?.text;
if (typeof itemText === "string" && itemText.trim()) {
last = itemText;
}
const content = event?.item?.content;
if (Array.isArray(content)) {
const text = content
.map((part) => typeof part?.text === "string" ? part.text : "")
.join("\n")
.trim();
if (text) {
last = text;
}
}
} catch {
if (line.trim()) {
last = line.trim();
}
}
}
return last;
}
function indentBlock(block, prefix) {
return block.split(/\r?\n/).map((line) => `${prefix}${line}`).join("\n").split(/\r?\n/);
}
function readArg(name) {
const index = process.argv.indexOf(name);
if (index < 0) {
return undefined;
}
return process.argv[index + 1];
}
function escapeRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function sanitizeJob(value) {
return value.replace(/[^A-Za-z0-9_.-]+/g, "_");
}

File diff suppressed because it is too large Load diff

View file

@ -1,83 +0,0 @@
param(
[int] $Port = 8813,
[string] $HostName = "127.0.0.1",
[string] $StateRoot = "E:\Projects\weksa\.weksa",
[string] $MiMoApiKeyPath = "E:\Projects\gamecult-ops\mimo-api-Weksa.txt",
[string] $IdunnRudpHealth = "127.0.0.1:17870",
[string] $IdunnDaemon = "weksa",
[string] $IdunnHealthContract = "weksa.cultnet-rudp-provider-health",
[string] $OdinCultMeshRudp = "127.0.0.1:17871"
)
$ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $PSScriptRoot
$pidPath = Join-Path $StateRoot "weksa-daemon.pid"
$outLog = Join-Path $StateRoot "weksa-daemon.out.log"
$errLog = Join-Path $StateRoot "weksa-daemon.err.log"
New-Item -ItemType Directory -Force -Path $StateRoot | Out-Null
$cultLibPackages = Resolve-Path -LiteralPath (Join-Path $repoRoot "..\CultLib\packages")
$env:NODE_PATH = (@($cultLibPackages.Path, $env:NODE_PATH) | Where-Object { $_ }) -join [IO.Path]::PathSeparator
if (Test-Path -LiteralPath $pidPath) {
$pidText = (Get-Content -LiteralPath $pidPath -Raw).Trim()
if ($pidText -match "^\d+$") {
$existing = Get-Process -Id ([int] $pidText) -ErrorAction SilentlyContinue
if ($null -ne $existing) {
try {
& node (Join-Path $repoRoot "scripts\weksa-daemon.mjs") --health --host $HostName --port $Port --state-root $StateRoot | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host "Weksa daemon already healthy as PID $pidText."
return
}
} catch {
Stop-Process -Id $existing.Id -Force -ErrorAction SilentlyContinue
}
}
}
Remove-Item -LiteralPath $pidPath -Force -ErrorAction SilentlyContinue
}
$arguments = @(
(Join-Path $repoRoot "scripts\weksa-daemon.mjs"),
"--host", $HostName,
"--port", [string] $Port,
"--state-root", $StateRoot,
"--mimo-api-key-path", $MiMoApiKeyPath,
"--idunn-rudp-health", $IdunnRudpHealth,
"--idunn-daemon", $IdunnDaemon,
"--idunn-health-contract", $IdunnHealthContract
)
if (-not [string]::IsNullOrWhiteSpace($OdinCultMeshRudp)) {
$arguments += @("--odin-cultmesh-rudp", $OdinCultMeshRudp)
}
$process = Start-Process -FilePath "node" `
-ArgumentList $arguments `
-WorkingDirectory $repoRoot `
-WindowStyle Hidden `
-PassThru `
-RedirectStandardOutput $outLog `
-RedirectStandardError $errLog
$process.Id | Set-Content -Encoding ASCII -LiteralPath $pidPath
Start-Sleep -Seconds 2
if ($process.HasExited) {
$detail = ""
if (Test-Path -LiteralPath $outLog) { $detail += Get-Content -Raw -LiteralPath $outLog }
if (Test-Path -LiteralPath $errLog) { $detail += Get-Content -Raw -LiteralPath $errLog }
throw "Weksa daemon exited immediately with code $($process.ExitCode).`n$detail"
}
& node (Join-Path $repoRoot "scripts\weksa-daemon.mjs") --health --host $HostName --port $Port --state-root $StateRoot | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Weksa daemon started but health check failed."
}
Write-Host "Started Weksa daemon as PID $($process.Id)."
Write-Host " command: rudp://$HostName`:$Port"
Write-Host " Odin CultMesh/RUDP: $OdinCultMeshRudp"
Write-Host " state: $StateRoot"

File diff suppressed because it is too large Load diff

View file

@ -1,466 +0,0 @@
"use strict";
const dgram = require("dgram");
const path = require("path");
const {
CultNetRudpSession,
decodeRudpPacket,
encodeCultNetMessageForWire,
encodeRudpPacket,
parseCultNetMessage,
} = require("cultnet-ts");
const { encode, decode } = require(path.resolve(
__dirname,
"..",
"..",
"CultLib",
"node_modules",
"@msgpack",
"msgpack",
));
const CULTNET_RUDP_PROTOCOL_ID = "cultnet.transport.rudp.v0";
const WEKSA_COMMAND_RUDP_CONNECTION_ID = 0x1d0d0002;
const WEKSA_MIMO_VOICEDESIGN_COMMAND_SCHEMA_ID = "weksa.mimo_voicedesign_command.v0";
const WEKSA_MIMO_VOICEDESIGN_RECEIPT_SCHEMA_ID = "weksa.mimo_voicedesign_receipt.v0";
async function createWeksaRudpCommandServer(options) {
if (!options?.host || !options?.port || typeof options.onCommand !== "function") {
throw new Error("Weksa RUDP command server requires host, port, and onCommand.");
}
const socket = dgram.createSocket(endpointFamily(options.host));
await bindServerSocket(socket, options.host, options.port);
const sessions = new Map();
const resendTimer = setInterval(() => {
for (const entry of sessions.values()) {
for (const packet of entry.session.dueResends(Date.now())) {
void sendPacket(socket, entry.endpoint, packet);
}
}
}, 25);
resendTimer.unref?.();
const onMessage = (wire, remote) => {
void handleServerDatagram({
wire,
remote,
socket,
sessions,
options,
}).catch((error) => {
options.onError?.(error);
});
};
const onError = (error) => {
options.onError?.(error instanceof Error ? error : new Error(String(error)));
};
socket.on("message", onMessage);
socket.on("error", onError);
return {
endpoint: { host: options.host, port: options.port },
uri: formatRudpEndpoint(options.host, options.port),
close() {
clearInterval(resendTimer);
socket.off("message", onMessage);
socket.off("error", onError);
socket.close();
sessions.clear();
},
};
}
async function handleServerDatagram(input) {
const { wire, remote, socket, sessions, options } = input;
const packet = decodeRudpPacket(wire);
const key = endpointKey(remote.address, remote.port);
let entry = sessions.get(key);
if (!entry) {
if (packet.packetType !== "connect") {
return;
}
const session = new CultNetRudpSession({
connectionId: WEKSA_COMMAND_RUDP_CONNECTION_ID,
initialSequence: 1,
resendDelayMs: 100,
maxPendingReliablePackets: 64,
});
entry = {
session,
endpoint: { host: remote.address, port: remote.port },
};
sessions.set(key, entry);
await sendPacket(socket, entry.endpoint, session.acceptConnect(packet, Date.now()));
return;
}
const result = entry.session.receive(packet, Date.now());
if (result.reply) {
await sendPacket(socket, entry.endpoint, result.reply);
}
for (const frame of result.delivered) {
await handleServerFrame({
socket,
entry,
frame,
options,
});
}
if (packet.packetType === "accept" || result.delivered.length > 0) {
await sendPacket(socket, entry.endpoint, entry.session.createAck());
}
if (result.disconnected) {
sessions.delete(key);
}
}
async function handleServerFrame(input) {
const { socket, entry, frame, options } = input;
if (frame.channelId !== "schema") {
return;
}
const message = parseCultNetMessage(decode(frame.payload), "cultnet.schema.v0");
if (message.schemaVersion !== "cultnet.document_put_raw.v0") {
return;
}
if (message.document.schemaId !== WEKSA_MIMO_VOICEDESIGN_COMMAND_SCHEMA_ID) {
return;
}
const payload = decode(message.document.payload);
const command = {
...payload,
request_id: payload?.request_id ?? message.document.recordKey,
};
let receipt;
try {
receipt = await options.onCommand(command, message);
} catch (error) {
options.onError?.(error instanceof Error ? error : new Error(String(error)));
receipt = {
schema_version: WEKSA_MIMO_VOICEDESIGN_RECEIPT_SCHEMA_ID,
request_id: command.request_id,
generated_at: new Date().toISOString(),
ok: false,
error: error instanceof Error ? error.message : String(error),
};
}
if (!receipt) {
return;
}
const receiptMessage = {
schemaVersion: "cultnet.document_put_raw.v0",
messageId: `${options.runtimeId ?? "weksa-daemon"}:receipt:${receipt.request_id}`,
document: {
schemaId: WEKSA_MIMO_VOICEDESIGN_RECEIPT_SCHEMA_ID,
recordKey: receipt.request_id,
storedAt: receipt.generated_at ?? receipt.observed_at ?? new Date().toISOString(),
payloadEncoding: "messagepack",
payload: encode(receipt),
sourceRuntimeId: options.runtimeId ?? "weksa-daemon",
sourceRole: "weksa-command-ingress",
tags: [CULTNET_RUDP_PROTOCOL_ID, "speech_provider.mimo.voicedesign"],
},
};
const wirePayload = encode(
encodeCultNetMessageForWire(receiptMessage, "cultnet.schema.v0"),
);
for (const packet of entry.session.sendMany("schema", wirePayload, {
reliable: true,
ordered: true,
nowMs: Date.now(),
})) {
await sendPacket(socket, entry.endpoint, packet);
}
}
async function sendWeksaMimoVoiceDesignCommand(options) {
const endpoint = parseEndpoint(options?.endpoint);
const requestId = options.command?.request_id ?? buildRequestId();
const command = {
...options.command,
request_id: requestId,
};
const socket = dgram.createSocket(endpointFamily(endpoint.host));
await bindClientSocket(socket, options?.localHost);
const receiver = createPacketReceiver(socket);
const session = new CultNetRudpSession({
connectionId: WEKSA_COMMAND_RUDP_CONNECTION_ID,
initialSequence: 1,
resendDelayMs: 100,
maxPendingReliablePackets: 64,
});
try {
await sendPacket(socket, endpoint, session.createConnect(Date.now(), new Uint8Array()));
await receiveCultNetMessageUntil({
receiver,
session,
endpoint,
timeoutMs: options.timeoutMs ?? 5000,
label: "accept",
predicate: (_message, packet) => packet.packetType === "accept",
});
const commandMessage = {
schemaVersion: "cultnet.document_put_raw.v0",
messageId: `${options.runtimeId ?? "weksa-cli"}:command:${requestId}`,
document: {
schemaId: WEKSA_MIMO_VOICEDESIGN_COMMAND_SCHEMA_ID,
recordKey: requestId,
storedAt: new Date().toISOString(),
payloadEncoding: "messagepack",
payload: encode(command),
sourceRuntimeId: options.runtimeId ?? "weksa-cli",
sourceRole: "command-client",
tags: [CULTNET_RUDP_PROTOCOL_ID, "speech_provider.mimo.voicedesign"],
},
};
const wirePayload = encode(
encodeCultNetMessageForWire(commandMessage, "cultnet.schema.v0"),
);
for (const packet of session.sendMany("schema", wirePayload, {
reliable: true,
ordered: true,
nowMs: Date.now(),
})) {
await sendPacket(socket, endpoint, packet);
}
return await receiveCultNetMessageUntil({
receiver,
session,
endpoint,
timeoutMs: options.timeoutMs ?? 10000,
label: "receipt",
predicate: (message) =>
message.schemaVersion === "cultnet.document_put_raw.v0"
&& message.document.schemaId === WEKSA_MIMO_VOICEDESIGN_RECEIPT_SCHEMA_ID
&& message.document.recordKey === requestId,
decodePayload: true,
});
} finally {
receiver.close();
socket.close();
}
}
async function receiveCultNetMessageUntil(options) {
const deadline = Date.now() + options.timeoutMs;
while (Date.now() < deadline) {
try {
const packet = await options.receiver.next(
Math.min(100, Math.max(1, deadline - Date.now())),
options.label,
);
const result = options.session.receive(packet, Date.now());
if (result.reply) {
await sendPacket(options.receiver.socket, options.endpoint, result.reply);
}
if (packet.packetType === "accept" || result.delivered.length > 0) {
await sendPacket(
options.receiver.socket,
options.endpoint,
options.session.createAck(),
);
}
if (packet.packetType === "accept" && options.predicate(undefined, packet)) {
return undefined;
}
for (const frame of result.delivered) {
if (frame.channelId !== "schema") {
continue;
}
const message = parseCultNetMessage(decode(frame.payload), "cultnet.schema.v0");
if (!options.predicate(message, packet)) {
continue;
}
if (
options.decodePayload
&& message.schemaVersion === "cultnet.document_put_raw.v0"
) {
return decode(message.document.payload);
}
return message;
}
} catch (error) {
if (error.code !== "ETIMEDOUT") {
throw error;
}
}
for (const packet of options.session.dueResends(Date.now())) {
await sendPacket(options.receiver.socket, options.endpoint, packet);
}
}
throw new Error(`timed out waiting for Weksa RUDP ${options.label} after ${options.timeoutMs}ms`);
}
async function bindServerSocket(socket, host, port) {
await new Promise((resolve, reject) => {
socket.once("error", reject);
socket.bind(port, host, () => {
socket.off("error", reject);
resolve();
});
});
}
async function bindClientSocket(socket, localHost) {
const bindHost = localHost ?? "0.0.0.0";
await new Promise((resolve, reject) => {
socket.once("error", reject);
socket.bind(0, bindHost, () => {
socket.off("error", reject);
resolve();
});
});
}
function createPacketReceiver(socket) {
const packets = [];
const waiters = [];
const errors = [];
const resolveNext = () => {
while (waiters.length > 0 && (packets.length > 0 || errors.length > 0)) {
const waiter = waiters.shift();
clearTimeout(waiter.timer);
if (errors.length > 0) {
waiter.reject(errors.shift());
} else {
waiter.resolve(packets.shift());
}
}
};
const onMessage = (wire) => {
try {
packets.push(decodeRudpPacket(wire));
} catch (error) {
errors.push(error);
}
resolveNext();
};
const onError = (error) => {
errors.push(error);
resolveNext();
};
socket.on("message", onMessage);
socket.on("error", onError);
return {
socket,
next(timeoutMs, label = "packet") {
if (packets.length > 0) {
return Promise.resolve(packets.shift());
}
if (errors.length > 0) {
return Promise.reject(errors.shift());
}
return new Promise((resolve, reject) => {
const waiter = {
resolve,
reject,
timer: setTimeout(() => {
const index = waiters.indexOf(waiter);
if (index >= 0) {
waiters.splice(index, 1);
}
const error = new Error(`timed out waiting for Weksa RUDP ${label}`);
error.code = "ETIMEDOUT";
reject(error);
}, Math.max(1, timeoutMs)),
};
waiters.push(waiter);
});
},
close() {
socket.off("message", onMessage);
socket.off("error", onError);
while (waiters.length > 0) {
const waiter = waiters.shift();
clearTimeout(waiter.timer);
const error = new Error("Weksa RUDP command receiver closed.");
error.code = "ECLOSED";
waiter.reject(error);
}
},
};
}
async function sendPacket(socket, endpoint, packet) {
const wire = encodeRudpPacket(packet);
await new Promise((resolve, reject) => {
socket.send(wire, endpoint.port, endpoint.host, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
function parseEndpoint(value) {
if (!value) {
throw new Error("Weksa RUDP endpoint is required.");
}
const text = String(value).trim();
if (text.toLowerCase().startsWith("rudp://")) {
const parsed = new URL(text);
return {
host: parsed.hostname,
port: parsePort(parsed.port),
};
}
const ipv6 = text.match(/^\[([^\]]+)\]:(\d+)$/);
if (ipv6) {
return { host: ipv6[1], port: parsePort(ipv6[2]) };
}
const index = text.lastIndexOf(":");
if (index <= 0) {
throw new Error(`Weksa RUDP endpoint must be host:port, got "${value}".`);
}
return {
host: text.slice(0, index),
port: parsePort(text.slice(index + 1)),
};
}
function parsePort(value) {
const port = Number(value);
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
throw new Error(`Weksa RUDP endpoint port is invalid: ${value}`);
}
return port;
}
function endpointFamily(host) {
return host.includes(":") ? "udp6" : "udp4";
}
function endpointKey(host, port) {
return `${host}:${port}`;
}
function formatRudpEndpoint(host, port) {
return host.includes(":") ? `rudp://[${host}]:${port}` : `rudp://${host}:${port}`;
}
function buildRequestId() {
return `mimo-${new Date().toISOString().replace(/[-:.TZ]/g, "")}-${Math.random().toString(36).slice(2, 8)}`;
}
module.exports = {
CULTNET_RUDP_PROTOCOL_ID,
WEKSA_COMMAND_RUDP_CONNECTION_ID,
WEKSA_MIMO_VOICEDESIGN_COMMAND_SCHEMA_ID,
WEKSA_MIMO_VOICEDESIGN_RECEIPT_SCHEMA_ID,
createWeksaRudpCommandServer,
sendWeksaMimoVoiceDesignCommand,
formatRudpEndpoint,
};