From 77ae48b82ad219cd48db983f65afb2609ee3dff9 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 15 Jul 2026 21:29:59 +0100 Subject: [PATCH] Gate Void turns behind their owning organ --- packages/config/src/index.ts | 3 +++ scripts/run-repo-face-heartbeats.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index d38e2e3..cecee54 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -136,6 +136,7 @@ const envSchema = z.object({ BIFROST_CULTMESH_COMMAND_TIMEOUT_MS: z.coerce.number().int().positive().default(30000), BIFROST_CULTMESH_COMMAND_PUMP_ENABLED: booleanFromEnv.default(true), REPO_FACE_HEARTBEATS_ENABLED: booleanFromEnv.default(false), + VOIDBOT_MODERATION_HEARTBEAT_ENABLED: booleanFromEnv.default(false), REPO_FACE_HEARTBEAT_STATE_PATH: z.string().min(1).default(".voidbot/status/repo-face-heartbeats.json"), REPO_FACE_HEARTBEAT_TASK_NAME: z.string().min(1).default("VoidBot Repo Face Heartbeats"), REPO_FACE_HEARTBEAT_INTERVAL_MINUTES: z.coerce.number().int().min(1).default(5), @@ -246,6 +247,7 @@ export interface AppConfig { timeoutMs: number; pumpEnabled: boolean; }; + voidModerationHeartbeatEnabled: boolean; repoFaceHeartbeats: { enabled: boolean; statePath: string; @@ -535,6 +537,7 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig { timeoutMs: parsed.BIFROST_CULTMESH_COMMAND_TIMEOUT_MS, pumpEnabled: parsed.BIFROST_CULTMESH_COMMAND_PUMP_ENABLED, }, + voidModerationHeartbeatEnabled: parsed.VOIDBOT_MODERATION_HEARTBEAT_ENABLED, repoFaceHeartbeats: { enabled: parsed.REPO_FACE_HEARTBEATS_ENABLED, statePath: resolve(parsed.REPO_FACE_HEARTBEAT_STATE_PATH), diff --git a/scripts/run-repo-face-heartbeats.ts b/scripts/run-repo-face-heartbeats.ts index 3ed584e..2d6aee5 100644 --- a/scripts/run-repo-face-heartbeats.ts +++ b/scripts/run-repo-face-heartbeats.ts @@ -262,7 +262,7 @@ async function main(): Promise { const completedThisTick = new Set(); state.participants = reconcileParticipants( state.participants, - buildParticipantSpecs(registry.identities), + buildParticipantSpecs(registry.identities, config.voidModerationHeartbeatEnabled), config.repoFaceHeartbeats.defaultChannelId, config.repoFaceHeartbeats.speedOverrides, config.repoFaceHeartbeats.heatOverrides, @@ -287,7 +287,7 @@ async function main(): Promise { }); await applySemanticResponsePressure({ state, - specs: buildParticipantSpecs(registry.identities), + specs: buildParticipantSpecs(registry.identities, config.voidModerationHeartbeatEnabled), messages: idleCooling.observedHumanMessages, restStates, completedThisTick, @@ -478,17 +478,17 @@ interface ParticipantSpec { identity?: RepoDiscordIdentity; } -function buildParticipantSpecs(identities: RepoDiscordIdentity[]): ParticipantSpec[] { +function buildParticipantSpecs(identities: RepoDiscordIdentity[], includeVoid: boolean): ParticipantSpec[] { return [ - { + ...(includeVoid ? [{ id: "void", - participantKind: "system_agent", - turnKind: "void_moderation", + participantKind: "system_agent" as const, + turnKind: "void_moderation" as const, repoName: "VoidBot", displayName: "Void", allowedChannelIds: [], channelSpeedMultiplier: 1, - }, + }] : []), ...identities.map((identity) => ({ id: identity.id, participantKind: identity.identityKind === "native_persona"