Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/extensions/discord/src/monitor/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 9 kB image not shown  

Quelle  auto-presence.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import type { Activity, UpdatePresenceData } from "@buape/carbon/gateway";
import {
  clearExpiredCooldowns,
  ensureAuthProfileStore,
  isProfileInCooldown,
  resolveProfilesUnavailableReason,
  type AuthProfileFailureReason,
  type AuthProfileStore,
} from "openclaw/plugin-sdk/agent-runtime";
import type {
  DiscordAccountConfig,
  DiscordAutoPresenceConfig,
} from "openclaw/plugin-sdk/config-runtime";
import { warn } from "openclaw/plugin-sdk/runtime-env";
import { resolveDiscordPresenceUpdate } from "./presence.js";

const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
const CUSTOM_STATUS_NAME = "Custom Status";
const DEFAULT_INTERVAL_MS = 30_000;
const DEFAULT_MIN_UPDATE_INTERVAL_MS = 15_000;
const MIN_INTERVAL_MS = 5_000;
const MIN_UPDATE_INTERVAL_MS = 1_000;

export type DiscordAutoPresenceState = "healthy" | "degraded" | "exhausted";

type ResolvedDiscordAutoPresenceConfig = {
  enabled: boolean;
  intervalMs: number;
  minUpdateIntervalMs: number;
  healthyText?: string;
  degradedText?: string;
  exhaustedText?: string;
};

export type DiscordAutoPresenceDecision = {
  state: DiscordAutoPresenceState;
  unavailableReason?: AuthProfileFailureReason | null;
  presence: UpdatePresenceData;
};

type PresenceGateway = {
  isConnected: boolean;
  updatePresence: (payload: UpdatePresenceData) => void;
};

function normalizeOptionalText(value: unknown): string | undefined {
  if (typeof value !== "string") {
    return undefined;
  }
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : undefined;
}

function clampPositiveInt(value: unknown, fallback: number, minValue: number): number {
  if (typeof value !== "number" || !Number.isFinite(value)) {
    return fallback;
  }
  const rounded = Math.round(value);
  if (rounded <= 0) {
    return fallback;
  }
  return Math.max(minValue, rounded);
}

function resolveAutoPresenceConfig(
  config?: DiscordAutoPresenceConfig,
): ResolvedDiscordAutoPresenceConfig {
  const intervalMs = clampPositiveInt(config?.intervalMs, DEFAULT_INTERVAL_MS, MIN_INTERVAL_MS);
  const minUpdateIntervalMs = clampPositiveInt(
    config?.minUpdateIntervalMs,
    DEFAULT_MIN_UPDATE_INTERVAL_MS,
    MIN_UPDATE_INTERVAL_MS,
  );

  return {
    enabled: config?.enabled === true,
    intervalMs,
    minUpdateIntervalMs,
    healthyText: normalizeOptionalText(config?.healthyText),
    degradedText: normalizeOptionalText(config?.degradedText),
    exhaustedText: normalizeOptionalText(config?.exhaustedText),
  };
}

function buildCustomStatusActivity(text: string): Activity {
  return {
    name: CUSTOM_STATUS_NAME,
    type: DEFAULT_CUSTOM_ACTIVITY_TYPE,
    state: text,
  };
}

function renderTemplate(
  template: string,
  vars: Record<string, string | undefined>,
): string | undefined {
  const rendered = template
    .replace(/\{([a-zA-Z0-9_]+)\}/g, (_full, key: string) => vars[key] ?? "")
    .replace(/\s+/g, " ")
    .trim();
  return rendered.length > 0 ? rendered : undefined;
}

function isExhaustedUnavailableReason(reason: AuthProfileFailureReason | null): boolean {
  if (!reason) {
    return false;
  }
  return (
    reason === "rate_limit" ||
    reason === "overloaded" ||
    reason === "billing" ||
    reason === "auth" ||
    reason === "auth_permanent"
  );
}

function formatUnavailableReason(reason: AuthProfileFailureReason | null): string {
  if (!reason) {
    return "unknown";
  }
  return reason.replace(/_/g, " ");
}

function resolveAuthAvailability(params: { store: AuthProfileStore; now: number }): {
  state: DiscordAutoPresenceState;
  unavailableReason?: AuthProfileFailureReason | null;
} {
  const profileIds = Object.keys(params.store.profiles);
  if (profileIds.length === 0) {
    return { state: "degraded", unavailableReason: null };
  }

  clearExpiredCooldowns(params.store, params.now);

  const hasUsableProfile = profileIds.some(
    (profileId) => !isProfileInCooldown(params.store, profileId, params.now),
  );
  if (hasUsableProfile) {
    return { state: "healthy", unavailableReason: null };
  }

  const unavailableReason = resolveProfilesUnavailableReason({
    store: params.store,
    profileIds,
    now: params.now,
  });

  if (isExhaustedUnavailableReason(unavailableReason)) {
    return {
      state: "exhausted",
      unavailableReason,
    };
  }

  return {
    state: "degraded",
    unavailableReason,
  };
}

