Allow message retries for "pending" status, refactor message context handling, remove workspace import/export routes, and add SQLite-backed rate limiting.
CI / check (22) (push) Failing after 16m26s
CI / check (24) (push) Failing after 15m49s
CI / check (22) (pull_request) Failing after 16m26s
CI / check (24) (pull_request) Failing after 15m50s

This commit is contained in:
2026-10-09 19:28:43 +02:00
parent 8666e09049
commit f67d918d09
13 changed files with 313 additions and 193 deletions
+21 -1
View File
@@ -75,7 +75,7 @@ async function setup(t, {visionResult = null, replyResult = null, visionModel =
const image = format => sharp({create: {width: 20, height: 10, channels: 3, background: "blue"}}).toFormat(format).toBuffer();
const chat = async () => (await (await api("/chats", {title: "Image test"})).json()).chat.id;
return {app, api, upload, image, register, directory, requests, order, searchQueries, chat,
failVision: () => { visionFailure = true; }, holdVision: () => { holdVision = true; return visionStarted; },
failVision: () => { visionFailure = true; }, recoverVision: () => { visionFailure = false; }, holdVision: () => { holdVision = true; return visionStarted; },
get visionAborted() { return visionAborted; }};
}
@@ -239,6 +239,26 @@ test("vision failure prevents an ungrounded answer and malformed JSON falls back
assert.throws(() => parseVisionAnalysis(""));
});
test("resuming a failed image turn reuses its branch node and attachment", async t => {
const s = await setup(t);
const attachment = await (await s.upload(await s.image("png"))).json();
const chatId = await s.chat();
s.failVision();
const failedWire = await (await s.api("/chat/stream", {chatId, message: "Describe the image", attachments: [attachment.id]})).text();
assert.match(failedWire, /event: error/);
const failedMessages = (await (await s.api(`/chats/${chatId}/messages`)).json()).messages;
const interrupted = failedMessages.find(message => message.role === "user");
assert.equal(interrupted.deliveryStatus, "failed");
s.recoverVision();
const resumedWire = await (await s.api("/chat/stream", {chatId, message: interrupted.content,
attachments: [attachment.id], userMessageId: interrupted.id})).text();
assert.match(resumedWire, /event: done/);
const messages = (await (await s.api(`/chats/${chatId}/messages`)).json()).messages;
assert.equal(messages.filter(message => message.role === "user").length, 1);
assert.equal(messages[0].attachments[0].id, attachment.id);
assert.equal(messages[0].deliveryStatus, "complete");
});
test("browser disconnect cancels in-progress vision and never starts the final model", async t => {
const s = await setup(t);
const attachment = await (await s.upload(await s.image("png"))).json();