UNPKG

@artinet/sdk

Version:

A TypeScript SDK for building collaborative AI agents.

332 lines (331 loc) 10.8 kB
/** * Copyright 2025 The Artinet Project * SPDX-License-Identifier: Apache-2.0 */ /** * @fileoverview A2A Agent Builder and Execution Engine Factory * * This module provides a fluent builder API for constructing A2A agents and * execution engines. It enables declarative definition of multi-step agent * workflows with type-safe step composition and automatic execution orchestration. * * **Key Features:** * - Fluent API with method chaining (`.text()`, `.data()`, `.file()`, etc.) * - Type-safe argument passing between steps via `args` carry pattern * - Multiple output types: text, file, data, message, artifact, status, task * - Agent-to-agent orchestration via `.sendMessage()` * - Static value shortcuts for simple steps * - Step skipping via `skip()` function * * **Basic Usage:** * ```typescript * import { cr8 } from "@artinet/sdk"; * * const agent = cr8("MyAgent") * .text(({ content }) => `You said: ${content}`) * .data(({ content }) => ({ length: content?.length })) * .agent; * ``` * * @module A2ABuilder * @version 0.6 * @since 0.5.6 * @author The Artinet Project */ import { A2A } from "../types/index.js"; import * as A from './agent-builder.js'; import { ServiceParams } from '../services/a2a/factory/service.js'; import { MessageParams } from './message-builder.js'; import { StatusUpdateParams, ArtifactUpdateParams, TaskParams } from './task-builder.js'; import { ServerParams as BaseServerParams } from "../server/params.js"; export interface MessageSender { sendMessage(params: A2A.MessageSendParams): Promise<A2A.SendMessageSuccessResult>; } /** * Type alias for text-based workflow steps. * * This type represents a step that processes or generates text content * within an agent workflow. Text steps are the most common type of step * and are used for message processing, content generation, and text-based * decision making. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Simple text return * const greetingStep: textStep = async ({ content }) => { * return `Hello! You said: ${content}`; * }; * * // With carry args for next step * const analyzeStep: textStep = async ({ content }) => { * return { * reply: `Analyzed: ${content}`, * args: { sentiment: 'positive', length: content?.length ?? 0 } * }; * }; * ``` * * @public * @since 0.5.6 */ export type textStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A2A.TextPart['text'], Input, Carry>; /** * Type alias for file-based workflow steps. * * This type represents a step that processes or generates file content * within an agent workflow. File steps handle document processing, * file generation, and file-based data operations. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Return file with URI * const downloadStep: fileStep = async ({ content }) => { * return { uri: `https://example.com/files/${content}.pdf` }; * }; * * // Return file with bytes * const generateStep: fileStep = async ({ args }) => { * return { * name: 'report.pdf', * mimeType: 'application/pdf', * bytes: generatePDF(args?.data) * }; * }; * * // Return multiple files * const batchStep: fileStep = async () => { * return [ * { uri: 'https://example.com/file1.pdf' }, * { uri: 'https://example.com/file2.pdf' } * ]; * }; * ``` * * @public * @since 0.5.6 */ export type fileStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A2A.FilePart['file'], Input, Carry>; /** * Type alias for data-based workflow steps. * * This type represents a step that processes or generates structured data * within an agent workflow. Data steps handle JSON processing, API responses, * and structured data transformations. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Return structured data * const analyzeStep: dataStep = async ({ content }) => { * const analysis = await analyzeMessage(content); * return { * sentiment: analysis.sentiment, * entities: analysis.entities, * confidence: analysis.confidence * }; * }; * * // With carry args * const processStep: dataStep = async ({ args }) => { * return { * reply: { processed: true, input: args?.rawData }, * args: { processedAt: Date.now() } * }; * }; * ``` * * @public * @since 0.5.6 */ export type dataStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A2A.DataPart['data'], Input, Carry>; /** * Type alias for message-based workflow steps. * * This type represents a step that constructs or transforms complete A2A messages. * Message steps are useful when you need full control over the message structure, * including role, parts, and metadata. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Return a string (auto-converted to message) * const simpleStep: messageStep = async () => { * return "Hello from the agent!"; * }; * * // Return a full message object * const fullStep: messageStep = async ({ context }) => { * return { * role: "agent", * parts: [ * { kind: "text", text: "Here is your report:" }, * { kind: "file", file: { uri: "https://example.com/report.pdf" } } * ] * }; * }; * ``` * * @public * @since 0.6.0 */ export type messageStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A.Stateless<MessageParams>, Input, Carry>; /** * Type alias for artifact-based workflow steps. * * This type represents a step that creates or updates artifacts within an agent * workflow. Artifacts are persistent, versioned outputs that can be referenced * across task sessions - useful for documents, generated files, or any content * that should be retrievable later. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Create an artifact * const createArtifact: artifactStep = async ({ context, args }) => { * return { * artifactId: `report-${context.taskId}`, * name: "Analysis Report", * parts: [{ kind: "text", text: args?.analysisResult }] * }; * }; * * // Using describe helper * const helperStep: artifactStep = async ({ context }) => { * return describe.artifact({ * artifactId: context.taskId, * parts: [{ kind: "text", text: "Generated content" }] * }); * }; * ``` * * @public * @since 0.6.0 */ export type artifactStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A.Stateless<ArtifactUpdateParams>, Input, Carry>; /** * Type alias for status update workflow steps. * * This type represents a step that emits task status updates within an agent * workflow. Status steps are useful for communicating progress, state changes, * or intermediate results to the client during long-running operations. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Simple status string * const progressStep: statusStep = async () => { * return "working"; * }; * * // Status with message * const detailedStep: statusStep = async ({ args }) => { * return { * status: { * state: A2A.TaskState.working, * message: describe.message(`Processing step ${args?.step} of 5...`) * } * }; * }; * * // Mark completion * const completeStep: statusStep = async () => { * return { status: { state: A2A.TaskState.completed } }; * }; * ``` * * @public * @since 0.6.0 */ export type statusStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A.Stateless<StatusUpdateParams>, Input, Carry>; /** * Type alias for task-based workflow steps. * * This type represents a step that creates or manipulates complete A2A tasks. * Task steps provide full control over the task object, including status, * artifacts, and history. Useful for complex orchestration scenarios or * when you need to return a complete task representation. * * @template Input - Arguments received from previous step * @template Carry - Arguments passed to next step * * @example * ```typescript * // Return task from string * const simpleTask: taskStep = async () => { * return "Task completed successfully"; * }; * * // Return full task object * const fullTask: taskStep = async ({ context, args }) => { * return describe.task({ * id: context.taskId, * contextId: context.contextId, * status: { state: A2A.TaskState.completed }, * artifacts: [args?.generatedArtifact] * }); * }; * * // With carry for chaining * const chainTask: taskStep = async ({ context }) => { * const task = describe.task({ id: context.taskId }); * return { reply: task, args: { taskSnapshot: task } }; * }; * ``` * * @public * @since 0.6.0 */ export type taskStep<Input extends A.bargs = A.empty, Carry extends A.bargs = A.empty> = A.Step<A.Stateless<TaskParams>, Input, Carry>; export type FactoryParams<ServerParams extends BaseServerParams = BaseServerParams> = Omit<ServiceParams, 'engine' | 'agentCard'> & Omit<ServerParams, 'agent'>; /** * Creates an agent execution engine from a list of workflow steps. * * This function transforms a list of resolved step definitions into an executable * A2A engine that processes contexts through the defined workflow. The engine * is an async generator that yields updates as each step completes. * * **Execution Flow:** * 1. Yields "submitted" status update * 2. Executes each step in order, yielding transformed results * 3. Passes carried args from one step to the next * 4. Yields final task on completion * * @param stepsList - Array of resolved workflow steps (from AgentFactory.steps) * @returns A2A.Engine async generator function * @throws Error if stepsList is empty * * @example * ```typescript * // Typically accessed via AgentFactory * const engine = cr8("MyAgent") * .text("Hello") * .data({ timestamp: Date.now() }) * .engine; * * // Or create manually from steps * const engine = createStepEngine(factory.steps); * * // Execute the engine * for await (const update of engine(context)) { * console.log(update.kind, update); * } * ``` * * @public * @since 0.5.6 */ export declare function createStepEngine(stepsList: A.Resolved[]): A2A.Engine;