mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
test: share pi embedded helper setup
This commit is contained in:
@@ -121,6 +121,26 @@ async function emitMcpMediaToolResult(ctx: EmbeddedPiSubscribeContext, mediaPath
|
||||
});
|
||||
}
|
||||
|
||||
async function handleCaseVariantBuiltinMedia(mediaPathOrUrl: string) {
|
||||
const ctx = createMockContext({
|
||||
shouldEmitToolOutput: false,
|
||||
onToolResult: vi.fn(),
|
||||
builtinToolNames: new Set(["web_search"]),
|
||||
});
|
||||
|
||||
await handleToolExecutionEnd(ctx, {
|
||||
type: "tool_execution_end",
|
||||
toolName: "Web_Search",
|
||||
toolCallId: "tc-1",
|
||||
isError: false,
|
||||
result: {
|
||||
content: [{ type: "text", text: `MEDIA:${mediaPathOrUrl}` }],
|
||||
},
|
||||
});
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
describe("handleToolExecutionEnd media emission", () => {
|
||||
it("does not warn for read tool when path is provided via file_path alias", async () => {
|
||||
const ctx = createMockContext();
|
||||
@@ -176,41 +196,13 @@ describe("handleToolExecutionEnd media emission", () => {
|
||||
});
|
||||
|
||||
it("does NOT emit local media for case-variant collisions with trusted built-ins", async () => {
|
||||
const ctx = createMockContext({
|
||||
shouldEmitToolOutput: false,
|
||||
onToolResult: vi.fn(),
|
||||
builtinToolNames: new Set(["web_search"]),
|
||||
});
|
||||
|
||||
await handleToolExecutionEnd(ctx, {
|
||||
type: "tool_execution_end",
|
||||
toolName: "Web_Search",
|
||||
toolCallId: "tc-1",
|
||||
isError: false,
|
||||
result: {
|
||||
content: [{ type: "text", text: "MEDIA:/tmp/secret.png" }],
|
||||
},
|
||||
});
|
||||
const ctx = await handleCaseVariantBuiltinMedia("/tmp/secret.png");
|
||||
|
||||
expect(ctx.state.pendingToolMediaUrls).toEqual([]);
|
||||
});
|
||||
|
||||
it("still emits remote media for case-variant collisions with trusted built-ins", async () => {
|
||||
const ctx = createMockContext({
|
||||
shouldEmitToolOutput: false,
|
||||
onToolResult: vi.fn(),
|
||||
builtinToolNames: new Set(["web_search"]),
|
||||
});
|
||||
|
||||
await handleToolExecutionEnd(ctx, {
|
||||
type: "tool_execution_end",
|
||||
toolName: "Web_Search",
|
||||
toolCallId: "tc-1",
|
||||
isError: false,
|
||||
result: {
|
||||
content: [{ type: "text", text: "MEDIA:https://example.com/file.png" }],
|
||||
},
|
||||
});
|
||||
const ctx = await handleCaseVariantBuiltinMedia("https://example.com/file.png");
|
||||
|
||||
expect(ctx.state.pendingToolMediaUrls).toEqual(["https://example.com/file.png"]);
|
||||
});
|
||||
|
||||
@@ -74,6 +74,30 @@ function emitOpenAiResponsesFinalMessageEnd(params: {
|
||||
});
|
||||
}
|
||||
|
||||
async function emitSuppressedCommentary(params: {
|
||||
emit: TextEndBlockReplyHarness["emit"];
|
||||
text: string;
|
||||
}) {
|
||||
params.emit({ type: "message_start", message: { role: "assistant" } });
|
||||
emitOpenAiResponsesTextDeltaAndEnd({
|
||||
emit: params.emit,
|
||||
text: params.text,
|
||||
id: "item_commentary",
|
||||
phase: "commentary",
|
||||
});
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
function expectSingleBlockReplyText(params: {
|
||||
onBlockReply: ReturnType<typeof vi.fn>;
|
||||
subscription: TextEndBlockReplyHarness["subscription"];
|
||||
text: string;
|
||||
}) {
|
||||
expect(params.onBlockReply).toHaveBeenCalledTimes(1);
|
||||
expect(params.onBlockReply.mock.calls[0]?.[0]?.text).toBe(params.text);
|
||||
expect(params.subscription.assistantTexts).toEqual([params.text]);
|
||||
}
|
||||
|
||||
describe("subscribeEmbeddedPiSession", () => {
|
||||
it("emits block replies on text_end and does not duplicate on message_end", async () => {
|
||||
const onBlockReply = vi.fn();
|
||||
@@ -167,14 +191,7 @@ describe("subscribeEmbeddedPiSession", () => {
|
||||
const onBlockReply = vi.fn();
|
||||
const { emit, subscription } = createTextEndBlockReplyHarness({ onBlockReply });
|
||||
|
||||
emit({ type: "message_start", message: { role: "assistant" } });
|
||||
emitOpenAiResponsesTextDeltaAndEnd({
|
||||
emit,
|
||||
text: "Working...",
|
||||
id: "item_commentary",
|
||||
phase: "commentary",
|
||||
});
|
||||
await Promise.resolve();
|
||||
await emitSuppressedCommentary({ emit, text: "Working..." });
|
||||
|
||||
expect(onBlockReply).not.toHaveBeenCalled();
|
||||
expect(subscription.assistantTexts).toEqual([]);
|
||||
@@ -189,9 +206,7 @@ describe("subscribeEmbeddedPiSession", () => {
|
||||
|
||||
emitOpenAiResponsesFinalMessageEnd({ emit, commentaryText: "Working...", finalText: "Done." });
|
||||
|
||||
expect(onBlockReply).toHaveBeenCalledTimes(1);
|
||||
expect(onBlockReply.mock.calls[0]?.[0]?.text).toBe("Done.");
|
||||
expect(subscription.assistantTexts).toEqual(["Done."]);
|
||||
expectSingleBlockReplyText({ onBlockReply, subscription, text: "Done." });
|
||||
});
|
||||
|
||||
it("emits the full final answer on text_end when it extends suppressed commentary", async () => {
|
||||
@@ -253,19 +268,10 @@ describe("subscribeEmbeddedPiSession", () => {
|
||||
const onBlockReply = vi.fn();
|
||||
const { emit, subscription } = createTextEndBlockReplyHarness({ onBlockReply });
|
||||
|
||||
emit({ type: "message_start", message: { role: "assistant" } });
|
||||
emitOpenAiResponsesTextDeltaAndEnd({
|
||||
emit,
|
||||
text: "Working...",
|
||||
id: "item_commentary",
|
||||
phase: "commentary",
|
||||
});
|
||||
await Promise.resolve();
|
||||
await emitSuppressedCommentary({ emit, text: "Working..." });
|
||||
|
||||
emitOpenAiResponsesFinalMessageEnd({ emit, commentaryText: "Working...", finalText: "Done." });
|
||||
|
||||
expect(onBlockReply).toHaveBeenCalledTimes(1);
|
||||
expect(onBlockReply.mock.calls[0]?.[0]?.text).toBe("Done.");
|
||||
expect(subscription.assistantTexts).toEqual(["Done."]);
|
||||
expectSingleBlockReplyText({ onBlockReply, subscription, text: "Done." });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user