mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:50:43 +00:00
test: share acp prompt harness
This commit is contained in:
@@ -1,88 +1,9 @@
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
import type { EventFrame } from "../gateway/protocol/index.js";
|
||||
import { createInMemorySessionStore } from "./session.js";
|
||||
import { AcpGatewayAgent } from "./translator.js";
|
||||
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";
|
||||
|
||||
type PendingPromptHarness = {
|
||||
agent: AcpGatewayAgent;
|
||||
promptPromise: ReturnType<AcpGatewayAgent["prompt"]>;
|
||||
runId: string;
|
||||
};
|
||||
|
||||
const DEFAULT_SESSION_ID = "session-1";
|
||||
const DEFAULT_SESSION_KEY = "agent:main:main";
|
||||
const DEFAULT_PROMPT_TEXT = "hello";
|
||||
|
||||
function createSessionAgentHarness(
|
||||
request: GatewayClient["request"],
|
||||
options: { sessionId?: string; sessionKey?: string; cwd?: string } = {},
|
||||
) {
|
||||
const sessionId = options.sessionId ?? DEFAULT_SESSION_ID;
|
||||
const sessionKey = options.sessionKey ?? DEFAULT_SESSION_KEY;
|
||||
const sessionStore = createInMemorySessionStore();
|
||||
sessionStore.createSession({
|
||||
sessionId,
|
||||
sessionKey,
|
||||
cwd: options.cwd ?? "/tmp",
|
||||
});
|
||||
const agent = new AcpGatewayAgent(createAcpConnection(), createAcpGateway(request), {
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
sessionStore,
|
||||
};
|
||||
}
|
||||
|
||||
function promptAgent(
|
||||
agent: AcpGatewayAgent,
|
||||
sessionId = DEFAULT_SESSION_ID,
|
||||
text = DEFAULT_PROMPT_TEXT,
|
||||
) {
|
||||
return agent.prompt({
|
||||
sessionId,
|
||||
prompt: [{ type: "text", text }],
|
||||
_meta: {},
|
||||
} as unknown as PromptRequest);
|
||||
}
|
||||
|
||||
async function createPendingPromptHarness(): Promise<PendingPromptHarness> {
|
||||
let runId: string | undefined;
|
||||
const request = vi.fn(async (method: string, params?: Record<string, unknown>) => {
|
||||
if (method === "chat.send") {
|
||||
runId = params?.idempotencyKey as string | undefined;
|
||||
return new Promise<never>(() => {});
|
||||
}
|
||||
return {};
|
||||
}) as GatewayClient["request"];
|
||||
|
||||
const { agent, sessionId } = createSessionAgentHarness(request);
|
||||
const promptPromise = promptAgent(agent, sessionId);
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(runId).toBeDefined();
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
promptPromise,
|
||||
runId: runId!,
|
||||
};
|
||||
}
|
||||
|
||||
function createChatEvent(payload: Record<string, unknown>): EventFrame {
|
||||
return {
|
||||
type: "event",
|
||||
event: "chat",
|
||||
payload,
|
||||
} as EventFrame;
|
||||
}
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createChatEvent,
|
||||
createPendingPromptHarness,
|
||||
DEFAULT_SESSION_KEY,
|
||||
} from "./translator.prompt-harness.test-support.js";
|
||||
|
||||
describe("acp translator errorKind mapping", () => {
|
||||
it("maps errorKind: refusal to stopReason: refusal", async () => {
|
||||
|
||||
94
src/acp/translator.prompt-harness.test-support.ts
Normal file
94
src/acp/translator.prompt-harness.test-support.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
import { expect, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
import type { EventFrame } from "../gateway/protocol/index.js";
|
||||
import { createInMemorySessionStore } from "./session.js";
|
||||
import { AcpGatewayAgent } from "./translator.js";
|
||||
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";
|
||||
|
||||
export type PendingPromptHarness = {
|
||||
agent: AcpGatewayAgent;
|
||||
promptPromise: ReturnType<AcpGatewayAgent["prompt"]>;
|
||||
runId: string;
|
||||
};
|
||||
|
||||
export const DEFAULT_SESSION_ID = "session-1";
|
||||
export const DEFAULT_SESSION_KEY = "agent:main:main";
|
||||
export const DEFAULT_PROMPT_TEXT = "hello";
|
||||
|
||||
export function createSessionAgentHarness(
|
||||
request: GatewayClient["request"],
|
||||
options: { sessionId?: string; sessionKey?: string; cwd?: string } = {},
|
||||
) {
|
||||
const sessionId = options.sessionId ?? DEFAULT_SESSION_ID;
|
||||
const sessionKey = options.sessionKey ?? DEFAULT_SESSION_KEY;
|
||||
const sessionStore = createInMemorySessionStore();
|
||||
sessionStore.createSession({
|
||||
sessionId,
|
||||
sessionKey,
|
||||
cwd: options.cwd ?? "/tmp",
|
||||
});
|
||||
const agent = new AcpGatewayAgent(createAcpConnection(), createAcpGateway(request), {
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
sessionStore,
|
||||
};
|
||||
}
|
||||
|
||||
export function promptAgent(
|
||||
agent: AcpGatewayAgent,
|
||||
sessionId = DEFAULT_SESSION_ID,
|
||||
text = DEFAULT_PROMPT_TEXT,
|
||||
) {
|
||||
return agent.prompt({
|
||||
sessionId,
|
||||
prompt: [{ type: "text", text }],
|
||||
_meta: {},
|
||||
} as unknown as PromptRequest);
|
||||
}
|
||||
|
||||
export function observeSettlement(promise: ReturnType<AcpGatewayAgent["prompt"]>) {
|
||||
const settleSpy = vi.fn();
|
||||
void promise.then(
|
||||
(value) => settleSpy({ kind: "resolve", value }),
|
||||
(error) => settleSpy({ kind: "reject", error }),
|
||||
);
|
||||
return settleSpy;
|
||||
}
|
||||
|
||||
export async function createPendingPromptHarness(): Promise<PendingPromptHarness> {
|
||||
let runId: string | undefined;
|
||||
const request = vi.fn(async (method: string, params?: Record<string, unknown>) => {
|
||||
if (method === "chat.send") {
|
||||
runId = params?.idempotencyKey as string | undefined;
|
||||
return new Promise<never>(() => {});
|
||||
}
|
||||
return {};
|
||||
}) as GatewayClient["request"];
|
||||
|
||||
const { agent, sessionId } = createSessionAgentHarness(request);
|
||||
const promptPromise = promptAgent(agent, sessionId);
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(runId).toBeDefined();
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
promptPromise,
|
||||
runId: runId!,
|
||||
};
|
||||
}
|
||||
|
||||
export function createChatEvent(payload: Record<string, unknown>): EventFrame {
|
||||
return {
|
||||
type: "event",
|
||||
event: "chat",
|
||||
payload,
|
||||
} as EventFrame;
|
||||
}
|
||||
@@ -1,98 +1,17 @@
|
||||
import type { PromptRequest } from "@agentclientprotocol/sdk";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
import type { EventFrame } from "../gateway/protocol/index.js";
|
||||
import { createInMemorySessionStore } from "./session.js";
|
||||
import { AcpGatewayAgent } from "./translator.js";
|
||||
import {
|
||||
createChatEvent,
|
||||
createPendingPromptHarness,
|
||||
createSessionAgentHarness,
|
||||
observeSettlement,
|
||||
promptAgent,
|
||||
} from "./translator.prompt-harness.test-support.js";
|
||||
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";
|
||||
|
||||
type PendingPromptHarness = {
|
||||
agent: AcpGatewayAgent;
|
||||
promptPromise: ReturnType<AcpGatewayAgent["prompt"]>;
|
||||
runId: string;
|
||||
};
|
||||
|
||||
const DEFAULT_SESSION_ID = "session-1";
|
||||
const DEFAULT_SESSION_KEY = "agent:main:main";
|
||||
const DEFAULT_PROMPT_TEXT = "hello";
|
||||
|
||||
function createSessionAgentHarness(
|
||||
request: GatewayClient["request"],
|
||||
options: { sessionId?: string; sessionKey?: string; cwd?: string } = {},
|
||||
) {
|
||||
const sessionId = options.sessionId ?? DEFAULT_SESSION_ID;
|
||||
const sessionKey = options.sessionKey ?? DEFAULT_SESSION_KEY;
|
||||
const sessionStore = createInMemorySessionStore();
|
||||
sessionStore.createSession({
|
||||
sessionId,
|
||||
sessionKey,
|
||||
cwd: options.cwd ?? "/tmp",
|
||||
});
|
||||
const agent = new AcpGatewayAgent(createAcpConnection(), createAcpGateway(request), {
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
sessionStore,
|
||||
};
|
||||
}
|
||||
|
||||
function promptAgent(
|
||||
agent: AcpGatewayAgent,
|
||||
sessionId = DEFAULT_SESSION_ID,
|
||||
text = DEFAULT_PROMPT_TEXT,
|
||||
) {
|
||||
return agent.prompt({
|
||||
sessionId,
|
||||
prompt: [{ type: "text", text }],
|
||||
_meta: {},
|
||||
} as unknown as PromptRequest);
|
||||
}
|
||||
|
||||
function observeSettlement(promise: ReturnType<AcpGatewayAgent["prompt"]>) {
|
||||
const settleSpy = vi.fn();
|
||||
void promise.then(
|
||||
(value) => settleSpy({ kind: "resolve", value }),
|
||||
(error) => settleSpy({ kind: "reject", error }),
|
||||
);
|
||||
return settleSpy;
|
||||
}
|
||||
|
||||
async function createPendingPromptHarness(): Promise<PendingPromptHarness> {
|
||||
let runId: string | undefined;
|
||||
const request = vi.fn(async (method: string, params?: Record<string, unknown>) => {
|
||||
if (method === "chat.send") {
|
||||
runId = params?.idempotencyKey as string | undefined;
|
||||
return new Promise<never>(() => {});
|
||||
}
|
||||
return {};
|
||||
}) as GatewayClient["request"];
|
||||
|
||||
const { agent, sessionId } = createSessionAgentHarness(request);
|
||||
const promptPromise = promptAgent(agent, sessionId);
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(runId).toBeDefined();
|
||||
});
|
||||
|
||||
return {
|
||||
agent,
|
||||
promptPromise,
|
||||
runId: runId!,
|
||||
};
|
||||
}
|
||||
|
||||
function createChatEvent(payload: Record<string, unknown>): EventFrame {
|
||||
return {
|
||||
type: "event",
|
||||
event: "chat",
|
||||
payload,
|
||||
} as EventFrame;
|
||||
}
|
||||
|
||||
describe("acp translator stop reason mapping", () => {
|
||||
it("error state resolves as end_turn, not refusal", async () => {
|
||||
const { agent, promptPromise, runId } = await createPendingPromptHarness();
|
||||
|
||||
Reference in New Issue
Block a user