Fix OpenClaw wake env injection for OpenResponses input
This commit is contained in:
@@ -110,6 +110,60 @@ function buildWakeText(payload: WakePayload, paperclipEnv: Record<string, string
|
|||||||
return lines.join("\n");
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendWakeText(baseText: string, wakeText: string): string {
|
||||||
|
const trimmedBase = baseText.trim();
|
||||||
|
return trimmedBase.length > 0 ? `${trimmedBase}\n\n${wakeText}` : wakeText;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOpenResponsesWakeInputMessage(wakeText: string): Record<string, unknown> {
|
||||||
|
return {
|
||||||
|
type: "message",
|
||||||
|
role: "user",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "input_text",
|
||||||
|
text: wakeText,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendWakeTextToOpenResponsesInput(input: unknown, wakeText: string): unknown {
|
||||||
|
if (typeof input === "string") {
|
||||||
|
return appendWakeText(input, wakeText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(input)) {
|
||||||
|
return [...input, buildOpenResponsesWakeInputMessage(wakeText)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof input === "object" && input !== null) {
|
||||||
|
const parsed = parseObject(input);
|
||||||
|
const content = parsed.content;
|
||||||
|
if (typeof content === "string") {
|
||||||
|
return {
|
||||||
|
...parsed,
|
||||||
|
content: appendWakeText(content, wakeText),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (Array.isArray(content)) {
|
||||||
|
return {
|
||||||
|
...parsed,
|
||||||
|
content: [
|
||||||
|
...content,
|
||||||
|
{
|
||||||
|
type: "input_text",
|
||||||
|
text: wakeText,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return [parsed, buildOpenResponsesWakeInputMessage(wakeText)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return wakeText;
|
||||||
|
}
|
||||||
|
|
||||||
function isTextRequiredResponse(responseText: string): boolean {
|
function isTextRequiredResponse(responseText: string): boolean {
|
||||||
const parsed = parseOpenClawResponse(responseText);
|
const parsed = parseOpenClawResponse(responseText);
|
||||||
const parsedError = parsed && typeof parsed.error === "string" ? parsed.error : null;
|
const parsedError = parsed && typeof parsed.error === "string" ? parsed.error : null;
|
||||||
@@ -478,6 +532,9 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||||||
const wakeText = buildWakeText(wakePayload, paperclipEnv);
|
const wakeText = buildWakeText(wakePayload, paperclipEnv);
|
||||||
const payloadText = templateText ? `${templateText}\n\n${wakeText}` : wakeText;
|
const payloadText = templateText ? `${templateText}\n\n${wakeText}` : wakeText;
|
||||||
const isOpenResponses = isOpenResponsesEndpoint(url);
|
const isOpenResponses = isOpenResponsesEndpoint(url);
|
||||||
|
const openResponsesInput = Object.prototype.hasOwnProperty.call(payloadTemplate, "input")
|
||||||
|
? appendWakeTextToOpenResponsesInput(payloadTemplate.input, wakeText)
|
||||||
|
: payloadText;
|
||||||
|
|
||||||
const paperclipBody: Record<string, unknown> = isOpenResponses
|
const paperclipBody: Record<string, unknown> = isOpenResponses
|
||||||
? {
|
? {
|
||||||
@@ -487,9 +544,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
|
|||||||
nonEmpty(payloadTemplate.model) ??
|
nonEmpty(payloadTemplate.model) ??
|
||||||
nonEmpty(config.model) ??
|
nonEmpty(config.model) ??
|
||||||
"openclaw",
|
"openclaw",
|
||||||
input: Object.prototype.hasOwnProperty.call(payloadTemplate, "input")
|
input: openResponsesInput,
|
||||||
? payloadTemplate.input
|
|
||||||
: payloadText,
|
|
||||||
metadata: {
|
metadata: {
|
||||||
...toStringRecord(payloadTemplate.metadata),
|
...toStringRecord(payloadTemplate.metadata),
|
||||||
...paperclipEnv,
|
...paperclipEnv,
|
||||||
|
|||||||
@@ -229,6 +229,56 @@ describe("openclaw adapter execute", () => {
|
|||||||
expect(headers["x-openclaw-session-key"]).toBe("paperclip");
|
expect(headers["x-openclaw-session-key"]).toBe("paperclip");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("appends wake text when OpenResponses input is provided as a message object", async () => {
|
||||||
|
const fetchMock = vi.fn().mockResolvedValue(
|
||||||
|
sseResponse([
|
||||||
|
"event: response.completed\n",
|
||||||
|
'data: {"type":"response.completed","status":"completed"}\n\n',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
|
|
||||||
|
const result = await execute(
|
||||||
|
buildContext({
|
||||||
|
url: "https://agent.example/v1/responses",
|
||||||
|
method: "POST",
|
||||||
|
payloadTemplate: {
|
||||||
|
model: "openclaw",
|
||||||
|
input: {
|
||||||
|
type: "message",
|
||||||
|
role: "user",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "input_text",
|
||||||
|
text: "start with this context",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
const body = JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body ?? "{}")) as Record<string, unknown>;
|
||||||
|
const input = body.input as Record<string, unknown>;
|
||||||
|
expect(input.type).toBe("message");
|
||||||
|
expect(input.role).toBe("user");
|
||||||
|
expect(Array.isArray(input.content)).toBe(true);
|
||||||
|
|
||||||
|
const content = input.content as Record<string, unknown>[];
|
||||||
|
expect(content).toHaveLength(2);
|
||||||
|
expect(content[0]).toEqual({
|
||||||
|
type: "input_text",
|
||||||
|
text: "start with this context",
|
||||||
|
});
|
||||||
|
expect(content[1]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
type: "input_text",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(String(content[1]?.text ?? "")).toContain("PAPERCLIP_RUN_ID=run-123");
|
||||||
|
});
|
||||||
|
|
||||||
it("fails when SSE endpoint does not return text/event-stream", async () => {
|
it("fails when SSE endpoint does not return text/event-stream", async () => {
|
||||||
const fetchMock = vi.fn().mockResolvedValue(
|
const fetchMock = vi.fn().mockResolvedValue(
|
||||||
new Response(JSON.stringify({ ok: false, error: "unexpected payload" }), {
|
new Response(JSON.stringify({ ok: false, error: "unexpected payload" }), {
|
||||||
|
|||||||
Reference in New Issue
Block a user