import { EventType, type BaseEvent } from "@ag-ui/core";
import type { ArtifactSummary } from "@datafoundry/contracts";
import { randomUUID } from "node:crypto";
import type { AgentRunContext } from "./types.js";
export type JsonPatchOperation = {
op: "add" | "replace" | "remove";
path: string;
value?: unknown;
};
export const createActivitySnapshot = (
context: AgentRunContext,
activityType: string,
content: Record<string, unknown>,
replace = true
): BaseEvent => ({
type: EventType.ACTIVITY_SNAPSHOT,
messageId: activityMessageId(context, activityType, content),
activityType,
content,
replace,
timestamp: Date.now()
});
export const createActivityDelta = (
context: AgentRunContext,
activityType: string,
patch: JsonPatchOperation[],
content: Record<string, unknown> = {}
): BaseEvent => ({
type: EventType.ACTIVITY_DELTA,
messageId: activityMessageId(context, activityType, content),
activityType,
patch,
timestamp: Date.now()
});
export const createCustomEvent = (name: string, value: unknown): BaseEvent => ({
type: EventType.CUSTOM,
name,
value,
timestamp: Date.now()
});
export const createToolCallResult = (
toolCallId: string,
toolCallName: string,
content: string,
): BaseEvent => ({
type: EventType.TOOL_CALL_RESULT,
toolCallId,
toolCallName,
content,
messageId: randomUUID(),
role: "tool",
timestamp: Date.now()
});
export const createArtifactEvent = (artifact: ArtifactSummary & {
download_url?: string;
file_id?: string;
logical_key?: string;
version?: number;
}): BaseEvent =>
createCustomEvent("artifact", {
id: artifact.id,
type: artifact.type,
name: artifact.name,
title: artifact.name,
summary: artifactEventSummary(artifact),
preview_available: artifact.preview_json !== undefined || Boolean(artifact.file_id),
...(artifact.preview_json !== undefined ? { preview_json: artifact.preview_json } : {}),
...(artifact.download_url ? { download_url: artifact.download_url } : {}),
...(artifact.file_id ? { file_id: artifact.file_id } : {}),
...(artifact.run_id ? { run_id: artifact.run_id } : {}),
...(artifact.tool_call_id ? { tool_call_id: artifact.tool_call_id } : {}),
...(artifact.step_id ? { step_id: artifact.step_id } : {}),
...(artifact.logical_key ? { logical_key: artifact.logical_key } : {}),
...(artifact.version !== undefined ? { version: artifact.version } : {})
});
const artifactEventSummary = (artifact: ArtifactSummary): string => {
if (artifact.type === "table" && isRecord(artifact.preview_json)) {
const rowCount = numberField(artifact.preview_json, "row_count");
if (rowCount !== undefined) {
return `Dataset, ${rowCount.toLocaleString()} rows`;
}
}
return `${artifact.type} artifact`;
};
const activityMessageId = (
context: AgentRunContext,
activityType: string,
content: Record<string, unknown>
): string => {
const normalizedActivityType = activityType.toLowerCase();
const stepId = typeof content.step_id === "string" && normalizedActivityType === "step" ? `:${content.step_id}` : "";
return `${context.run_id}:activity:${normalizedActivityType}${stepId}`;
};
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;
const numberField = (record: Record<string, unknown>, key: string): number | undefined => {
const value = record[key];
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
};