mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
docs: document acp translator bridge
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/** Shared ACP translator bridge request/event fixtures and assertions. */
|
||||
import type {
|
||||
LoadSessionRequest,
|
||||
NewSessionRequest,
|
||||
@@ -21,6 +22,7 @@ export function createNewSessionRequest(cwd = "/tmp"): NewSessionRequest {
|
||||
} as unknown as NewSessionRequest;
|
||||
}
|
||||
|
||||
/** Builds a minimal ACP load-session request for translator tests. */
|
||||
export function createLoadSessionRequest(sessionId: string, cwd = "/tmp"): LoadSessionRequest {
|
||||
return {
|
||||
sessionId,
|
||||
@@ -30,6 +32,7 @@ export function createLoadSessionRequest(sessionId: string, cwd = "/tmp"): LoadS
|
||||
} as unknown as LoadSessionRequest;
|
||||
}
|
||||
|
||||
/** Builds a minimal ACP prompt request for translator tests. */
|
||||
export function createPromptRequest(
|
||||
sessionId: string,
|
||||
text: string,
|
||||
@@ -42,6 +45,7 @@ export function createPromptRequest(
|
||||
} as unknown as PromptRequest;
|
||||
}
|
||||
|
||||
/** Builds a minimal ACP set-session-mode request for translator tests. */
|
||||
export function createSetSessionModeRequest(
|
||||
sessionId: string,
|
||||
modeId: string,
|
||||
@@ -53,6 +57,7 @@ export function createSetSessionModeRequest(
|
||||
} as unknown as SetSessionModeRequest;
|
||||
}
|
||||
|
||||
/** Builds a minimal ACP set-session-config-option request for translator tests. */
|
||||
export function createSetSessionConfigOptionRequest(
|
||||
sessionId: string,
|
||||
configId: string,
|
||||
@@ -66,6 +71,7 @@ export function createSetSessionConfigOptionRequest(
|
||||
} as unknown as SetSessionConfigOptionRequest;
|
||||
}
|
||||
|
||||
/** Builds a Gateway tool event fixture for translator tests. */
|
||||
export function createToolEvent(params: {
|
||||
sessionKey: string;
|
||||
phase: "start" | "update" | "result";
|
||||
@@ -94,6 +100,7 @@ export function createToolEvent(params: {
|
||||
} as unknown as EventFrame;
|
||||
}
|
||||
|
||||
/** Builds a Gateway final chat event fixture for translator tests. */
|
||||
export function createChatFinalEvent(sessionKey: string): EventFrame {
|
||||
return {
|
||||
event: "chat",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests prompt cancellation scoping across concurrent ACP sessions and Gateway runs. */
|
||||
import type { CancelNotification, PromptRequest, PromptResponse } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests Gateway errorKind to ACP stopReason mapping. */
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createChatEvent,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator replay ledger recording and load-session replay behavior. */
|
||||
import type {
|
||||
LoadSessionRequest,
|
||||
NewSessionRequest,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests final Gateway snapshots are emitted before ACP prompt resolution. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator initialize/session lifecycle and prompt bridge behavior. */
|
||||
import type {
|
||||
CloseSessionRequest,
|
||||
InitializeRequest,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator permission relay for Gateway exec approvals. */
|
||||
import type { CancelNotification } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Builds ACP session presentation, metadata, usage, and config-option snapshots. */
|
||||
import type {
|
||||
InitializeRequest,
|
||||
SessionConfigOption,
|
||||
@@ -23,6 +24,7 @@ export const ACP_ELEVATED_LEVEL_CONFIG_ID = "elevated_level";
|
||||
export const ACP_TIMEOUT_CONFIG_ID = "timeout";
|
||||
export const ACP_TIMEOUT_SECONDS_CONFIG_ID = "timeout_seconds";
|
||||
|
||||
/** Normalized ACP client capability flags used to choose session controls. */
|
||||
export type ClientCapabilityState = {
|
||||
readTextFile: boolean;
|
||||
writeTextFile: boolean;
|
||||
@@ -61,27 +63,32 @@ export type GatewaySessionPresentationRow = Pick<
|
||||
| "contextTokens"
|
||||
>;
|
||||
|
||||
/** ACP session controls and modes shown to the client. */
|
||||
export type SessionPresentation = {
|
||||
configOptions: SessionConfigOption[];
|
||||
modes: SessionModeState;
|
||||
};
|
||||
|
||||
/** ACP session metadata plus lineage information. */
|
||||
export type SessionMetadata = {
|
||||
title?: string | null;
|
||||
updatedAt?: string | null;
|
||||
_meta?: AcpSessionLineageMeta;
|
||||
};
|
||||
|
||||
/** Context/token usage snapshot for ACP clients that expose progress meters. */
|
||||
export type SessionUsageSnapshot = {
|
||||
size: number;
|
||||
used: number;
|
||||
};
|
||||
|
||||
/** Full session snapshot sent after load/list/prompt completion. */
|
||||
export type SessionSnapshot = SessionPresentation & {
|
||||
metadata?: SessionMetadata;
|
||||
usage?: SessionUsageSnapshot;
|
||||
};
|
||||
|
||||
/** Normalizes optional ACP initialize capabilities into stable booleans. */
|
||||
export function normalizeClientCapabilities(
|
||||
capabilities: InitializeRequest["clientCapabilities"] | undefined,
|
||||
): ClientCapabilityState {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Prompt harness helpers for ACP translator lifecycle/cancel/stop-reason tests. */
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { expect, vi } from "vitest";
|
||||
@@ -17,6 +18,7 @@ const DEFAULT_SESSION_ID = "session-1";
|
||||
export const DEFAULT_SESSION_KEY = "agent:main:main";
|
||||
const DEFAULT_PROMPT_TEXT = "hello";
|
||||
|
||||
/** Creates an ACP translator instance with one preloaded session. */
|
||||
export function createSessionAgentHarness(
|
||||
request: GatewayClient["request"],
|
||||
options: { sessionId?: string; sessionKey?: string; cwd?: string } = {},
|
||||
@@ -41,6 +43,7 @@ export function createSessionAgentHarness(
|
||||
};
|
||||
}
|
||||
|
||||
/** Starts a prompt against a translator test agent. */
|
||||
export function promptAgent(
|
||||
agent: AcpGatewayAgent,
|
||||
sessionId = DEFAULT_SESSION_ID,
|
||||
@@ -53,6 +56,7 @@ export function promptAgent(
|
||||
} as unknown as PromptRequest);
|
||||
}
|
||||
|
||||
/** Observes prompt promise settlement without awaiting it immediately. */
|
||||
export function observeSettlement(promise: ReturnType<AcpGatewayAgent["prompt"]>) {
|
||||
const settleSpy = vi.fn();
|
||||
void promise.then(
|
||||
@@ -62,6 +66,7 @@ export function observeSettlement(promise: ReturnType<AcpGatewayAgent["prompt"]>
|
||||
return settleSpy;
|
||||
}
|
||||
|
||||
/** Starts a prompt that remains pending until tests inject Gateway events. */
|
||||
export async function createPendingPromptHarness(): Promise<PendingPromptHarness> {
|
||||
let runId: string | undefined;
|
||||
const request = vi.fn(async (method: string, params?: Record<string, unknown>) => {
|
||||
@@ -86,6 +91,7 @@ export async function createPendingPromptHarness(): Promise<PendingPromptHarness
|
||||
};
|
||||
}
|
||||
|
||||
/** Builds a Gateway chat event fixture for pending-prompt tests. */
|
||||
export function createChatEvent(payload: Record<string, unknown>): EventFrame {
|
||||
return {
|
||||
type: "event",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP prompt cwd-prefix provenance behavior. */
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator prompt-size hardening. */
|
||||
import { describe, it, vi } from "vitest";
|
||||
import { expectOversizedPromptRejected } from "./translator.bridge-test-helpers.js";
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests transcript replay conversion into ACP session update chunks. */
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { extractReplayChunks } from "./translator.replay.js";
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP setSessionMode and setSessionConfigOption Gateway bridge behavior. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP session lineage metadata in list/load session responses. */
|
||||
import type { ListSessionsRequest, LoadSessionRequest } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator session-list cursor and page-size helpers. */
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
ACP_LIST_SESSIONS_MAX_FETCH_LIMIT,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Cursor and pagination helpers for ACP session/list requests. */
|
||||
import path from "node:path";
|
||||
import { readNumber } from "@openclaw/acp-core/meta";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
@@ -10,15 +11,18 @@ const ACP_LIST_SESSIONS_MAX_CURSOR_OFFSET = 10_000;
|
||||
export const ACP_LIST_SESSIONS_MAX_FETCH_LIMIT =
|
||||
ACP_LIST_SESSIONS_MAX_CURSOR_OFFSET + ACP_LIST_SESSIONS_MAX_PAGE_SIZE + 1;
|
||||
|
||||
/** Opaque cursor payload used to page ACP session list results. */
|
||||
export type ListSessionsCursor = {
|
||||
offset: number;
|
||||
cwd?: string;
|
||||
};
|
||||
|
||||
/** Encodes an ACP session-list cursor as base64url JSON. */
|
||||
export function encodeListSessionsCursor(cursor: ListSessionsCursor): string {
|
||||
return Buffer.from(JSON.stringify({ v: 1, ...cursor }), "utf8").toString("base64url");
|
||||
}
|
||||
|
||||
/** Decodes and validates an ACP session-list cursor, defaulting to the first page. */
|
||||
export function decodeListSessionsCursor(value: string | null | undefined): ListSessionsCursor {
|
||||
if (!value) {
|
||||
return { offset: 0 };
|
||||
@@ -51,12 +55,14 @@ export function decodeListSessionsCursor(value: string | null | undefined): List
|
||||
};
|
||||
}
|
||||
|
||||
/** Throws when an ACP method receives a relative cwd filter/path. */
|
||||
export function assertAbsoluteCwd(cwd: string, method: string): void {
|
||||
if (!path.isAbsolute(cwd)) {
|
||||
throw new Error(`ACP ${method} requires an absolute cwd.`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolves requested ACP session-list page size with bridge limits. */
|
||||
export function resolveListSessionsPageSize(
|
||||
meta: Record<string, unknown> | null | undefined,
|
||||
): number {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator session creation rate limiting. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP translator session setup constraints and initial updates. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP session metadata and usage snapshots after prompts. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Emits ACP session updates and mirrors replayable updates into the event ledger. */
|
||||
import type {
|
||||
AgentSideConnection,
|
||||
AvailableCommand,
|
||||
@@ -6,6 +7,7 @@ import type {
|
||||
} from "@agentclientprotocol/sdk";
|
||||
import type { AcpEventLedger, AcpEventLedgerReplay } from "./event-ledger.js";
|
||||
|
||||
/** Session identity used when emitting and recording ACP translator updates. */
|
||||
export type AcpTranslatorSessionRef = {
|
||||
sessionId: string;
|
||||
sessionKey: string;
|
||||
@@ -28,6 +30,7 @@ function resolveLedgerSessionId(session: { sessionId: string; ledgerSessionId?:
|
||||
return session.ledgerSessionId ?? session.sessionId;
|
||||
}
|
||||
|
||||
/** Helper that keeps ACP client updates and replay ledger writes in sync. */
|
||||
export class AcpTranslatorSessionUpdates {
|
||||
constructor(private options: AcpTranslatorSessionUpdatesOptions) {}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests ACP setSessionMode request translation and error propagation. */
|
||||
import type { SetSessionModeRequest } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests Gateway final/error states to ACP prompt stopReason mapping. */
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Shared mocked ACP connection and Gateway client helpers for translator tests. */
|
||||
import type { AgentSideConnection } from "@agentclientprotocol/sdk";
|
||||
import { vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
@@ -24,6 +25,7 @@ export function createAcpConnection(
|
||||
} as unknown as TestAcpConnection;
|
||||
}
|
||||
|
||||
/** Creates a mocked Gateway client for translator tests. */
|
||||
export function createAcpGateway(
|
||||
request: GatewayClient["request"] = vi.fn(async () => ({ ok: true })) as GatewayClient["request"],
|
||||
): GatewayClient {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Tests Gateway tool streaming to ACP tool-call update mapping. */
|
||||
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** Agent Client Protocol bridge that translates ACP sessions/prompts to Gateway chat sessions. */
|
||||
import { randomUUID } from "node:crypto";
|
||||
import os from "node:os";
|
||||
import type {
|
||||
@@ -222,6 +223,7 @@ function hasExplicitSessionRouting(
|
||||
);
|
||||
}
|
||||
|
||||
/** ACP Agent implementation backed by the OpenClaw Gateway and replay ledger. */
|
||||
export class AcpGatewayAgent implements Agent {
|
||||
private connection: AgentSideConnection;
|
||||
private gateway: GatewayClient;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** ACP server option re-exports and OpenClaw agent identity metadata. */
|
||||
export type { AcpProvenanceMode, AcpServerOptions, AcpSession } from "@openclaw/acp-core/types";
|
||||
export { normalizeAcpProvenanceMode } from "@openclaw/acp-core/types";
|
||||
import { VERSION } from "../version.js";
|
||||
|
||||
Reference in New Issue
Block a user