UNPKG

@artinet/sdk

Version:

A TypeScript SDK for building collaborative AI agents.

118 lines (117 loc) 4.25 kB
/** * Copyright 2025 The Artinet Project * SPDX-License-Identifier: Apache-2.0 */ import { getCurrentTimestamp, formatJson } from "../../../utils/utils.js"; import { validateSchema } from "../../../utils/schema-validation.js"; import { upsertArtifact } from "./artifact.js"; import { A2A } from "../../../types/index.js"; import { logger } from "../../../config/index.js"; const isMessageInHistory = (task, message) => { return task.history?.find((msg) => msg.messageId === message.messageId); }; const updateHistory = (task, updateMessage) => { if (!isMessageInHistory(task, updateMessage)) { task.history = [...(task.history ?? []), updateMessage]; } }; export const handleMessageUpdate = async ({ task, update, }) => { const validated = await validateSchema(A2A.MessageSchema, update); if (validated.taskId && task.id !== validated.taskId) { throw new Error(`updateMessage: Invalid task id: incoming: ${validated.taskId} expected: ${task.id} ${formatJson({ cause: { validated, actual: task.id, task, }, })}`); } updateHistory(task, validated); return task; }; export const handleTaskUpdate = async ({ context, task, update, }) => { const validated = await validateSchema(A2A.TaskSchema, update); if (task.id !== validated.id) { throw new Error(`updateTask: Invalid task id: incoming: ${validated.id} expected: ${task.id}`, { cause: validated, }); } task = { ...task, ...validated }; if (context.userMessage) { updateHistory(task, context.userMessage); } return task; }; export const handleStatusUpdate = async ({ task, update, }) => { const validated = await validateSchema(A2A.TaskStatusUpdateEventSchema, update); if (validated.taskId && task.id !== validated.taskId) { throw new Error(`updateTaskStatusUpdate: Invalid task id: incoming: ${validated.taskId} expected: ${task.id}`, { cause: validated }); } task.status = validated.status; task.status.timestamp = getCurrentTimestamp(); if (validated.status.message) { updateHistory(task, validated.status.message); } return task; }; export const handleArtifactUpdate = async ({ task, update }) => { const validated = await validateSchema(A2A.TaskArtifactUpdateEventSchema, update); if (validated.taskId && task.id !== validated.taskId) { throw new Error(`updateTaskArtifactUpdate: Invalid task id: incoming: ${validated.taskId} expected: ${task.id}`, { cause: validated, }); } validated.taskId = task.id; task.artifacts = upsertArtifact(task.artifacts ?? [], validated); return task; }; // The onus is now on the caller to handle errors when processing updates // and to decide whether the updated task should be saved or not export const handleUpdate = async ({ context, task, update, }) => { if (!update || !update.kind) { throw new Error("updateState: Invalid update", { cause: update }); } logger.debug(`handleUpdate:`, { contextId: context?.contextId, taskId: task?.id, }); task = await validateSchema(A2A.TaskSchema, task); if (!context || !context.contextId) { throw new Error("updateState: Invalid context", { cause: context }); } switch (update.kind) { case A2A.Kind.message: { return handleMessageUpdate({ context, task, update, }); } case A2A.Kind.task: { return handleTaskUpdate({ context, task, update, }); } case A2A.Kind["status-update"]: { return handleStatusUpdate({ context, task, update, }); } case A2A.Kind["artifact-update"]: { return handleArtifactUpdate({ context, task, update, }); } default: { throw new Error(`updateState: Invalid update kind: {"kind": "unknown"}`, { cause: update, }); } } };