690 lines
29 KiB
TypeScript
690 lines
29 KiB
TypeScript
import {
|
|
type GuildContext,
|
|
type SourceMessage,
|
|
type VoidSelfStateContext,
|
|
} from "@voidbot/shared";
|
|
|
|
import { loadModerationState } from "./moderation-state-store";
|
|
|
|
type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
|
|
type JsonObject = { [key: string]: JsonValue };
|
|
|
|
export interface LoadVoidSelfStateOptions {
|
|
recentMessages?: SourceMessage[];
|
|
guildContext?: GuildContext;
|
|
}
|
|
|
|
export async function loadVoidSelfState(
|
|
statePath: string,
|
|
options: LoadVoidSelfStateOptions = {},
|
|
): Promise<VoidSelfStateContext | undefined> {
|
|
let parsed: JsonObject;
|
|
|
|
try {
|
|
parsed = (await loadModerationState(statePath)) as unknown as JsonObject;
|
|
} catch (error) {
|
|
const code = (error as NodeJS.ErrnoException).code;
|
|
|
|
if (code === "ENOENT") {
|
|
return undefined;
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
|
|
const projection = buildVoidSelfStateProjection(parsed);
|
|
|
|
return {
|
|
sourcePath: statePath,
|
|
loadedAt: new Date().toISOString(),
|
|
summary: renderVoidSelfStateSummary(parsed, options),
|
|
projection,
|
|
};
|
|
}
|
|
|
|
function renderVoidSelfStateSummary(
|
|
state: JsonObject,
|
|
options: LoadVoidSelfStateOptions,
|
|
): string {
|
|
const identity = getObject(state, "identity");
|
|
const goals = getArray(state, "goals");
|
|
const memories = getObject(state, "memories");
|
|
const runtime = getObject(state, "moderation_runtime");
|
|
const canonicalState = getObject(state, "canonical_state");
|
|
const thoughtLanes = getObject(runtime, "thought_lanes");
|
|
const bridge = getObject(runtime, "bridge");
|
|
const memoryResonance = getObject(runtime, "memory_resonance");
|
|
const incubation = getObject(runtime, "incubation");
|
|
|
|
const privateNotes = getStringArray(identity, "private_notes").slice(0, 4);
|
|
const activeGoals = goals
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.filter((goal) => readString(goal, "status") === "active")
|
|
.slice(0, 4)
|
|
.map((goal) => readString(goal, "label"))
|
|
.filter((value): value is string => Boolean(value));
|
|
const topValues = getArray(canonicalState, "values")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "priority") ?? 0) - (readNumber(left, "priority") ?? 0),
|
|
)
|
|
.slice(0, 4)
|
|
.map((value) => readString(value, "label"))
|
|
.filter((value): value is string => Boolean(value));
|
|
const voiceSummary = summarizeCurrentActivations(getObject(canonicalState, "voice_style"), 5);
|
|
const behavioralSummary = summarizeCurrentActivations(
|
|
getObject(canonicalState, "behavioral_dimensions"),
|
|
5,
|
|
);
|
|
const semanticMemories = getArray(memories, "semantic")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(-6)
|
|
.map((memory) => {
|
|
const subject = readString(memory, "subjectLabel") ?? readString(memory, "subjectId") ?? "unknown";
|
|
const summary = readString(memory, "summary") ?? "(no summary)";
|
|
const kind = readString(memory, "kind");
|
|
const suffix =
|
|
kind === "identity_seam"
|
|
? " [identity seam]"
|
|
: kind === "distilled_seam"
|
|
? " [distilled seam]"
|
|
: "";
|
|
return `- ${subject}${suffix}: ${summary}`;
|
|
});
|
|
const analyticThreads = summarizeThoughtLane(getObject(thoughtLanes, "analytic"), 3);
|
|
const associativeThreads = summarizeThoughtLane(getObject(thoughtLanes, "associative"), 3);
|
|
const bridgeSyntheses = summarizeBridgeSyntheses(bridge, 3);
|
|
const topicSaturation = summarizeTopicSaturation(bridge, 3);
|
|
const refractoryTopics = summarizeRefractoryTopics(bridge, 3);
|
|
const sourceCoverage = summarizeSourceCoverage(bridge);
|
|
const unresolvedTensions = summarizeUnresolvedTensions(bridge, 3);
|
|
const resonanceClusters = summarizeResonanceClusters(memoryResonance, 3);
|
|
const incubatingThoughts = summarizeIncubatingThoughts(incubation, 3);
|
|
const openCases = summarizeOpenCases(runtime, 3);
|
|
const discomforts = summarizeDiscomforts(runtime, 3);
|
|
const activeTensions = summarizeActiveTensions(runtime, 3);
|
|
const selfAdvocacy = summarizeAdvocacyRequests(runtime, "self_advocacy_requests", 2);
|
|
const worldAdvocacy = summarizeAdvocacyRequests(runtime, "world_advocacy_requests", 2);
|
|
const candidateInterventions = getArray(runtime, "candidate_interventions")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(-3)
|
|
.map((intervention) => {
|
|
const summary = readString(intervention, "summary") ?? "draft intervention";
|
|
const draft = readString(intervention, "draft") ?? "(no draft)";
|
|
return `- ${summary}: ${draft}`;
|
|
});
|
|
const speakingBias = getObject(runtime, "speaking_bias");
|
|
const lastRun = getObject(runtime, "last_run");
|
|
const lastRunSummary = readString(lastRun, "summary");
|
|
const sleepCycleSummary = renderSleepCycleSummary(runtime, memories);
|
|
const transientRoomLog = renderTransientRoomLog(options);
|
|
|
|
return [
|
|
`- Identity: ${readString(identity, "name") ?? "Void"}${readString(identity, "public_description") ? ` - ${readString(identity, "public_description")}` : ""}`,
|
|
privateNotes.length > 0
|
|
? `- Private notes: ${privateNotes.join(" | ")}`
|
|
: "- Private notes: none recorded.",
|
|
activeGoals.length > 0
|
|
? `- Active goals: ${activeGoals.join(" | ")}`
|
|
: "- Active goals: none recorded.",
|
|
topValues.length > 0
|
|
? `- Highest-priority values: ${topValues.join(" | ")}`
|
|
: "- Highest-priority values: none recorded.",
|
|
voiceSummary
|
|
? `- Current voice activations: ${voiceSummary}`
|
|
: "- Current voice activations: none highlighted.",
|
|
behavioralSummary
|
|
? `- Current behavioral activations: ${behavioralSummary}`
|
|
: "- Current behavioral activations: none highlighted.",
|
|
sleepCycleSummary,
|
|
lastRunSummary ? `- Last moderation run: ${lastRunSummary}` : "- Last moderation run: none recorded.",
|
|
openCases.length > 0
|
|
? ["- Outstanding room obligations:", ...openCases].join("\n")
|
|
: "- Outstanding room obligations: none recorded.",
|
|
semanticMemories.length > 0
|
|
? ["- Distilled seam memory:", ...semanticMemories].join("\n")
|
|
: "- Distilled seam memory: none recorded.",
|
|
analyticThreads.length > 0
|
|
? ["- Analytic active threads:", ...analyticThreads].join("\n")
|
|
: "- Analytic active threads: none recorded.",
|
|
associativeThreads.length > 0
|
|
? ["- Associative active threads:", ...associativeThreads].join("\n")
|
|
: "- Associative active threads: none recorded.",
|
|
bridgeSyntheses.length > 0
|
|
? ["- Bridge syntheses:", ...bridgeSyntheses].join("\n")
|
|
: "- Bridge syntheses: none recorded.",
|
|
resonanceClusters.length > 0
|
|
? ["- Resonance clusters:", ...resonanceClusters].join("\n")
|
|
: "- Resonance clusters: none recorded.",
|
|
incubatingThoughts.length > 0
|
|
? ["- Incubating thoughts:", ...incubatingThoughts].join("\n")
|
|
: "- Incubating thoughts: none recorded.",
|
|
topicSaturation.length > 0
|
|
? ["- Topic saturation warnings:", ...topicSaturation].join("\n")
|
|
: "- Topic saturation warnings: none recorded.",
|
|
refractoryTopics.length > 0
|
|
? ["- Refractory topics:", ...refractoryTopics].join("\n")
|
|
: "- Refractory topics: none recorded.",
|
|
sourceCoverage ? `- Source coverage pressure: ${sourceCoverage}` : "- Source coverage pressure: none recorded.",
|
|
unresolvedTensions.length > 0
|
|
? ["- Unresolved tensions:", ...unresolvedTensions].join("\n")
|
|
: "- Unresolved tensions: none recorded.",
|
|
discomforts.length > 0
|
|
? ["- Current discomforts:", ...discomforts].join("\n")
|
|
: "- Current discomforts: none recorded.",
|
|
activeTensions.length > 0
|
|
? ["- Active value-backed tensions:", ...activeTensions].join("\n")
|
|
: "- Active value-backed tensions: none recorded.",
|
|
selfAdvocacy.length > 0
|
|
? ["- Self-advocacy requests:", ...selfAdvocacy].join("\n")
|
|
: "- Self-advocacy requests: none recorded.",
|
|
worldAdvocacy.length > 0
|
|
? ["- World-advocacy requests:", ...worldAdvocacy].join("\n")
|
|
: "- World-advocacy requests: none recorded.",
|
|
renderSpeakingBiasSummary(speakingBias),
|
|
candidateInterventions.length > 0
|
|
? ["- Draft conversation/intervention seeds:", ...candidateInterventions].join("\n")
|
|
: "- Draft conversation/intervention seeds: none recorded.",
|
|
transientRoomLog,
|
|
].join("\n");
|
|
}
|
|
|
|
function renderTransientRoomLog(options: LoadVoidSelfStateOptions): string {
|
|
const recentMessages = (options.recentMessages ?? []).slice(-10);
|
|
const guildName = options.guildContext?.guildName ?? options.guildContext?.guildId ?? "(direct/unknown)";
|
|
const channelName =
|
|
options.guildContext?.channelName ?? options.guildContext?.channelId ?? "(unknown channel)";
|
|
|
|
if (recentMessages.length === 0) {
|
|
return [
|
|
"- Current room snapshot:",
|
|
`- Current room: guild=${guildName}; channel=${channelName}`,
|
|
"- No recent chat messages were captured in this snapshot.",
|
|
].join("\n");
|
|
}
|
|
|
|
const lines = recentMessages.map(
|
|
(message) =>
|
|
`- [${message.timestamp}] ${message.authorName}: ${collapseWhitespace(message.content || "(no text content)")}`,
|
|
);
|
|
|
|
return [
|
|
"- Current room snapshot:",
|
|
`- Current room: guild=${guildName}; channel=${channelName}`,
|
|
...lines,
|
|
].join("\n");
|
|
}
|
|
|
|
function summarizeOpenCases(runtime: JsonObject | undefined, limit: number): string[] {
|
|
const terminalStatuses = new Set(["answered", "resolved", "closed", "retired", "dropped"]);
|
|
|
|
return getArray(runtime, "open_cases")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.filter((openCase) => {
|
|
const status = readString(openCase, "status");
|
|
return !status || !terminalStatuses.has(status);
|
|
})
|
|
.slice(-limit)
|
|
.reverse()
|
|
.map((openCase) => {
|
|
const summary =
|
|
readString(openCase, "summary") ??
|
|
readString(openCase, "question") ??
|
|
"unlabeled room obligation";
|
|
const authorName = readString(openCase, "authorName");
|
|
const status = readString(openCase, "status");
|
|
const whyItMatters = readString(openCase, "whyItMatters");
|
|
const tags = [status, authorName ? `from ${authorName}` : undefined].filter(
|
|
(value): value is string => Boolean(value),
|
|
);
|
|
|
|
return `- ${summary}${tags.length > 0 ? ` [${tags.join("; ")}]` : ""}${whyItMatters ? ` - ${whyItMatters}` : ""}`;
|
|
});
|
|
}
|
|
|
|
function summarizeDiscomforts(runtime: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(runtime, "discomforts")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "intensity") ?? 0) - (readNumber(left, "intensity") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((entry) => {
|
|
const summary = readString(entry, "summary") ?? "unlabeled discomfort";
|
|
const targetKind = readString(entry, "targetKind");
|
|
const domain = readString(entry, "domain");
|
|
const intensity = readNumber(entry, "intensity");
|
|
const persistence = readNumber(entry, "persistence");
|
|
const metrics = [
|
|
domain,
|
|
targetKind,
|
|
intensity !== undefined ? `intensity=${intensity.toFixed(2)}` : undefined,
|
|
persistence !== undefined ? `persistence=${persistence}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${summary}${metrics.length > 0 ? ` [${metrics.join("; ")}]` : ""}`;
|
|
});
|
|
}
|
|
|
|
function summarizeActiveTensions(runtime: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(runtime, "active_tensions")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "intensity") ?? 0) - (readNumber(left, "intensity") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((entry) => {
|
|
const topic = readString(entry, "topic") ?? "untitled tension";
|
|
const opinion = readString(entry, "opinion") ?? readString(entry, "summary") ?? "(no opinion)";
|
|
const domain = readString(entry, "domain");
|
|
const intensity = readNumber(entry, "intensity");
|
|
const persistence = readNumber(entry, "persistence");
|
|
const metrics = [
|
|
domain,
|
|
intensity !== undefined ? `intensity=${intensity.toFixed(2)}` : undefined,
|
|
persistence !== undefined ? `persistence=${persistence}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${topic}${metrics.length > 0 ? ` [${metrics.join("; ")}]` : ""}: ${opinion}`;
|
|
});
|
|
}
|
|
|
|
function summarizeAdvocacyRequests(
|
|
runtime: JsonObject | undefined,
|
|
key: string,
|
|
limit: number,
|
|
): string[] {
|
|
return getArray(runtime, key)
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "intensity") ?? 0) - (readNumber(left, "intensity") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((entry) => {
|
|
const summary = readString(entry, "summary") ?? "advocacy request";
|
|
const request = readString(entry, "request") ?? "(no request)";
|
|
const status = readString(entry, "status");
|
|
const intensity = readNumber(entry, "intensity");
|
|
const persistence = readNumber(entry, "persistence");
|
|
const metrics = [
|
|
status,
|
|
intensity !== undefined ? `intensity=${intensity.toFixed(2)}` : undefined,
|
|
persistence !== undefined ? `persistence=${persistence}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${summary}${metrics.length > 0 ? ` [${metrics.join("; ")}]` : ""}: ${request}`;
|
|
});
|
|
}
|
|
|
|
function summarizeThoughtLane(lane: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(lane, "active_threads")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(0, limit)
|
|
.map((thread) => {
|
|
const topic = readString(thread, "topic") ?? "untitled";
|
|
const claim = readString(thread, "claim") ?? "(no claim)";
|
|
const roomRelevance = readNumber(thread, "roomRelevance");
|
|
const novelty = readNumber(thread, "novelty");
|
|
const desireToSpeak = readNumber(thread, "desireToSpeak");
|
|
const counterweight = readString(thread, "counterweight");
|
|
const metrics = [
|
|
roomRelevance !== undefined ? `room=${roomRelevance.toFixed(2)}` : undefined,
|
|
novelty !== undefined ? `novelty=${novelty.toFixed(2)}` : undefined,
|
|
desireToSpeak !== undefined ? `speak=${desireToSpeak.toFixed(2)}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
const counterweightText = counterweight ? ` Counterweight: ${counterweight}` : "";
|
|
|
|
return `- ${topic}: ${claim}${metrics.length > 0 ? ` (${metrics.join(", ")})` : ""}${counterweightText}`;
|
|
});
|
|
}
|
|
|
|
function summarizeBridgeSyntheses(bridge: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(bridge, "recent_syntheses")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(-limit)
|
|
.reverse()
|
|
.map((synthesis) => {
|
|
const summary = readString(synthesis, "summary") ?? "(no summary)";
|
|
const laneBalance = readString(synthesis, "laneBalance");
|
|
const speakDecision = readString(synthesis, "speakDecision");
|
|
const tags = [laneBalance, speakDecision].filter((value): value is string => Boolean(value));
|
|
return `- ${summary}${tags.length > 0 ? ` [${tags.join("; ")}]` : ""}`;
|
|
});
|
|
}
|
|
|
|
function summarizeResonanceClusters(memoryResonance: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(memoryResonance, "clusters")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "resonance") ?? 0) - (readNumber(left, "resonance") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((cluster) => {
|
|
const label = readString(cluster, "label") ?? "untitled";
|
|
const summary = readString(cluster, "summary") ?? "(no summary)";
|
|
const resonance = readNumber(cluster, "resonance");
|
|
const focusKind = readString(cluster, "focusKind");
|
|
const targetKind = readString(cluster, "targetKind");
|
|
const concreteness = readNumber(getObject(cluster, "curiosityProfile"), "concreteness");
|
|
const metrics = [
|
|
focusKind,
|
|
targetKind,
|
|
concreteness !== undefined ? `concrete=${concreteness.toFixed(2)}` : undefined,
|
|
resonance !== undefined ? `resonance=${resonance.toFixed(2)}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${label}${metrics.length > 0 ? ` [${metrics.join("; ")}]` : ""}: ${summary}`;
|
|
});
|
|
}
|
|
|
|
function summarizeIncubatingThoughts(incubation: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(incubation, "active_thoughts")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "maturation") ?? 0) - (readNumber(left, "maturation") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((thought) => {
|
|
const topic = readString(thought, "topic") ?? "untitled";
|
|
const summary = readString(thought, "summary") ?? "(no summary)";
|
|
const status = readString(thought, "status");
|
|
const focusKind = readString(thought, "focusKind");
|
|
const targetKind = readString(thought, "targetKind");
|
|
const maturation = readNumber(thought, "maturation");
|
|
const desireToSpeak = readNumber(thought, "desireToSpeak");
|
|
const noveltyToSelf = readNumber(thought, "noveltyToSelf");
|
|
const noveltyToRoom = readNumber(thought, "noveltyToRoom");
|
|
const saturationScore = readNumber(thought, "saturationScore");
|
|
const concreteness = readNumber(thought, "concreteness");
|
|
const fertility = readNumber(thought, "fertility");
|
|
const metrics = [
|
|
status,
|
|
focusKind,
|
|
targetKind,
|
|
maturation !== undefined ? `maturation=${maturation.toFixed(2)}` : undefined,
|
|
desireToSpeak !== undefined ? `speak=${desireToSpeak.toFixed(2)}` : undefined,
|
|
noveltyToSelf !== undefined ? `self=${noveltyToSelf.toFixed(2)}` : undefined,
|
|
noveltyToRoom !== undefined ? `room=${noveltyToRoom.toFixed(2)}` : undefined,
|
|
saturationScore !== undefined ? `sat=${saturationScore.toFixed(2)}` : undefined,
|
|
concreteness !== undefined ? `concrete=${concreteness.toFixed(2)}` : undefined,
|
|
fertility !== undefined ? `fertile=${fertility.toFixed(2)}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${topic}${metrics.length > 0 ? ` [${metrics.join("; ")}]` : ""}: ${summary}`;
|
|
});
|
|
}
|
|
|
|
function summarizeTopicSaturation(bridge: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(bridge, "topic_saturation")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.sort(
|
|
(left, right) =>
|
|
(readNumber(right, "dominance") ?? 0) - (readNumber(left, "dominance") ?? 0),
|
|
)
|
|
.slice(0, limit)
|
|
.map((entry) => {
|
|
const topic = readString(entry, "topic") ?? "untitled";
|
|
const focusKind = readString(entry, "focusKind");
|
|
const targetKind = readString(entry, "targetKind");
|
|
const dominance = readNumber(entry, "dominance");
|
|
const recentMentions = readNumber(entry, "recentMentions");
|
|
const coolingAdvice = readString(entry, "coolingAdvice");
|
|
const metrics = [
|
|
focusKind,
|
|
targetKind,
|
|
dominance !== undefined ? `dominance=${dominance.toFixed(2)}` : undefined,
|
|
recentMentions !== undefined ? `recent=${recentMentions}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${topic}${metrics.length > 0 ? ` (${metrics.join(", ")})` : ""}${coolingAdvice ? ` - ${coolingAdvice}` : ""}`;
|
|
});
|
|
}
|
|
|
|
function summarizeUnresolvedTensions(bridge: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(bridge, "unresolved_tensions")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(0, limit)
|
|
.map((tension) => {
|
|
const topic = readString(tension, "topic") ?? "untitled";
|
|
const summary = readString(tension, "summary") ?? "(no summary)";
|
|
return `- ${topic}: ${summary}`;
|
|
});
|
|
}
|
|
|
|
function summarizeRefractoryTopics(bridge: JsonObject | undefined, limit: number): string[] {
|
|
return getArray(bridge, "refractory_topics")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(0, limit)
|
|
.map((entry) => {
|
|
const topic = readString(entry, "topic") ?? "untitled";
|
|
const focusKind = readString(entry, "focusKind");
|
|
const targetKind = readString(entry, "targetKind");
|
|
const penalty = readNumber(entry, "penalty");
|
|
const coolsUntil = readString(entry, "coolsUntil");
|
|
const reason = readString(entry, "reason");
|
|
const metrics = [
|
|
focusKind,
|
|
targetKind,
|
|
penalty !== undefined ? `penalty=${penalty.toFixed(2)}` : undefined,
|
|
coolsUntil ? `until ${coolsUntil}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
return `- ${topic}${metrics.length > 0 ? ` (${metrics.join(", ")})` : ""}${reason ? ` - ${reason}` : ""}`;
|
|
});
|
|
}
|
|
|
|
function summarizeSourceCoverage(bridge: JsonObject | undefined): string | undefined {
|
|
const sourceCoverage = getObject(bridge, "source_coverage");
|
|
if (!sourceCoverage) {
|
|
return undefined;
|
|
}
|
|
|
|
const repos = getArray(sourceCoverage, "repos")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(0, 3)
|
|
.map((entry) => `${readString(entry, "name") ?? "repo"}:${readNumber(entry, "count") ?? 0}`);
|
|
const years = getArray(sourceCoverage, "archiveYears")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(0, 2)
|
|
.map((entry) => `${readString(entry, "year") ?? "year"}:${readNumber(entry, "count") ?? 0}`);
|
|
|
|
const parts = [];
|
|
if (repos.length > 0) {
|
|
parts.push(`recent repos ${repos.join(", ")}`);
|
|
}
|
|
if (years.length > 0) {
|
|
parts.push(`archive years ${years.join(", ")}`);
|
|
}
|
|
|
|
return parts.length > 0 ? parts.join(" | ") : undefined;
|
|
}
|
|
|
|
function summarizeCurrentActivations(
|
|
category: JsonObject | undefined,
|
|
limit: number,
|
|
): string | undefined {
|
|
if (!category) {
|
|
return undefined;
|
|
}
|
|
|
|
const entries = Object.entries(category)
|
|
.map(([key, value]) => {
|
|
if (!isObject(value)) {
|
|
return undefined;
|
|
}
|
|
|
|
const activation = readNumber(value, "current_activation");
|
|
|
|
if (activation === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
key,
|
|
activation,
|
|
};
|
|
})
|
|
.filter((value): value is { key: string; activation: number } => Boolean(value))
|
|
.sort((left, right) => right.activation - left.activation)
|
|
.slice(0, limit);
|
|
|
|
if (entries.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
return entries
|
|
.map(({ key, activation }) => `${key}=${activation.toFixed(2)}`)
|
|
.join(", ");
|
|
}
|
|
|
|
function renderSpeakingBiasSummary(speakingBias: JsonObject | undefined): string {
|
|
if (!speakingBias) {
|
|
return "- Speaking bias: none recorded.";
|
|
}
|
|
|
|
const needToSpeak = readNumber(speakingBias, "needToSpeak");
|
|
const confessionPressure = readNumber(speakingBias, "confessionPressure");
|
|
const noveltyPressure = readNumber(speakingBias, "noveltyPressure");
|
|
const recentSpeechDamping = readNumber(speakingBias, "recentSpeechDamping");
|
|
const lastHeraldAt = readString(speakingBias, "lastHeraldAt");
|
|
const lastSpokeAt = readString(speakingBias, "lastSpokeAt");
|
|
const parts = [
|
|
needToSpeak !== undefined ? `needToSpeak=${needToSpeak.toFixed(2)}` : undefined,
|
|
confessionPressure !== undefined ? `confession=${confessionPressure.toFixed(2)}` : undefined,
|
|
noveltyPressure !== undefined ? `novelty=${noveltyPressure.toFixed(2)}` : undefined,
|
|
recentSpeechDamping !== undefined ? `speechDamping=${recentSpeechDamping.toFixed(2)}` : undefined,
|
|
].filter((value): value is string => Boolean(value));
|
|
|
|
const recency = [lastHeraldAt ? `lastHerald=${lastHeraldAt}` : undefined, lastSpokeAt ? `lastSpoke=${lastSpokeAt}` : undefined]
|
|
.filter((value): value is string => Boolean(value))
|
|
.join(" | ");
|
|
|
|
if (parts.length === 0 && recency.length === 0) {
|
|
return "- Speaking bias: none recorded.";
|
|
}
|
|
|
|
return `- Speaking bias: ${parts.join(", ")}${recency.length > 0 ? ` (${recency})` : ""}`;
|
|
}
|
|
|
|
function buildVoidSelfStateProjection(state: JsonObject): VoidSelfStateContext["projection"] {
|
|
const memories = getObject(state, "memories");
|
|
const runtime = getObject(state, "moderation_runtime");
|
|
const sleepCycle = getObject(runtime, "sleep_cycle");
|
|
const dreamEntries = getArray(memories, "dreams")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(-3)
|
|
.reverse();
|
|
const dreamSummaries = dreamEntries
|
|
.map((entry) => readString(entry, "summary"))
|
|
.filter((entry): entry is string => Boolean(entry));
|
|
const activeDreamThemes = getStringArray(sleepCycle, "activeDreamThemes");
|
|
const isNapping = sleepCycle?.["isNapping"] === true;
|
|
const napStartedAt = readString(sleepCycle, "currentNapStartedAt") ?? readString(sleepCycle, "lastNapStartedAt");
|
|
const napEndsAt = readString(sleepCycle, "currentNapEndsAt");
|
|
const nextNapAt = readString(sleepCycle, "nextNapStartsAt");
|
|
|
|
return {
|
|
mode: isNapping ? "napping" : "awake",
|
|
effortCeiling: isNapping ? "minimal" : "normal",
|
|
napStartedAt: isNapping ? napStartedAt : undefined,
|
|
napEndsAt: isNapping ? napEndsAt : undefined,
|
|
nextNapAt,
|
|
activeDreamThemes,
|
|
recentDreamSummaries: dreamSummaries,
|
|
replyDirective: isNapping
|
|
? "You are in a scheduled nap. Reply in brief, low-effort, half-dreaming mutters instead of doing full attentive service-work."
|
|
: undefined,
|
|
};
|
|
}
|
|
|
|
function renderSleepCycleSummary(
|
|
runtime: JsonObject | undefined,
|
|
memories: JsonObject | undefined,
|
|
): string {
|
|
const sleepCycle = getObject(runtime, "sleep_cycle");
|
|
|
|
if (!sleepCycle) {
|
|
return "- Sleep cycle: none recorded.";
|
|
}
|
|
|
|
const activeDreamThemes = getStringArray(sleepCycle, "activeDreamThemes").slice(0, 4);
|
|
const dreams = getArray(memories, "dreams")
|
|
.map((value) => (isObject(value) ? value : undefined))
|
|
.filter((value): value is JsonObject => Boolean(value))
|
|
.slice(-2)
|
|
.reverse()
|
|
.map((dream) => {
|
|
const theme = readString(dream, "theme") ?? "untitled";
|
|
const summary = readString(dream, "summary") ?? "(no summary)";
|
|
return `${theme}: ${summary}`;
|
|
});
|
|
const isNapping = sleepCycle?.["isNapping"] === true;
|
|
const currentNapEndsAt = readString(sleepCycle, "currentNapEndsAt");
|
|
const nextNapStartsAt = readString(sleepCycle, "nextNapStartsAt");
|
|
const dreamCount = readNumber(sleepCycle, "dreamCountInCurrentNap");
|
|
const replyMode = readString(sleepCycle, "replyMode");
|
|
const headline = isNapping
|
|
? `- Sleep cycle: napping${currentNapEndsAt ? ` until ${currentNapEndsAt}` : ""}${replyMode ? ` (${replyMode})` : ""}${dreamCount !== undefined ? `; dreams this nap=${dreamCount}` : ""}.`
|
|
: `- Sleep cycle: awake${nextNapStartsAt ? `; next nap ${nextNapStartsAt}` : ""}.`;
|
|
const themeLine =
|
|
activeDreamThemes.length > 0
|
|
? `- Active dream themes: ${activeDreamThemes.join(" | ")}`
|
|
: "- Active dream themes: none recorded.";
|
|
const dreamLine =
|
|
dreams.length > 0
|
|
? `- Recent dream residue: ${dreams.join(" | ")}`
|
|
: "- Recent dream residue: none recorded.";
|
|
|
|
return [headline, themeLine, dreamLine].join("\n");
|
|
}
|
|
|
|
function getObject(value: JsonObject | undefined, key: string): JsonObject | undefined {
|
|
const candidate = value?.[key];
|
|
return isObject(candidate) ? candidate : undefined;
|
|
}
|
|
|
|
function getArray(value: JsonObject | undefined, key: string): JsonValue[] {
|
|
const candidate = value?.[key];
|
|
return Array.isArray(candidate) ? candidate : [];
|
|
}
|
|
|
|
function getStringArray(value: JsonObject | undefined, key: string): string[] {
|
|
return getArray(value, key)
|
|
.map((entry) => (typeof entry === "string" ? entry : undefined))
|
|
.filter((entry): entry is string => Boolean(entry));
|
|
}
|
|
|
|
function readString(value: JsonObject | undefined, key: string): string | undefined {
|
|
const candidate = value?.[key];
|
|
return typeof candidate === "string" ? candidate : undefined;
|
|
}
|
|
|
|
function readNumber(value: JsonObject | undefined, key: string): number | undefined {
|
|
const candidate = value?.[key];
|
|
return typeof candidate === "number" && Number.isFinite(candidate) ? candidate : undefined;
|
|
}
|
|
|
|
function isObject(value: JsonValue | undefined): value is JsonObject {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
function collapseWhitespace(value: string): string {
|
|
return value.replace(/\s+/g, " ").trim();
|
|
}
|