function resolvePresenceActivities(params: {
  state: DiscordAutoPresenceState;
  cfg: ResolvedDiscordAutoPresenceConfig;
  basePresence: UpdatePresenceData | null;
  unavailableReason?: AuthProfileFailureReason | null;
}): Activity[] {
  const reasonLabel = formatUnavailableReason(params.unavailableReason ?? null);

  if (params.state === "healthy") {
    if (params.cfg.healthyText) {
      return [buildCustomStatusActivity(params.cfg.healthyText)];
    }
    return params.basePresence?.activities ?? [];
  }

  if (params.state === "degraded") {
    const template = params.cfg.degradedText ?? "runtime degraded";
    const text = renderTemplate(template, { reason: reasonLabel });
    return text ? [buildCustomStatusActivity(text)] : [];
  }

  const defaultTemplate = isExhaustedUnavailableReason(params.unavailableReason ?? null)
    ? "token exhausted"
    : "model unavailable ({reason})";
  const template = params.cfg.exhaustedText ?? defaultTemplate;
  const text = renderTemplate(template, { reason: reasonLabel });
  return text ? [buildCustomStatusActivity(text)] : [];
}

function resolvePresenceStatus(state: DiscordAutoPresenceState): UpdatePresenceData["status"] {
  if (state === "healthy") {
    return "online";
  }
  if (state === "exhausted") {
    return "dnd";
  }
  return "idle";
}

export function resolveDiscordAutoPresenceDecision(params: {
  discordConfig: Pick<
    DiscordAccountConfig,
    "autoPresence" | "activity" | "status" | "activityType" | "activityUrl"
  >;
  authStore: AuthProfileStore;
  gatewayConnected: boolean;
  now?: number;
}): DiscordAutoPresenceDecision | null {
  const autoPresence = resolveAutoPresenceConfig(params.discordConfig.autoPresence);
  if (!autoPresence.enabled) {
    return null;
  }

  const now = params.now ?? Date.now();
  const basePresence = resolveDiscordPresenceUpdate(params.discordConfig);

  const availability = resolveAuthAvailability({
    store: params.authStore,
    now,
  });
  const state = params.gatewayConnected ? availability.state : "degraded";
  const unavailableReason = params.gatewayConnected
    ? availability.unavailableReason
    : (availability.unavailableReason ?? "unknown");

  const activities = resolvePresenceActivities({
    state,
    cfg: autoPresence,
    basePresence,
    unavailableReason,
  });

  return {
    state,
    unavailableReason,
    presence: {
      since: null,
      activities,
      status: resolvePresenceStatus(state),
      afk: false,
    },
  };
}

function stablePresenceSignature(payload: UpdatePresenceData): string {
  return JSON.stringify({
    status: payload.status,
    afk: payload.afk,
    since: payload.since,
    activities: payload.activities.map((activity) => ({
      type: activity.type,
      name: activity.name,
      state: activity.state,
      url: activity.url,
    })),
  });
}

export type DiscordAutoPresenceController = {
  start: () => void;
  stop: () => void;
  refresh: () => void;
  runNow: () => void;
  enabled: boolean;
};

export function createDiscordAutoPresenceController(params: {
  accountId: string;
  discordConfig: Pick<
    DiscordAccountConfig,
    "autoPresence" | "activity" | "status" | "activityType" | "activityUrl"
  >;
  gateway: PresenceGateway;
  loadAuthStore?: () => AuthProfileStore;
  now?: () => number;
  setIntervalFn?: typeof setInterval;
  clearIntervalFn?: typeof clearInterval;
  log?: (message: string) => void;
}): DiscordAutoPresenceController {
  const autoCfg = resolveAutoPresenceConfig(params.discordConfig.autoPresence);
  if (!autoCfg.enabled) {
    return {
      enabled: false,
      start: () => undefined,
      stop: () => undefined,
      refresh: () => undefined,
      runNow: () => undefined,
    };
  }

  const loadAuthStore = params.loadAuthStore ?? (() => ensureAuthProfileStore());
  const now = params.now ?? (() => Date.now());
  const setIntervalFn = params.setIntervalFn ?? setInterval;
  const clearIntervalFn = params.clearIntervalFn ?? clearInterval;

  let timer: ReturnType<typeof setInterval> | undefined;
  let lastAppliedSignature: string | null = null;
  let lastAppliedAt = 0;

  const runEvaluation = (options?: { force?: boolean }) => {
    let decision: DiscordAutoPresenceDecision | null = null;
    try {
      decision = resolveDiscordAutoPresenceDecision({
        discordConfig: params.discordConfig,
        authStore: loadAuthStore(),
        gatewayConnected: params.gateway.isConnected,
        now: now(),
      });
    } catch (err) {
      params.log?.(
        warn(
          `discord: auto-presence evaluation failed for account ${params.accountId}: ${String(err)}`,
        ),
      );
      return;
    }

    if (!decision || !params.gateway.isConnected) {
      return;
    }

    const forceApply = options?.force === true;
    const ts = now();
    const signature = stablePresenceSignature(decision.presence);
    if (!forceApply && signature === lastAppliedSignature) {
      return;
    }
    if (!forceApply && lastAppliedAt > 0 && ts - lastAppliedAt < autoCfg.minUpdateIntervalMs) {
      return;
    }

    params.gateway.updatePresence(decision.presence);
    lastAppliedSignature = signature;
    lastAppliedAt = ts;
  };

  return {
    enabled: true,
    runNow: () => runEvaluation(),
    refresh: () => runEvaluation({ force: true }),
    start: () => {
      if (timer) {
        return;
      }
      runEvaluation({ force: true });
      timer = setIntervalFn(() => runEvaluation(), autoCfg.intervalMs);
    },
    stop: () => {
      if (!timer) {
        return;
      }
      clearIntervalFn(timer);
      timer = undefined;
    },
  };
}

export const __testing = {
  resolveAutoPresenceConfig,
  resolveAuthAvailability,
  stablePresenceSignature,
};

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.