mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
docs: document codex app-server support helpers
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Reads OpenClaw session history for Codex transcript mirroring and sanitizes
|
||||
* image payloads before replaying messages into the app-server projector.
|
||||
*/
|
||||
import fs from "node:fs/promises";
|
||||
import type { AgentMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import type { SessionEntry } from "openclaw/plugin-sdk/agent-sessions";
|
||||
@@ -17,6 +21,7 @@ function isMissingFileError(error: unknown): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns sanitized session-context messages for a Codex mirrored session file. */
|
||||
export async function readCodexMirroredSessionHistoryMessages(
|
||||
sessionFile: string,
|
||||
): Promise<AgentMessage[] | undefined> {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Owns shared and isolated Codex app-server client startup, auth application,
|
||||
* lease tracking, and teardown.
|
||||
*/
|
||||
import { resolveDefaultAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import {
|
||||
applyCodexAppServerAuthProfile,
|
||||
@@ -142,12 +146,14 @@ async function resolveCodexAppServerClientStartContext(
|
||||
return { agentDir, usesNativeAuth, authProfileId, startOptions };
|
||||
}
|
||||
|
||||
/** Gets or starts a shared Codex app-server client without retaining a lease. */
|
||||
export async function getSharedCodexAppServerClient(
|
||||
options?: CodexAppServerClientOptions,
|
||||
): Promise<CodexAppServerClient> {
|
||||
return (await acquireSharedCodexAppServerClient(options)).client;
|
||||
}
|
||||
|
||||
/** Gets or starts a shared Codex app-server client and records a release lease. */
|
||||
export async function getLeasedSharedCodexAppServerClient(
|
||||
options?: CodexAppServerClientOptions,
|
||||
): Promise<CodexAppServerClient> {
|
||||
@@ -159,6 +165,7 @@ export async function getLeasedSharedCodexAppServerClient(
|
||||
return acquired.client;
|
||||
}
|
||||
|
||||
/** Releases one outstanding lease for a shared Codex app-server client. */
|
||||
export function releaseLeasedSharedCodexAppServerClient(client: CodexAppServerClient): boolean {
|
||||
const state = getSharedCodexAppServerClientState();
|
||||
const releases = state.leasedReleases.get(client);
|
||||
@@ -260,6 +267,7 @@ async function acquireSharedCodexAppServerClient(
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts a non-shared Codex app-server client owned entirely by the caller. */
|
||||
export async function createIsolatedCodexAppServerClient(
|
||||
options?: CodexAppServerClientOptions,
|
||||
): Promise<CodexAppServerClient> {
|
||||
@@ -284,6 +292,7 @@ export async function createIsolatedCodexAppServerClient(
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears and closes all shared clients for deterministic tests. */
|
||||
export function resetSharedCodexAppServerClientForTests(): void {
|
||||
const state = getSharedCodexAppServerClientState();
|
||||
const clients = collectSharedClients(state);
|
||||
@@ -294,6 +303,7 @@ export function resetSharedCodexAppServerClientForTests(): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears and closes all shared clients. */
|
||||
export function clearSharedCodexAppServerClient(): void {
|
||||
const state = getSharedCodexAppServerClientState();
|
||||
const clients = collectSharedClients(state);
|
||||
@@ -303,6 +313,7 @@ export function clearSharedCodexAppServerClient(): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears and closes the shared entry only if it still owns the supplied client. */
|
||||
export function clearSharedCodexAppServerClientIfCurrent(
|
||||
client: CodexAppServerClient | undefined,
|
||||
): boolean {
|
||||
@@ -320,6 +331,7 @@ export function clearSharedCodexAppServerClientIfCurrent(
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Detaches the shared entry without closing the client when it still matches. */
|
||||
export function detachSharedCodexAppServerClientIfCurrent(
|
||||
client: CodexAppServerClient | undefined,
|
||||
): boolean {
|
||||
@@ -336,6 +348,7 @@ export function detachSharedCodexAppServerClientIfCurrent(
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Retains the matching shared client and returns a release callback. */
|
||||
export function retainSharedCodexAppServerClientIfCurrent(
|
||||
client: CodexAppServerClient | undefined,
|
||||
): (() => void) | undefined {
|
||||
@@ -351,6 +364,7 @@ export function retainSharedCodexAppServerClientIfCurrent(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Marks a matching shared client to close after active leases/acquires drain. */
|
||||
export function retireSharedCodexAppServerClientIfCurrent(
|
||||
client: CodexAppServerClient | undefined,
|
||||
): { activeLeases: number; closed: boolean } | undefined {
|
||||
@@ -373,6 +387,7 @@ export function retireSharedCodexAppServerClientIfCurrent(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Clears a matching shared client and waits for its process to exit. */
|
||||
export async function clearSharedCodexAppServerClientIfCurrentAndWait(
|
||||
client: CodexAppServerClient | undefined,
|
||||
options?: {
|
||||
@@ -394,6 +409,7 @@ export async function clearSharedCodexAppServerClientIfCurrentAndWait(
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Clears all shared clients and waits for their processes to exit. */
|
||||
export async function clearSharedCodexAppServerClientAndWait(options?: {
|
||||
exitTimeoutMs?: number;
|
||||
forceKillDelayMs?: number;
|
||||
@@ -433,6 +449,7 @@ function clearSharedClientEntryIfCurrent(key: string, client: CodexAppServerClie
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears a matching shared client only when no lease or acquire currently claims it. */
|
||||
export function clearSharedCodexAppServerClientIfCurrentAndUnclaimed(
|
||||
client: CodexAppServerClient | undefined,
|
||||
): { found: boolean; closed: boolean; activeLeases: number; pendingAcquires: number } {
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/**
|
||||
* Shared Codex app-server test helpers for model fixtures and in-memory client
|
||||
* transports.
|
||||
*/
|
||||
import { EventEmitter } from "node:events";
|
||||
import { PassThrough, Writable } from "node:stream";
|
||||
import type { Model } from "openclaw/plugin-sdk/llm";
|
||||
import { vi } from "vitest";
|
||||
import { CodexAppServerClient } from "./client.js";
|
||||
|
||||
/** Builds a representative Codex-capable model fixture for app-server tests. */
|
||||
export function createCodexTestModel(provider = "openai", input = ["text"]): Model {
|
||||
return {
|
||||
id: "gpt-5.4-codex",
|
||||
@@ -18,6 +23,7 @@ export function createCodexTestModel(provider = "openai", input = ["text"]): Mod
|
||||
} as Model;
|
||||
}
|
||||
|
||||
/** Creates an in-memory Codex app-server client harness with writable stdout frames. */
|
||||
export function createClientHarness() {
|
||||
const stdout = new PassThrough();
|
||||
const writes: string[] = [];
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Bridges Codex item/tool user-input requests to OpenClaw messaging prompts and
|
||||
* turns replies into app-server answer payloads.
|
||||
*/
|
||||
import {
|
||||
embeddedAgentLog,
|
||||
type EmbeddedRunAttemptParams,
|
||||
@@ -44,6 +48,7 @@ type CodexUserInputBridge = {
|
||||
cancelPending: () => void;
|
||||
};
|
||||
|
||||
/** Creates a per-turn bridge for pending Codex user-input requests. */
|
||||
export function createCodexUserInputBridge(params: {
|
||||
paramsForRun: EmbeddedRunAttemptParams;
|
||||
threadId: string;
|
||||
@@ -241,6 +246,8 @@ function formatUserInputPrompt(questions: UserInputQuestion[]): string {
|
||||
}
|
||||
|
||||
function buildUserInputResponse(questions: UserInputQuestion[], inputText: string): JsonObject {
|
||||
// Multi-question replies may use "header: answer" or numbered lines. Keep the
|
||||
// parser permissive so chat-channel replies remain ergonomic.
|
||||
const answers: JsonObject = {};
|
||||
if (questions.length === 1) {
|
||||
const question = questions[0];
|
||||
|
||||
Reference in New Issue
Block a user