Ctrl K
ComunidadGuías…

lib/project-capsule-turn.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Delivers a Capsule turn prompt into this Mate project.
//
// A Capsule game against a Mate needs the Mate to actually take its turns:
// when Logic passes the turn to the mate seat, this module wakes the Mate
// with a prompt telling it to snapshot the game and act. One session hosts
// the whole game (found again by session.capsuleGame.toolId), so the user
// watches a single running conversation of the Mate playing rather than a
// new session per turn. The prompt is recorded as an internal user message,
// the same shape the debate engine uses, so the transcript shows the nudge
// without pretending the human typed it.
//
// This module only carries words to the Mate. Every actual game mutation the
// Mate then makes goes through the same clay_tool_act pipeline as always.

function attachCapsuleTurn(ctx) {
  var sm = ctx.sm;

  function ownsSession(session, principal) {
    if (ctx.isMultiUser()) return !!principal.userId && session.ownerId === principal.userId;
    return !session.ownerId;
  }

  function findGameSession(principal, toolId) {
    var found = null;
    sm.sessions.forEach(function (session) {
      if (found || !session || session.hidden || session.destroying) return;
      if (!session.capsuleGame || session.capsuleGame.toolId !== toolId) return;
      if (!ownsSession(session, principal)) return;
      found = session;
    });
    return found;
  }

  async function createGameSession(principal, options) {
    var selection = await ctx.resolveModel(principal);
    if (!selection || selection.status !== "ready" || !selection.vendor || !selection.model) {
      throw new Error(selection && selection.error ? selection.error : "No configured model is available for the Mate.");
    }
    var create = typeof sm.createSessionRaw === "function" ? sm.createSessionRaw : sm.createSession;
    var session = create.call(sm, {
      ownerId: principal.userId || null,
      vendor: selection.vendor,
      model: selection.model,
      effort: selection.effort || null,
    });
    session.title = (options.toolName || options.toolId) + " game";
    session.capsuleGame = { toolId: options.toolId };
    return session;
  }

  async function deliverCapsuleTurn(principal, options) {
    if (!principal || !options || !options.toolId || !options.text) {
      throw new Error("A bound owner, toolId, and turn text are required.");
    }
    var sdk = ctx.getSdk();
    if (!sdk || typeof sdk.startQuery !== "function") throw new Error("Mate project runtime is unavailable.");
    var session = findGameSession(principal, options.toolId);
    var created = false;
    if (!session) {
      session = await createGameSession(principal, options);
      created = true;
    }
    // Recorded as a dedicated event, not a user message: the transcript shows
    // a short system note (see historyToHomeChat) instead of pretending the
    // human typed the delivery prompt. The full prompt still reaches the
    // model through the query below.
    sm.sendAndRecord(session, {
      type: "capsule_turn",
      text: options.text,
      toolId: options.toolId,
      toolName: options.toolName || options.toolId,
      kind: options.kind || "turn",
    });
    session.isProcessing = true;
    session.lastActivity = Date.now();
    sm.broadcastSessionList();
    try {
      var delivered = typeof sdk.pushMessage === "function" ? sdk.pushMessage(session, options.text) : false;
      if (!delivered) await Promise.resolve(sdk.startQuery(session, options.text, undefined, ctx.getLinuxUserForSession(session)));
    } catch (error) {
      session.isProcessing = false;
      sm.sendAndRecord(session, { type: "error", text: "Capsule turn could not start: " + (error && error.message ? error.message : String(error)) });
      sm.broadcastSessionList();
      throw error;
    }
    // The reference shape the home chat surface opens sessions by.
    return {
      session: session,
      created: created,
      reference: (typeof session.cliSessionId === "string" && session.cliSessionId) || "local:" + session.localId,
    };
  }

  return { deliverCapsuleTurn: deliverCapsuleTurn };
}

module.exports = { attachCapsuleTurn: attachCapsuleTurn };