mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
fix(sdk): preserve replayed chat snapshots
This commit is contained in:
committed by
Peter Steinberger
parent
10315ce215
commit
63724ddcfd
@@ -6251,6 +6251,7 @@ public struct ChatEvent: Codable, Sendable {
|
||||
public let seq: Int
|
||||
public let state: AnyCodable
|
||||
public let message: AnyCodable?
|
||||
public let deltatext: String?
|
||||
public let errormessage: String?
|
||||
public let errorkind: AnyCodable?
|
||||
public let usage: AnyCodable?
|
||||
@@ -6263,6 +6264,7 @@ public struct ChatEvent: Codable, Sendable {
|
||||
seq: Int,
|
||||
state: AnyCodable,
|
||||
message: AnyCodable?,
|
||||
deltatext: String?,
|
||||
errormessage: String?,
|
||||
errorkind: AnyCodable?,
|
||||
usage: AnyCodable?,
|
||||
@@ -6274,6 +6276,7 @@ public struct ChatEvent: Codable, Sendable {
|
||||
self.seq = seq
|
||||
self.state = state
|
||||
self.message = message
|
||||
self.deltatext = deltatext
|
||||
self.errormessage = errormessage
|
||||
self.errorkind = errorkind
|
||||
self.usage = usage
|
||||
@@ -6287,6 +6290,7 @@ public struct ChatEvent: Codable, Sendable {
|
||||
case seq
|
||||
case state
|
||||
case message
|
||||
case deltatext = "deltaText"
|
||||
case errormessage = "errorMessage"
|
||||
case errorkind = "errorKind"
|
||||
case usage
|
||||
|
||||
@@ -264,6 +264,7 @@ function normalizeChatProjectionEvent(
|
||||
): OpenClawEvent {
|
||||
const text = readChatProjectionText(projection.payload);
|
||||
const deltaText = readChatProjectionDeltaText(projection.payload);
|
||||
const hasPreviousText = previousText !== undefined;
|
||||
const isReplacement = Boolean(
|
||||
deltaText === undefined && previousText && text !== undefined && !text.startsWith(previousText),
|
||||
);
|
||||
@@ -275,7 +276,12 @@ function normalizeChatProjectionEvent(
|
||||
? text !== undefined
|
||||
? {
|
||||
text,
|
||||
delta: deltaText ?? (isReplacement ? text : text.slice(previousText?.length ?? 0)),
|
||||
delta:
|
||||
deltaText !== undefined && hasPreviousText
|
||||
? deltaText
|
||||
: isReplacement
|
||||
? text
|
||||
: text.slice(previousText?.length ?? 0),
|
||||
...(isReplacement ? { replace: true } : {}),
|
||||
}
|
||||
: event.data
|
||||
|
||||
@@ -847,6 +847,60 @@ describe("OpenClaw SDK", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("uses cumulative text for the first replayed chat projection", async () => {
|
||||
const transport = new FakeTransport({});
|
||||
const oc = new OpenClaw({ transport });
|
||||
const runId = "run_chat_delta_text_replay";
|
||||
let text = "";
|
||||
let iterator: AsyncIterator<OpenClawEvent> | undefined;
|
||||
|
||||
try {
|
||||
await oc.connect();
|
||||
const observedLast = (async () => {
|
||||
for await (const event of oc.events(
|
||||
(event) => event.raw?.event === "chat" && event.raw.seq === 501,
|
||||
)) {
|
||||
return event;
|
||||
}
|
||||
throw new Error("expected final replay setup event");
|
||||
})();
|
||||
|
||||
for (let index = 0; index <= 500; index += 1) {
|
||||
const deltaText = index === 0 ? "hello" : ` ${index}`;
|
||||
text += deltaText;
|
||||
transport.emit({
|
||||
event: "chat",
|
||||
seq: index + 1,
|
||||
payload: {
|
||||
runId,
|
||||
sessionKey: "chat-delta-text-replay",
|
||||
state: "delta",
|
||||
deltaText,
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text }],
|
||||
timestamp: 1_777_000_000_300 + index,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await observedLast;
|
||||
const run = await oc.runs.get(runId);
|
||||
iterator = run.events()[Symbol.asyncIterator]();
|
||||
const first = await iterator.next();
|
||||
expect(first.done).toBe(false);
|
||||
if (first.done !== false) {
|
||||
throw new Error("expected first replayed chat projection event");
|
||||
}
|
||||
expect(first.value.type).toBe("assistant.delta");
|
||||
expect(first.value.data).toEqual({ text: "hello 1", delta: "hello 1" });
|
||||
} finally {
|
||||
await iterator?.return?.();
|
||||
await oc.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("creates a session and sends a message as a run", async () => {
|
||||
const transport = new FakeTransport({
|
||||
"sessions.create": { key: "session-main", label: "Main" },
|
||||
|
||||
Reference in New Issue
Block a user