mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-20 00:12:50 +00:00
* refactor(packaging): reorganize published packages * fix(packaging): install AgentScope extra in wheel smoke * docs: align package guides and documentation site * ci(workflow): add core dependency verification step in Python package build - Add a workflow step to verify released core dependencies by installing the wheel with core extras - Assert the presence of the static index.html file to ensure proper package contents - Create and use a temporary virtual environment for isolation during verification - Keep existing artifacts upload step intact and conditional on inputs.upload_artifacts flag * fix(ci): update package installation dependencies in Windows workflow - Change pip install from editable reme_studio and core to only dev and as extras - Remove installation of reme_studio and core to streamline dependency setup - Ensure Windows CI uses the correct extras for testing environment * fix(tests): add missing commas in toml file reads in package version tests - Added trailing commas in the tomllib.loads calls for auto-fin and daily_paper configs - Ensured consistent syntax to prevent potential tuple misinterpretation - Improved readability and correctness of the test setup code * fix(packaging): protect qwenpaw releases and test Studio health
165 lines
4.1 KiB
JavaScript
165 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import {
|
|
applyStreamChunk,
|
|
chatStreamError,
|
|
decodeSseEvent,
|
|
} from "../app/chat-stream.ts";
|
|
|
|
const initial = () => ({
|
|
id: "assistant",
|
|
role: "assistant",
|
|
content: "",
|
|
blocks: [],
|
|
});
|
|
const chunk = (chunk_type, value = "", extra = {}) => ({
|
|
chunk_type,
|
|
chunk: value,
|
|
done: false,
|
|
...extra,
|
|
});
|
|
|
|
test("chat chunks retain arrival order and correlate tool results", () => {
|
|
let message = initial();
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("think", "checking", { block_id: "thought-1" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("tool_call", '{"path":"daily"}', {
|
|
tool_call_id: "tool-1",
|
|
tool_call_name: "search",
|
|
}),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("tool_result", ["daily/today.md"], { tool_call_id: "tool-1" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("content", "Found it.", { block_id: "answer-1" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk(
|
|
"data",
|
|
{ matches: 1 },
|
|
{ block_id: "data-1", media_type: "application/json" },
|
|
),
|
|
);
|
|
|
|
assert.deepEqual(
|
|
message.blocks.map((block) => block.type),
|
|
["think", "tool", "content", "data"],
|
|
);
|
|
assert.equal(message.blocks[1].name, "search");
|
|
assert.deepEqual(message.blocks[1].resultPayloads, [["daily/today.md"]]);
|
|
assert.equal(message.blocks[2].text, "Found it.");
|
|
});
|
|
|
|
test("reply completion collapses every non-text block", () => {
|
|
let message = initial();
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("think", "done", { block_id: "thought-1" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("usage", "", { input_tokens: 12, output_tokens: 4 }),
|
|
);
|
|
assert.ok(
|
|
message.blocks.every(
|
|
(block) =>
|
|
block.type === "content" || block.type === "error" || block.expanded,
|
|
),
|
|
);
|
|
|
|
message = applyStreamChunk(message, chunk("reply_end"));
|
|
assert.ok(
|
|
message.blocks.every(
|
|
(block) =>
|
|
block.type === "content" || block.type === "error" || !block.expanded,
|
|
),
|
|
);
|
|
assert.ok(
|
|
message.blocks.every(
|
|
(block) =>
|
|
block.type === "content" ||
|
|
block.type === "error" ||
|
|
block.status === "done",
|
|
),
|
|
);
|
|
});
|
|
|
|
test("reply completion restores the final answer when content deltas were missed", () => {
|
|
let message = initial();
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("think", "checking", { block_id: "thought-1" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("reply_end", "", { metadata: { answer: "Final answer." } }),
|
|
);
|
|
|
|
assert.equal(message.blocks.at(-1).type, "content");
|
|
assert.equal(message.blocks.at(-1).text, "Final answer.");
|
|
assert.equal(message.blocks[0].status, "done");
|
|
});
|
|
|
|
test("content deltas with the same block id are combined", () => {
|
|
let message = initial();
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("content", "Hello", { block_id: "answer" }),
|
|
);
|
|
message = applyStreamChunk(
|
|
message,
|
|
chunk("content", " world", { block_id: "answer" }),
|
|
);
|
|
|
|
assert.equal(message.blocks.length, 1);
|
|
assert.equal(message.blocks[0].text, "Hello world");
|
|
});
|
|
|
|
test("SSE terminal marker becomes an explicit done chunk", () => {
|
|
assert.deepEqual(decodeSseEvent("data:[DONE]"), {
|
|
chunk_type: "done",
|
|
chunk: "",
|
|
done: true,
|
|
});
|
|
assert.deepEqual(
|
|
decodeSseEvent('data:{"chunk_type":"content","chunk":"hi","done":false}'),
|
|
{
|
|
chunk_type: "content",
|
|
chunk: "hi",
|
|
done: false,
|
|
},
|
|
);
|
|
});
|
|
|
|
test("an aborted stream finishes without showing an error", async () => {
|
|
const controller = new AbortController();
|
|
controller.abort();
|
|
|
|
const error = await chatStreamError(
|
|
() => Promise.reject(new DOMException("Aborted", "AbortError")),
|
|
controller.signal,
|
|
"Chat failed",
|
|
);
|
|
|
|
assert.equal(error, undefined);
|
|
});
|
|
|
|
test("a failed stream returns its error message", async () => {
|
|
const controller = new AbortController();
|
|
|
|
const error = await chatStreamError(
|
|
() => Promise.reject(new Error("Connection lost")),
|
|
controller.signal,
|
|
"Chat failed",
|
|
);
|
|
|
|
assert.equal(error, "Connection lost");
|
|
});
|