mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-24 16:32:29 +00:00
fix(acp): preserve hidden thought chunks from gateway chat
This commit is contained in:
@@ -194,6 +194,49 @@ describe("acp translator cancel and run scoping", () => {
|
||||
await expect(pending.promptPromise).resolves.toEqual({ stopReason: "end_turn" });
|
||||
});
|
||||
|
||||
it("projects gateway thinking blocks into hidden ACP thought chunks", async () => {
|
||||
const sessionKey = "agent:main:shared";
|
||||
const harness = createHarness([{ sessionId: "session-1", sessionKey }]);
|
||||
const pending = await startPendingPrompt(harness, "session-1");
|
||||
harness.sessionUpdateSpy.mockClear();
|
||||
|
||||
await harness.agent.handleGatewayEvent(
|
||||
createChatEvent({
|
||||
runId: pending.runId,
|
||||
sessionKey,
|
||||
seq: 1,
|
||||
state: "delta",
|
||||
message: {
|
||||
content: [
|
||||
{ type: "thinking", thinking: "Internal loop about NO_REPLY" },
|
||||
{ type: "text", text: "Final visible reply" },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(harness.sessionUpdateSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
sessionId: "session-1",
|
||||
update: expect.objectContaining({
|
||||
sessionUpdate: "agent_thought_chunk",
|
||||
content: { type: "text", text: "Internal loop about NO_REPLY" },
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(harness.sessionUpdateSpy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({
|
||||
sessionId: "session-1",
|
||||
update: expect.objectContaining({
|
||||
sessionUpdate: "agent_message_chunk",
|
||||
content: { type: "text", text: "Final visible reply" },
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("drops tool events when runId does not match the active prompt", async () => {
|
||||
const sessionKey = "agent:main:shared";
|
||||
const harness = createHarness([{ sessionId: "session-1", sessionKey }]);
|
||||
|
||||
@@ -68,6 +68,8 @@ type PendingPrompt = {
|
||||
reject: (err: Error) => void;
|
||||
sentTextLength?: number;
|
||||
sentText?: string;
|
||||
sentThoughtLength?: number;
|
||||
sentThought?: string;
|
||||
toolCalls?: Map<string, PendingToolCall>;
|
||||
};
|
||||
|
||||
@@ -126,6 +128,12 @@ type GatewayTranscriptMessage = {
|
||||
content?: unknown;
|
||||
};
|
||||
|
||||
type GatewayChatContentBlock = {
|
||||
type?: string;
|
||||
text?: string;
|
||||
thinking?: string;
|
||||
};
|
||||
|
||||
const SESSION_CREATE_RATE_LIMIT_DEFAULT_MAX_REQUESTS = 120;
|
||||
const SESSION_CREATE_RATE_LIMIT_DEFAULT_WINDOW_MS = 10_000;
|
||||
|
||||
@@ -834,22 +842,44 @@ export class AcpGatewayAgent implements Agent {
|
||||
sessionId: string,
|
||||
messageData: Record<string, unknown>,
|
||||
): Promise<void> {
|
||||
const content = messageData.content as Array<{ type: string; text?: string }> | undefined;
|
||||
const fullText = content?.find((c) => c.type === "text")?.text ?? "";
|
||||
const content = messageData.content as GatewayChatContentBlock[] | undefined;
|
||||
const pending = this.pendingPrompts.get(sessionId);
|
||||
if (!pending) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullThought = content
|
||||
?.filter((block) => block?.type === "thinking")
|
||||
.map((block) => block.thinking ?? "")
|
||||
.join("\n")
|
||||
.trimEnd();
|
||||
const sentThoughtSoFar = pending.sentThoughtLength ?? 0;
|
||||
if (fullThought && fullThought.length > sentThoughtSoFar) {
|
||||
const newThought = fullThought.slice(sentThoughtSoFar);
|
||||
pending.sentThoughtLength = fullThought.length;
|
||||
pending.sentThought = fullThought;
|
||||
await this.connection.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "agent_thought_chunk",
|
||||
content: { type: "text", text: newThought },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const fullText = content
|
||||
?.filter((block) => block?.type === "text")
|
||||
.map((block) => block.text ?? "")
|
||||
.join("\n")
|
||||
.trimEnd();
|
||||
const sentSoFar = pending.sentTextLength ?? 0;
|
||||
if (fullText.length <= sentSoFar) {
|
||||
if (!fullText || fullText.length <= sentSoFar) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newText = fullText.slice(sentSoFar);
|
||||
pending.sentTextLength = fullText.length;
|
||||
pending.sentText = fullText;
|
||||
|
||||
await this.connection.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
|
||||
Reference in New Issue
Block a user