agents
Version:
A home for your AI agents
225 lines (224 loc) • 7.47 kB
JavaScript
import { t as applyChunkToParts } from "./message-builder-BymO4N_D.js";
//#region src/chat/stream-accumulator.ts
function asMetadata(value) {
if (value != null && typeof value === "object" && !Array.isArray(value)) return value;
}
var StreamAccumulator = class {
constructor(options) {
this.messageId = options.messageId;
this._isContinuation = options.continuation ?? false;
this.parts = options.existingParts ? [...options.existingParts] : [];
this.metadata = options.existingMetadata ? { ...options.existingMetadata } : void 0;
this._pendingContinuationChunks = this._isContinuation && options.existingParts === void 0 && options.existingMetadata === void 0 ? [] : null;
}
applyChunk(chunk) {
this._pendingContinuationChunks?.push(chunk);
const handled = applyChunkToParts(this.parts, chunk);
if (chunk.type === "tool-approval-request" && chunk.toolCallId) return {
handled,
action: {
type: "tool-approval-request",
toolCallId: chunk.toolCallId
}
};
if ((chunk.type === "tool-output-available" || chunk.type === "tool-output-error") && chunk.toolCallId) {
if (!this.parts.some((p) => "toolCallId" in p && p.toolCallId === chunk.toolCallId)) return {
handled,
action: {
type: "cross-message-tool-update",
updateType: chunk.type === "tool-output-available" ? "output-available" : "output-error",
toolCallId: chunk.toolCallId,
output: chunk.output,
errorText: chunk.errorText,
preliminary: chunk.preliminary
}
};
}
if (!handled) switch (chunk.type) {
case "start": {
if (chunk.messageId != null && !this._isContinuation) this.messageId = chunk.messageId;
const startMeta = asMetadata(chunk.messageMetadata);
if (startMeta) this.metadata = this.metadata ? {
...this.metadata,
...startMeta
} : { ...startMeta };
return {
handled: true,
action: {
type: "start",
messageId: chunk.messageId,
metadata: startMeta
}
};
}
case "finish": {
const finishMeta = asMetadata(chunk.messageMetadata);
if (finishMeta) this.metadata = this.metadata ? {
...this.metadata,
...finishMeta
} : { ...finishMeta };
return {
handled: true,
action: {
type: "finish",
finishReason: "finishReason" in chunk ? chunk.finishReason : void 0,
metadata: finishMeta
}
};
}
case "message-metadata": {
const msgMeta = asMetadata(chunk.messageMetadata);
if (msgMeta) this.metadata = this.metadata ? {
...this.metadata,
...msgMeta
} : { ...msgMeta };
return {
handled: true,
action: {
type: "message-metadata",
metadata: msgMeta ?? {}
}
};
}
case "finish-step": return { handled: true };
case "error": return {
handled: true,
action: {
type: "error",
error: chunk.errorText ?? JSON.stringify(chunk)
}
};
}
return { handled };
}
/** Snapshot the current state as a UIMessage. */
toMessage() {
return {
id: this.messageId,
role: "assistant",
parts: [...this.parts],
...this.metadata != null && { metadata: this.metadata }
};
}
/**
* Merge this accumulator's message into an existing message array.
* Handles continuation (walk backward for last assistant), replacement
* (update existing by messageId), or append (new message). An unseeded
* continuation adopts current parts here before applying its queued chunks.
*/
mergeInto(messages) {
let existingIdx = messages.findIndex((m) => m.id === this.messageId);
if (existingIdx < 0 && this._isContinuation) {
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "assistant") {
existingIdx = i;
break;
}
}
if (this._pendingContinuationChunks !== null) {
const pendingChunks = this._pendingContinuationChunks;
this._pendingContinuationChunks = null;
this.parts.splice(0, this.parts.length, ...existingIdx >= 0 ? messages[existingIdx].parts : []);
const currentMetadata = existingIdx >= 0 ? asMetadata(messages[existingIdx].metadata) : void 0;
this.metadata = currentMetadata ? { ...currentMetadata } : void 0;
if (existingIdx >= 0) this.messageId = messages[existingIdx].id;
for (const chunk of pendingChunks) this.applyChunk(chunk);
}
const partialMessage = {
id: existingIdx >= 0 ? messages[existingIdx].id : this.messageId,
role: "assistant",
parts: [...this.parts],
...this.metadata != null && { metadata: this.metadata }
};
if (existingIdx >= 0) {
const updated = [...messages];
updated[existingIdx] = partialMessage;
return updated;
}
return [...messages, partialMessage];
}
};
//#endregion
//#region src/chat/broadcast-state.ts
function transition(state, event) {
switch (event.type) {
case "clear": return {
state: { status: "idle" },
isStreaming: false
};
case "resume-fallback": {
const accumulator = new StreamAccumulator({ messageId: event.messageId });
return {
state: {
status: "observing",
streamId: event.streamId,
accumulator
},
isStreaming: true
};
}
case "response": {
let accumulator;
const isReplayedStart = event.replay === true && event.chunkData?.type === "start";
if (state.status === "idle" || state.streamId !== event.streamId || isReplayedStart) accumulator = new StreamAccumulator({
messageId: event.messageId,
continuation: event.continuation
});
else accumulator = state.accumulator;
if (event.chunkData) accumulator.applyChunk(event.chunkData);
let messagesUpdate;
if (event.done) {
messagesUpdate = (prev) => accumulator.mergeInto(prev);
return {
state: { status: "idle" },
messagesUpdate,
isStreaming: false
};
}
if (event.chunkData && !event.replay) messagesUpdate = (prev) => accumulator.mergeInto(prev);
else if (event.replayComplete) messagesUpdate = (prev) => accumulator.mergeInto(prev);
return {
state: {
status: "observing",
streamId: event.streamId,
accumulator
},
messagesUpdate,
isStreaming: true
};
}
}
}
//#endregion
//#region src/chat/protocol.ts
/**
* Wire protocol message type constants for the cf_agent_chat_* protocol.
*
* These are the string values used on the wire between agent servers and
* clients. Both @cloudflare/ai-chat (via its MessageType enum) and
* @cloudflare/think use these values.
*/
const STREAM_RESUME_NONE_REASONS = {
/** No active, pending, or terminal stream exists for this agent. */
IDLE: "idle",
/** An active tool continuation is owned by another live connection. */
CONTINUATION_OWNED: "continuation-owned"
};
const CHAT_MESSAGE_TYPES = {
CHAT_MESSAGES: "cf_agent_chat_messages",
USE_CHAT_REQUEST: "cf_agent_use_chat_request",
USE_CHAT_RESPONSE: "cf_agent_use_chat_response",
CHAT_CLEAR: "cf_agent_chat_clear",
CHAT_REQUEST_CANCEL: "cf_agent_chat_request_cancel",
STREAM_RESUMING: "cf_agent_stream_resuming",
STREAM_RESUME_ACK: "cf_agent_stream_resume_ack",
STREAM_RESUME_REQUEST: "cf_agent_stream_resume_request",
STREAM_RESUME_NONE: "cf_agent_stream_resume_none",
STREAM_PENDING: "cf_agent_stream_pending",
TOOL_RESULT: "cf_agent_tool_result",
TOOL_APPROVAL: "cf_agent_tool_approval",
MESSAGE_UPDATED: "cf_agent_message_updated",
CHAT_RECOVERING: "cf_agent_chat_recovering"
};
//#endregion
export { StreamAccumulator as i, STREAM_RESUME_NONE_REASONS as n, transition as r, CHAT_MESSAGE_TYPES as t };
//# sourceMappingURL=protocol-B0nh6KNf.js.map