diff --git a/typescript/src/contracts/AgentExceptions.ts b/typescript/src/contracts/AgentExceptions.ts index c902241974c..90596baf528 100644 --- a/typescript/src/contracts/AgentExceptions.ts +++ b/typescript/src/contracts/AgentExceptions.ts @@ -1,32 +1,68 @@ +/** + * Base class for all agent-related exceptions. + */ export class AgentException extends Error { + /** + * Creates a new instance of the AgentException class. + * @param message Optional error message + */ constructor(message?: string) { super(message); this.name = "AgentException"; } } +/** + * Exception thrown when a handler cannot process the given message. + */ export class CantHandleException extends AgentException { + /** + * Creates a new instance of the CantHandleException class. + * @param message Optional custom error message + */ constructor(message?: string) { super(message || "The handler cannot process the given message."); this.name = "CantHandleException"; } } +/** + * Exception thrown when a message cannot be delivered. + */ export class UndeliverableException extends AgentException { + /** + * Creates a new instance of the UndeliverableException class. + * @param message Optional custom error message + */ constructor(message?: string) { super(message || "The message cannot be delivered."); this.name = "UndeliverableException"; } } +/** + * Exception thrown when a message is dropped. + */ export class MessageDroppedException extends AgentException { + /** + * Creates a new instance of the MessageDroppedException class. + * @param message Optional custom error message + */ constructor(message?: string) { super(message || "The message was dropped."); this.name = "MessageDroppedException"; } } +/** + * Exception thrown when an attempt is made to access an unavailable value, + * such as a remote resource. + */ export class NotAccessibleError extends AgentException { + /** + * Creates a new instance of the NotAccessibleError class. + * @param message Optional custom error message + */ constructor(message?: string) { super(message || "The requested value is not accessible."); this.name = "NotAccessibleError"; diff --git a/typescript/src/contracts/AgentMetadata.ts b/typescript/src/contracts/AgentMetadata.ts index d77dd099385..b6b9e07147d 100644 --- a/typescript/src/contracts/AgentMetadata.ts +++ b/typescript/src/contracts/AgentMetadata.ts @@ -1,5 +1,21 @@ +/** + * Represents metadata associated with an agent, including its type, unique key, and description. + */ export interface AgentMetadata { + /** + * An identifier that associates an agent with a specific factory function. + * Strings may only be composed of alphanumeric letters (a-z, 0-9), or underscores (_). + */ type: string; + + /** + * A unique key identifying the agent instance. + * Strings may only be composed of alphanumeric letters (a-z, 0-9), or underscores (_). + */ key: string; + + /** + * A brief description of the agent's purpose or functionality. + */ description?: string; } \ No newline at end of file diff --git a/typescript/src/contracts/AgentProxy.ts b/typescript/src/contracts/AgentProxy.ts index 146b94fed9e..2be7b481ac4 100644 --- a/typescript/src/contracts/AgentProxy.ts +++ b/typescript/src/contracts/AgentProxy.ts @@ -1,18 +1,44 @@ import { IAgentRuntime, AgentId } from "./IAgentRuntime"; +/** + * A helper class that allows you to use an AgentId in place of its associated IAgent. + */ export class AgentProxy { + /** + * Gets the target agent for this proxy. + */ public readonly agentId: AgentId; + + /** + * The runtime instance used to interact with agents. + */ private runtime: IAgentRuntime; + /** + * Creates a new instance of the AgentProxy class. + * @param agentId The ID of the agent to proxy + * @param runtime The runtime instance to use for agent interactions + */ constructor(agentId: AgentId, runtime: IAgentRuntime) { this.agentId = agentId; this.runtime = runtime; } + /** + * Gets the metadata of the agent. + * @returns A promise that resolves to the agent's metadata + */ async getMetadata(): Promise { return this.runtime.getAgentMetadataAsync(this.agentId); } + /** + * Sends a message to the agent and processes the response. + * @param message The message to send to the agent + * @param sender The agent that is sending the message + * @param messageId The message ID. If null, a new message ID will be generated + * @returns A promise resolving to the response from the agent + */ async sendMessageAsync( message: unknown, sender?: AgentId, @@ -21,10 +47,18 @@ export class AgentProxy { return this.runtime.sendMessageAsync(message, this.agentId, sender, messageId); } + /** + * Loads the saved state into the agent. + * @param state A dictionary representing the state of the agent + */ async loadStateAsync(state: unknown): Promise { return this.runtime.loadAgentStateAsync(this.agentId, state); } + /** + * Saves the state of the agent. + * @returns A promise resolving to a dictionary containing the saved state + */ async saveStateAsync(): Promise { return this.runtime.saveAgentStateAsync(this.agentId); } diff --git a/typescript/src/contracts/AgentType.ts b/typescript/src/contracts/AgentType.ts index 7ef8378911f..983b96653e1 100644 --- a/typescript/src/contracts/AgentType.ts +++ b/typescript/src/contracts/AgentType.ts @@ -1 +1,5 @@ +/** + * Represents the type of an agent as a string. + * This is a strongly-typed wrapper around a string, ensuring type safety when working with agent types. + */ export type AgentType = string; \ No newline at end of file diff --git a/typescript/src/contracts/IAgent.ts b/typescript/src/contracts/IAgent.ts index 82bb35d53ad..1c9ee0bda86 100644 --- a/typescript/src/contracts/IAgent.ts +++ b/typescript/src/contracts/IAgent.ts @@ -1,8 +1,36 @@ import { AgentId } from "./IAgentRuntime"; +/** + * Represents an agent within the runtime that can process messages, maintain state, + * and be closed when no longer needed. + */ export interface IAgent { + /** + * Gets the unique identifier of the agent. + */ readonly id: AgentId; + + /** + * Handles an incoming message for the agent. + * This should only be called by the runtime, not by other agents. + * @param message The received message. The type should match one of the expected subscription types. + * @param context The context of the message, providing additional metadata. + * @returns A promise resolving to a response to the message. Can be null if no reply is necessary. + * @throws {CantHandleException} If the agent cannot handle the message. + * @throws {OperationCanceledException} If the message was cancelled. + */ onMessageAsync(message: unknown, context: unknown): Promise; + + /** + * Saves the state of the agent. The result must be JSON serializable. + * @returns A promise resolving to a dictionary containing the saved state. + */ saveStateAsync(): Promise; + + /** + * Loads the saved state into the agent. + * @param state The state to restore. + * @returns A promise that completes when the state has been loaded. + */ loadStateAsync(state: unknown): Promise; } \ No newline at end of file diff --git a/typescript/src/contracts/IAgentRuntime.ts b/typescript/src/contracts/IAgentRuntime.ts index 0ac7b308a58..270e2fffba1 100644 --- a/typescript/src/contracts/IAgentRuntime.ts +++ b/typescript/src/contracts/IAgentRuntime.ts @@ -2,23 +2,40 @@ import { AgentType } from "./AgentType"; import { IAgent } from "./IAgent"; import { ISubscriptionDefinition } from "./ISubscriptionDefinition"; +/** + * Represents a unique identifier for an agent instance. + */ export interface AgentId { + /** The type of agent */ type: string; + /** Unique key identifying this agent instance */ key: string; } +/** + * Represents a topic identifier for message routing. + */ export interface TopicId { + /** The type of topic */ type: string; + /** The source of the topic */ source: string; } -// Remove this interface as it's defined in ISubscriptionDefinition.ts -// export interface ISubscriptionDefinition { -// type: string; -// agentType: string; -// } - +/** + * Defines the runtime environment for agents, managing message sending, subscriptions, + * agent resolution, and state persistence. + */ export interface IAgentRuntime { + /** + * Publishes a message to all agents subscribed to the given topic. + * No responses are expected from publishing. + * @param message The message to publish + * @param topic The topic to publish the message to + * @param sender The agent sending the message + * @param messageId A unique message ID. If null, a new one will be generated + * @throws {UndeliverableException} If the message cannot be delivered + */ publishMessageAsync( message: unknown, topic: TopicId, @@ -26,6 +43,16 @@ export interface IAgentRuntime { messageId?: string ): Promise; + /** + * Sends a message to an agent and gets a response. + * @param message The message to send + * @param recipient The agent to send the message to + * @param sender The agent sending the message + * @param messageId A unique message ID. If null, a new one will be generated + * @returns A promise resolving to the response from the agent + * @throws {UndeliverableException} If the message cannot be delivered + * @throws {CantHandleException} If the recipient cannot handle the message + */ sendMessageAsync( message: unknown, recipient: AgentId, @@ -33,20 +60,50 @@ export interface IAgentRuntime { messageId?: string ): Promise; + /** + * Retrieves metadata for an agent. + * @param agentId The ID of the agent + * @returns A promise resolving to the agent's metadata + */ getAgentMetadataAsync(agentId: AgentId): Promise; + /** + * Loads a previously saved state into an agent. + * @param agentId The ID of the agent whose state is being restored + * @param state The state to restore + */ loadAgentStateAsync(agentId: AgentId, state: unknown): Promise; + + /** + * Saves the state of an agent. + * @param agentId The ID of the agent whose state is being saved + * @returns A promise resolving to the saved state + */ saveAgentStateAsync(agentId: AgentId): Promise; + /** + * Registers an agent factory with the runtime. + * @param type The agent type to associate with the factory + * @param factoryFunc A function that creates the agent instance + * @returns The registered agent type + */ registerAgentFactoryAsync( type: AgentType, factoryFunc: (agentId: AgentId, runtime: IAgentRuntime) => Promise ): Promise; + /** + * Adds a new subscription for the runtime to handle when processing published messages. + * @param subscription The subscription to add + */ addSubscriptionAsync(subscription: ISubscriptionDefinition): Promise; + /** + * Removes a subscription from the runtime. + * @param subscriptionId The unique identifier of the subscription to remove + * @throws {Error} If the subscription does not exist + */ removeSubscriptionAsync(subscriptionId: string): Promise; - start(): Promise; stop(): Promise; } \ No newline at end of file diff --git a/typescript/src/contracts/IHandle.ts b/typescript/src/contracts/IHandle.ts index 1eb9d227717..f20c6c670f8 100644 --- a/typescript/src/contracts/IHandle.ts +++ b/typescript/src/contracts/IHandle.ts @@ -1,6 +1,15 @@ import { MessageContext } from "./MessageContext"; -// Generic interface for message handlers +/** + * Defines a handler interface for processing items of type TMessage. + * @template TMessage The type of message to be handled. + */ export interface IHandle { + /** + * Handles the specified message asynchronously. + * @param message The message to be handled. + * @param context The context information for the message being handled. + * @returns A promise that resolves to the result of handling the message. + */ handleAsync(message: TMessage, context: MessageContext): Promise; } \ No newline at end of file diff --git a/typescript/src/contracts/ISaveState.ts b/typescript/src/contracts/ISaveState.ts index d440336998d..e4b546a82ae 100644 --- a/typescript/src/contracts/ISaveState.ts +++ b/typescript/src/contracts/ISaveState.ts @@ -1,5 +1,20 @@ +/** + * Defines a contract for saving and loading the state of an object. + * The state must be JSON serializable. + */ export interface ISaveState { + /** + * Saves the current state of the object. + * @returns A promise that resolves to the saved state. The structure of the state + * is implementation-defined but must be JSON serializable. + */ saveStateAsync(): Promise; + + /** + * Loads a previously saved state into the object. + * @param state A state object representing the saved state. The structure of the state + * is implementation-defined but must be JSON serializable. + * @returns A promise that completes when the state has been loaded. + */ loadStateAsync(state: unknown): Promise; - // Interface for saving/loading agent state } \ No newline at end of file diff --git a/typescript/src/contracts/ISubscriptionDefinition.ts b/typescript/src/contracts/ISubscriptionDefinition.ts index aa031fc7366..45db3810409 100644 --- a/typescript/src/contracts/ISubscriptionDefinition.ts +++ b/typescript/src/contracts/ISubscriptionDefinition.ts @@ -1,7 +1,26 @@ import { AgentId, TopicId } from "./IAgentRuntime"; +/** + * Defines a subscription that matches topics and maps them to agents. + */ export interface ISubscriptionDefinition { + /** + * Gets the unique identifier of the subscription. + */ id: string; + + /** + * Checks if a given TopicId matches the subscription. + * @param topic The topic to check + * @returns true if the topic matches the subscription; otherwise, false + */ matches(topic: TopicId): boolean; + + /** + * Maps a TopicId to an AgentId. + * Should only be called if matches() returns true. + * @param topic The topic to map + * @returns The AgentId that should handle the topic + */ mapToAgent(topic: TopicId): AgentId; } \ No newline at end of file diff --git a/typescript/src/contracts/IUnboundSubscriptionDefinition.ts b/typescript/src/contracts/IUnboundSubscriptionDefinition.ts index 6d0c06a6c9a..e0867e496a5 100644 --- a/typescript/src/contracts/IUnboundSubscriptionDefinition.ts +++ b/typescript/src/contracts/IUnboundSubscriptionDefinition.ts @@ -1,6 +1,15 @@ import { AgentType } from "./AgentType"; import { ISubscriptionDefinition } from "./ISubscriptionDefinition"; +/** + * Defines a subscription that is not yet bound to a specific agent type. + * This interface allows the creation of dynamic subscriptions that can later be associated with an agent. + */ export interface IUnboundSubscriptionDefinition { + /** + * Binds the subscription to a specific agent type, creating a concrete subscription definition. + * @param agentType The agent type to associate with the subscription + * @returns A new subscription definition bound to the specified agent type + */ bind(agentType: AgentType): ISubscriptionDefinition; } \ No newline at end of file diff --git a/typescript/src/contracts/KVStringParseHelper.ts b/typescript/src/contracts/KVStringParseHelper.ts index 2531005f4ba..4466a420f43 100644 --- a/typescript/src/contracts/KVStringParseHelper.ts +++ b/typescript/src/contracts/KVStringParseHelper.ts @@ -1,4 +1,28 @@ -// Placeholder for key-value string parsing +/** + * Provides helper methods for parsing key-value string representations. + */ export class KVStringParseHelper { - // ...existing code... + /** + * The regular expression pattern used to match key-value pairs in the format "key/value". + */ + private static readonly KV_PAIR_PATTERN = /^(?\w+)\/(?\w+)$/; + + /** + * Parses a string in the format "key/value" into a tuple containing the key and value. + * @param kvString The input string containing a key-value pair + * @param keyName The expected name of the key component + * @param valueName The expected name of the value component + * @returns A tuple containing the extracted key and value + * @throws Error if the input string does not match the expected "key/value" format + * @example + * ```typescript + * const input = "agent1/12345"; + * const result = KVStringParseHelper.toKVPair(input, "Type", "Key"); + * console.log(result[0]); // Outputs: agent1 + * console.log(result[1]); // Outputs: 12345 + * ``` + */ + public static toKVPair(kvString: string, keyName: string, valueName: string): [string, string] { + // ...existing code... + } } diff --git a/typescript/src/contracts/MessageContext.ts b/typescript/src/contracts/MessageContext.ts index 736aa03e254..7915bef00dd 100644 --- a/typescript/src/contracts/MessageContext.ts +++ b/typescript/src/contracts/MessageContext.ts @@ -1,17 +1,53 @@ import { AgentId, TopicId } from "./IAgentRuntime"; +/** + * Represents the context of a message being sent within the agent runtime. + * This includes metadata such as the sender, topic, RPC status, and cancellation handling. + */ export class MessageContext { + /** + * Gets the unique identifier for this message. + */ public readonly messageId: string; + + /** + * Gets the cancellation signal associated with this message. + * This can be used to cancel the operation if necessary. + */ public readonly cancellation?: AbortSignal; + + /** + * Gets or sets the sender of the message. + * If null, the sender is unspecified. + */ public sender?: AgentId; + + /** + * Gets or sets the topic associated with the message. + * If null, the message is not tied to a specific topic. + */ public topic?: TopicId; + + /** + * Gets or sets a value indicating whether this message is part of an RPC (Remote Procedure Call). + */ public isRpc: boolean = false; + /** + * Creates a new instance of the MessageContext class. + * @param messageId The unique identifier for this message. + * @param cancellation Optional cancellation signal for the message. + */ constructor(messageId: string, cancellation?: AbortSignal) { this.messageId = messageId; this.cancellation = cancellation; } + /** + * Creates a new MessageContext with a random UUID and optional cancellation signal. + * @param cancellation Optional cancellation signal for the message. + * @returns A new MessageContext instance. + */ static create(cancellation?: AbortSignal): MessageContext { return new MessageContext(crypto.randomUUID(), cancellation); }