Accept image input and regenerate
Use this recipe when an Agent should interpret an image and an End-user may ask it to regenerate the stored response. Image input is a chat message part, not general-purpose file upload or Artifact ingestion.
Outcome
One image-bearing message creates a Session, then a verified assistant message ID triggers truncate-and-rerun in that same authorized Session. The replacement is proven by reading the stored transcript.
Before you begin
Create a backend SDK client and authorize the Agent and application chat as in Build a chat endpoint. Review Sessions and Turns, Generation and streaming, Files and outputs, and Security and credentials.
Send an image part
A submitted message must be a user UIMessage with a non-empty ID and only
text or image file parts. An image part uses type: "file", a non-empty
url, an image/... mediaType, and an optional non-empty filename.
Other file media types and arbitrary file-operation input are rejected.
import { BlazingAgents, type UIMessage } from "@blazing-agents/sdk";
const client = new BlazingAgents({ apiKey: process.env.BLAZING_AGENTS_API_KEY! });
const message: UIMessage = { id: "image-question-1", role: "user", parts: [
{ type: "text", text: "Describe this image." },
{ type: "file", mediaType: "image/png", filename: "sample.png",
url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" },
] };
const first = await client.chat({ agentId, message, userId });
const sessionId = await first.sessionId;
for await (const _chunk of first.toUIMessageStream()) { /* drain */ }
const before = await client.sessions.messages(agentId, sessionId);
const original = before.data.find(item => item.role === "assistant");
if (!original) throw new Error("No stored assistant response");
const retry = await client.chat({ agentId, sessionId, message,
trigger: "regenerate-message", messageId: original.id, userId });
for await (const _chunk of retry.toUIMessageStream()) { /* drain */ }
const after = await client.sessions.messages(agentId, sessionId);
const [retainedUser, replacement] = after.data;
const validBranch = await retry.sessionId === sessionId &&
after.data.length === 2 && retainedUser?.id === message.id &&
retainedUser?.role === "user" && replacement?.role === "assistant" &&
replacement.id !== original.id &&
!after.data.some(item => item.id === original.id);
if (!validBranch) {
throw new Error("The response was not replaced in the same Session");
}Store the response
Drain the first stream so a successful Turn can commit. Store the resolved
sessionId in the authorized application chat, then read
sessions.messages() to retain the stored assistant message ID. Message
listing returns newest pages first but keeps messages chronological within
each page.
Regenerate a response
Regeneration is valid only on the resume path. Send
trigger: "regenerate-message" with the authorized sessionId, the
original user message, and a messageId verified from that Session. When
the ID names the assistant response, the platform truncates from that
message onward, retains the preceding user message, and appends a new
assistant response. Omitting messageId targets the latest assistant
message.
Verify the transcript
The example requires the regeneration result to resolve the same
sessionId. It also asserts that the original user message remains exactly
once, the old assistant ID is absent, and a required replacement assistant
appears after the user message. This verifies transcript state rather than
only HTTP success.
Production notes
- Validate media type, URL source, and application upload limits before constructing the message. The chat contract itself requires an image media type and non-empty URL but does not place arbitrary files in an attached Sandbox filesystem.
- Authorize the Agent, Session, and target message in backend state. A
messageIdoutside that Session returnsnot_found. - Truncation and replacement commit together only when regeneration succeeds. A failed or aborted regeneration leaves the previous transcript unchanged.
- If you target a user message instead of its assistant response, truncation also removes that user event and the supplied message is appended again.