1140 lines · 35.3 KB · TypeScript
RawDownload
#!/usr/bin/env node// @effect-diagnostics nodeBuiltinImport:offimport * as NodeFS from "node:fs"; import * as Effect from "effect/Effect"; import * as NodeServices from "@effect/platform-node/NodeServices";import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as EffectAcpAgent from "effect-acp/agent";import * as AcpError from "effect-acp/errors";import type * as AcpSchema from "effect-acp/schema"; const requestLogPath = process.env.T3_ACP_REQUEST_LOG_PATH;const exitLogPath = process.env.T3_ACP_EXIT_LOG_PATH;const emitToolCalls = process.env.T3_ACP_EMIT_TOOL_CALLS === "1";const emitInterleavedAssistantToolCalls =  process.env.T3_ACP_EMIT_INTERLEAVED_ASSISTANT_TOOL_CALLS === "1";const emitGenericToolPlaceholders = process.env.T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS === "1";const emitAskQuestion = process.env.T3_ACP_EMIT_ASK_QUESTION === "1";const emitXAiAskUserQuestion = process.env.T3_ACP_EMIT_XAI_ASK_USER_QUESTION === "1";const emitXAiExitPlanMode = process.env.T3_ACP_EMIT_XAI_EXIT_PLAN_MODE === "1";const emitXAiPlanMdWrite = process.env.T3_ACP_EMIT_XAI_PLAN_MD_WRITE === "1";const emitXAiPromptCompleteThenHang = process.env.T3_ACP_EMIT_XAI_PROMPT_COMPLETE_THEN_HANG === "1";const emitXAiRateLimitThenHang = process.env.T3_ACP_EMIT_XAI_RATE_LIMIT_THEN_HANG === "1";const emitXAiAskUserQuestionThenHang =  process.env.T3_ACP_EMIT_XAI_ASK_USER_QUESTION_THEN_HANG === "1";const emitContentThenHang = process.env.T3_ACP_EMIT_CONTENT_THEN_HANG === "1";const emitPlanThenHang = process.env.T3_ACP_EMIT_PLAN_THEN_HANG === "1";const emitActiveToolThenHang = process.env.T3_ACP_EMIT_ACTIVE_TOOL_THEN_HANG === "1";const emitForeignSessionUpdates = process.env.T3_ACP_EMIT_FOREIGN_SESSION_UPDATES === "1";const hangPromptForever = process.env.T3_ACP_HANG_PROMPT_FOREVER === "1";const hangFirstPromptForever = process.env.T3_ACP_HANG_FIRST_PROMPT_FOREVER === "1";const emitLateUpdateAfterCancel = process.env.T3_ACP_EMIT_LATE_UPDATE_AFTER_CANCEL === "1";const omitXAiPromptCompleteStopReason =  process.env.T3_ACP_OMIT_XAI_PROMPT_COMPLETE_STOP_REASON === "1";const failLoadSession = process.env.T3_ACP_FAIL_LOAD_SESSION === "1";const emitLoadReplay = process.env.T3_ACP_EMIT_LOAD_REPLAY === "1";const hangLoadSessionAfterReplay = process.env.T3_ACP_HANG_LOAD_SESSION_AFTER_REPLAY === "1";const delayLoadSessionAfterReplay = process.env.T3_ACP_DELAY_LOAD_SESSION_AFTER_REPLAY === "1";const loadSessionDelayMs = Number(process.env.T3_ACP_LOAD_SESSION_DELAY_MS ?? "5000");const emitStaleXAiPromptCompleteBeforeSecondHang =  process.env.T3_ACP_EMIT_STALE_XAI_PROMPT_COMPLETE_BEFORE_SECOND_HANG === "1";const emitOverlappingXAiPromptCompleteOutOfOrder =  process.env.T3_ACP_EMIT_OVERLAPPING_XAI_PROMPT_COMPLETE_OUT_OF_ORDER === "1";const failPrompt = process.env.T3_ACP_FAIL_PROMPT === "1";const failSetConfigOption = process.env.T3_ACP_FAIL_SET_CONFIG_OPTION === "1";const exitOnSetConfigOption = process.env.T3_ACP_EXIT_ON_SET_CONFIG_OPTION === "1";const promptResponseText = process.env.T3_ACP_PROMPT_RESPONSE_TEXT;const initialGrokReasoningEffort =  process.env.T3_ACP_INITIAL_GROK_REASONING_EFFORT?.trim() || undefined;const promptDelayMs = Number(process.env.T3_ACP_PROMPT_DELAY_MS ?? "0");const permissionOptionIds = {  allowOnce: process.env.T3_ACP_ALLOW_ONCE_OPTION_ID ?? "allow-once",  allowAlways: process.env.T3_ACP_ALLOW_ALWAYS_OPTION_ID ?? "allow-always",  rejectOnce: process.env.T3_ACP_REJECT_ONCE_OPTION_ID ?? "reject-once",};const omitAllowAlways = process.env.T3_ACP_OMIT_ALLOW_ALWAYS === "1";const permissionRequestCount = Math.max(  1,  Number(process.env.T3_ACP_PERMISSION_REQUEST_COUNT ?? "1") || 1,);const sessionId = "mock-session-1"; let currentModeId = "ask";let currentModelId = "default";let parameterizedModelPicker = false;let currentReasoning = "medium";let currentContext = "272k";let currentFast = false;let promptCount = 0;let overlappingFirstPromptId: string | undefined;const cancelledSessions = new Set<string>(); function promptIdFromRequestMeta(  request: Pick<AcpSchema.PromptRequest, "_meta">,): string | undefined {  const meta = request._meta;  if (meta === null || typeof meta !== "object") {    return undefined;  }  const promptId = meta.promptId ?? meta.requestId;  return typeof promptId === "string" && promptId.length > 0 ? promptId : undefined;} function logExit(reason: string): void {  if (!exitLogPath) {    return;  }  NodeFS.appendFileSync(exitLogPath, `${reason}\n`, "utf8");} function writeJsonRpcNotification(method: string, params: unknown): void {  process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}\n`);} process.once("SIGTERM", () => {  logExit("SIGTERM");  process.exit(0);}); process.once("SIGINT", () => {  logExit("SIGINT");  process.exit(0);}); process.once("exit", (code) => {  logExit(`exit:${code}`);}); function configOptions(): ReadonlyArray<AcpSchema.SessionConfigOption> {  if (parameterizedModelPicker) {    const baseOptions: Array<AcpSchema.SessionConfigOption> = [      {        id: "mode",        name: "Mode",        category: "mode",        type: "select",        currentValue: currentModeId,        options: availableModes.map((mode) => ({          value: mode.id,          name: mode.name,          ...(mode.description ? { description: mode.description } : {}),        })),      },      {        id: "model",        name: "Model",        category: "model",        type: "select",        currentValue: currentModelId,        options: [          { value: "default", name: "Auto" },          { value: "composer-2", name: "Composer 2" },          { value: "gpt-5.4", name: "GPT-5.4" },          { value: "claude-opus-4-6", name: "Opus 4.6" },        ],      },    ];     switch (currentModelId) {      case "gpt-5.4":        return [          ...baseOptions,          {            id: "reasoning",            name: "Reasoning",            category: "thought_level",            type: "select",            currentValue: currentReasoning,            options: [              { value: "none", name: "None" },              { value: "low", name: "Low" },              { value: "medium", name: "Medium" },              { value: "high", name: "High" },              { value: "extra-high", name: "Extra High" },            ],          },          {            id: "context",            name: "Context",            category: "model_config",            type: "select",            currentValue: currentContext,            options: [              { value: "272k", name: "272K" },              { value: "1m", name: "1M" },            ],          },          {            id: "fast",            name: "Fast",            category: "model_config",            type: "select",            currentValue: String(currentFast),            options: [              { value: "false", name: "Off" },              { value: "true", name: "Fast" },            ],          },        ];      case "composer-2":        return [          ...baseOptions,          {            id: "fast",            name: "Fast",            category: "model_config",            type: "select",            currentValue: String(currentFast),            options: [              { value: "false", name: "Off" },              { value: "true", name: "Fast" },            ],          },        ];      case "claude-opus-4-6":        return [          ...baseOptions,          {            id: "reasoning",            name: "Reasoning",            category: "thought_level",            type: "select",            currentValue: currentReasoning,            options: [              { value: "low", name: "Low" },              { value: "medium", name: "Medium" },              { value: "high", name: "High" },            ],          },          {            id: "thinking",            name: "Thinking",            category: "model_config",            type: "boolean",            currentValue: true,          },        ];      default:        return baseOptions;    }  }   return [    {      id: "model",      name: "Model",      category: "model",      type: "select" as const,      currentValue: currentModelId,      options: [        { value: "default", name: "Auto" },        { value: "composer-2", name: "Composer 2" },        { value: "composer-2[fast=true]", name: "Composer 2 Fast" },        { value: "gpt-5.3-codex[reasoning=medium,fast=false]", name: "Codex 5.3" },      ],    },  ];} function modelConfigOptionsFor(modelId: string): ReadonlyArray<AcpSchema.SessionConfigOption> {  const previousModelId = currentModelId;  try {    currentModelId = modelId;    return configOptions().filter(      (option) => option.category !== "mode" && option.category !== "model",    );  } finally {    currentModelId = previousModelId;  }} function availableModels(): ReadonlyArray<{  readonly value: string;  readonly name: string;  readonly configOptions: ReadonlyArray<AcpSchema.SessionConfigOption>;}> {  return [    { value: "default", name: "Auto" },    { value: "composer-2", name: "Composer 2" },    { value: "gpt-5.4", name: "GPT-5.4" },    { value: "claude-opus-4-6", name: "Opus 4.6" },  ].map((model) => ({    value: model.value,    name: model.name,    configOptions: modelConfigOptionsFor(model.value),  }));} const availableModes: ReadonlyArray<AcpSchema.SessionMode> = [  {    id: "ask",    name: "Ask",    description: "Request permission before making any changes",  },  {    id: "architect",    name: "Architect",    description: "Design and plan software systems without implementation",  },  {    id: "code",    name: "Code",    description: "Write and modify code with full tool access",  },]; function modeState(): AcpSchema.SessionModeState {  return {    currentModeId,    availableModes,  };} const grokAcpModels: ReadonlyArray<AcpSchema.ModelInfo> = [  {    modelId: "grok-build",    name: "Grok Build",    ...(initialGrokReasoningEffort      ? { _meta: { reasoningEffort: initialGrokReasoningEffort } }      : {}),  },  { modelId: "grok-mock-alt", name: "Grok Mock Alt" },]; function modelState(): AcpSchema.SessionModelState {  const modelId = grokAcpModels.some((model) => model.modelId === currentModelId)    ? currentModelId    : "grok-build";  return {    currentModelId: modelId,    availableModels: grokAcpModels,  };} const program = Effect.gen(function* () {  const agent = yield* EffectAcpAgent.AcpAgent;   yield* agent.handleInitialize((request) =>    Effect.sync(() => {      parameterizedModelPicker =        request.clientCapabilities?._meta?.parameterizedModelPicker === true;      return {        protocolVersion: 1,        agentCapabilities: { loadSession: true },      };    }),  );   yield* agent.handleAuthenticate(() => Effect.succeed({}));   yield* agent.handleCreateSession(() =>    Effect.succeed({      sessionId,      modes: modeState(),      models: modelState(),      configOptions: configOptions(),    }),  );   const emitLoadReplayNotifications = (requestedSessionId: string) => {    writeJsonRpcNotification("session/update", {      _meta: { isReplay: true },      sessionId: requestedSessionId,      update: {        sessionUpdate: "tool_call",        toolCallId: "replay-tool-1",        title: "Replay tool",        kind: "search",        status: "completed",      },    });    writeJsonRpcNotification("session/update", {      _meta: { isReplay: true },      sessionId: requestedSessionId,      update: {        sessionUpdate: "agent_message_chunk",        content: { type: "text", text: "replayed assistant text" },      },    });  };   yield* agent.handleLoadSession((request) =>    Effect.gen(function* () {      const requestedSessionId = String(request.sessionId ?? sessionId);      if (failLoadSession) {        return yield* AcpError.AcpRequestError.internalError("Mock load session failure");      }      if (hangLoadSessionAfterReplay || delayLoadSessionAfterReplay) {        emitLoadReplayNotifications(requestedSessionId);        yield* agent.client.sessionUpdate({          sessionId: requestedSessionId,          update: {            sessionUpdate: "user_message_chunk",            content: { type: "text", text: "replay-tail" },          },        });        yield* Effect.sleep(loadSessionDelayMs);        return {          modes: modeState(),          models: modelState(),          configOptions: configOptions(),        };      }      if (emitLoadReplay) {        emitLoadReplayNotifications(requestedSessionId);      }      yield* agent.client.sessionUpdate({        sessionId: requestedSessionId,        update: {          sessionUpdate: "user_message_chunk",          content: { type: "text", text: "replay" },        },      });      return {        modes: modeState(),        models: modelState(),        configOptions: configOptions(),      };    }),  );   yield* agent.handleSetSessionModel((request) =>    Effect.gen(function* () {      if (!grokAcpModels.some((model) => model.modelId === request.modelId)) {        return yield* AcpError.AcpRequestError.invalidParams(          `Unknown mock model id: ${request.modelId}`,          {            method: "session/set_model",            params: request,          },        );      }      currentModelId = request.modelId;      return {};    }),  );   yield* agent.handleSetSessionConfigOption((request) =>    Effect.gen(function* () {      if (exitOnSetConfigOption) {        return yield* Effect.sync(() => {          process.exit(7);        });      }      if (failSetConfigOption) {        return yield* AcpError.AcpRequestError.invalidParams(          "Mock invalid params for session/set_config_option",          {            method: "session/set_config_option",            params: request,          },        );      }      if (request.configId === "mode" && typeof request.value === "string") {        currentModeId = request.value;      }      if (request.configId === "model" && typeof request.value === "string") {        currentModelId = request.value;      }      if (request.configId === "reasoning" && typeof request.value === "string") {        currentReasoning = request.value;      }      if (request.configId === "context" && typeof request.value === "string") {        currentContext = request.value;      }      if (request.configId === "fast") {        currentFast = request.value === true || request.value === "true";      }      return {        configOptions: configOptions(),      };    }),  );   yield* agent.handleCancel(({ sessionId }) =>    Effect.gen(function* () {      const cancelledSessionId = String(sessionId ?? "mock-session-1");      cancelledSessions.add(cancelledSessionId);      if (emitLateUpdateAfterCancel) {        yield* Effect.sleep("50 millis");        yield* Effect.sync(() => {          writeJsonRpcNotification("session/update", {            sessionId: cancelledSessionId,            update: {              sessionUpdate: "agent_message_chunk",              content: { type: "text", text: "late after cancel" },            },          });        });      }    }),  );   yield* agent.handlePrompt((request) =>    Effect.gen(function* () {      const requestedSessionId = String(request.sessionId ?? sessionId);      promptCount += 1;       if (Number.isFinite(promptDelayMs) && promptDelayMs > 0) {        yield* Effect.sleep(`${promptDelayMs} millis`);      }       if (failPrompt) {        return yield* AcpError.AcpRequestError.internalError("Mock prompt failure");      }       if (emitStaleXAiPromptCompleteBeforeSecondHang && promptCount === 1) {        return {          stopReason: "end_turn",          _meta: {            promptId: "mock-stale-xai-prompt-1",            requestId: "mock-stale-xai-prompt-1",          },        };      }       if (emitStaleXAiPromptCompleteBeforeSecondHang && promptCount === 2) {        const currentPromptId = promptIdFromRequestMeta(request) ?? "mock-current-xai-prompt-2";

Lines 1–500 of 1140.