@memberjunction/a2aserver
Version:
MemberJunction Agent-To-Agent (A2A) Server Implementation
236 lines • 8.99 kB
JavaScript
import { UUIDsEqual } from "@memberjunction/global";
import { AIEngine } from "@memberjunction/aiengine";
import { AgentRunner } from "@memberjunction/ai-agents";
/**
* Handles agent-related operations for the A2A server.
*
* **Multi-provider note:** every entity load/save inside this class binds to the
* `IMetadataProvider` passed at construction. The A2A server resolves the provider once
* per request and passes it down — when A2AServer gains a per-request provider model, only
* the request handler changes; this class is already correct.
*/
export class AgentOperations {
constructor(contextUser, provider) {
this.contextUser = contextUser;
this.provider = provider;
}
/**
* Discovers available agents based on pattern
* @param parameters Parameters containing the pattern
* @returns The operation result with list of agents
*/
async discoverAgents(parameters) {
try {
const pattern = parameters.pattern || '*';
// Ensure AIEngine is configured
const aiEngine = AIEngine.Instance;
await aiEngine.Config(false, this.contextUser);
const allAgents = aiEngine.Agents;
let agents = [];
if (pattern === '*') {
agents = allAgents;
}
else {
const isWildcardPattern = pattern.includes('*');
if (!isWildcardPattern) {
// Exact match
agents = allAgents.filter(a => a.Name === pattern);
}
else {
// Convert wildcard pattern to regex
const regexPattern = pattern
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // Escape special chars except *
.replace(/\*/g, '.*'); // Convert * to .*
const regex = new RegExp(`^${regexPattern}$`, 'i');
agents = allAgents.filter(a => a.Name && regex.test(a.Name));
}
}
return {
success: true,
result: agents.map(agent => ({
id: agent.ID,
name: agent.Name,
description: agent.Description || '',
typeID: agent.TypeID,
parentID: agent.ParentID
}))
};
}
catch (error) {
return {
success: false,
errorMessage: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Executes an agent
* @param parameters Parameters containing agent ID/name and execution params
* @returns The operation result with run info
*/
async executeAgent(parameters) {
try {
// Find the agent
const aiEngine = AIEngine.Instance;
await aiEngine.Config(false, this.contextUser);
let agent = null;
if (parameters.agentId) {
agent = aiEngine.Agents.find(a => UUIDsEqual(a.ID, parameters.agentId)) || null;
if (!agent) {
throw new Error(`Agent not found with ID: ${parameters.agentId}`);
}
}
else if (parameters.agentName) {
agent = aiEngine.Agents.find(a => a.Name?.toLowerCase() === parameters.agentName.toLowerCase()) || null;
if (!agent) {
throw new Error(`Agent not found with name: ${parameters.agentName}`);
}
}
else {
throw new Error('Either agentId or agentName must be provided');
}
// Convert conversation history
const messages = parameters.conversationHistory || [];
// Execute the agent
const agentRunner = new AgentRunner();
const result = await agentRunner.RunAgent({
agent,
conversationMessages: messages,
contextUser: this.contextUser,
data: parameters.data || {}
});
return {
success: result.success,
result: {
runId: result.agentRun?.ID,
agentName: agent.Name,
status: result.agentRun?.Status || (result.success ? 'Completed' : 'Failed'),
startTime: result.agentRun?.StartedAt,
endTime: result.agentRun?.CompletedAt,
errorMessage: result.agentRun?.ErrorMessage,
finalStep: result.agentRun?.FinalStep,
result: result.payload
}
};
}
catch (error) {
return {
success: false,
errorMessage: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Gets the status of an agent run
* @param parameters Parameters containing the run ID
* @returns The operation result with run status
*/
async getAgentRunStatus(parameters) {
try {
const runId = parameters.runId;
if (!runId) {
return {
success: false,
errorMessage: 'Run ID is required'
};
}
// Load the agent run from database via the per-request provider.
const agentRun = await this.provider.GetEntityObject('MJ: AI Agent Runs', this.contextUser);
const loaded = await agentRun.Load(runId);
if (!loaded) {
return {
success: false,
errorMessage: `Run not found: ${runId}`
};
}
return {
success: true,
result: {
runId: agentRun.ID,
agentName: agentRun.Agent,
status: agentRun.Status,
startTime: agentRun.StartedAt,
endTime: agentRun.CompletedAt,
errorMessage: agentRun.ErrorMessage,
totalTokens: agentRun.TotalTokensUsed
}
};
}
catch (error) {
return {
success: false,
errorMessage: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Cancels an agent run
* @param parameters Parameters containing the run ID
* @returns The operation result
*/
async cancelAgentRun(parameters) {
try {
const runId = parameters.runId;
if (!runId) {
return {
success: false,
errorMessage: 'Run ID is required'
};
}
// Load the agent run from database via the per-request provider.
const agentRun = await this.provider.GetEntityObject('MJ: AI Agent Runs', this.contextUser);
const loaded = await agentRun.Load(runId);
if (!loaded) {
return {
success: false,
errorMessage: `Run not found: ${runId}`
};
}
if (agentRun.Status !== 'Running') {
return {
success: false,
errorMessage: `Cannot cancel run with status: ${agentRun.Status}`
};
}
// Update status to cancelled
agentRun.Status = 'Cancelled';
agentRun.CompletedAt = new Date();
const saved = await agentRun.Save();
return {
success: saved,
result: { cancelled: saved },
errorMessage: saved ? undefined : 'Failed to update run status'
};
}
catch (error) {
return {
success: false,
errorMessage: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Processes an agent operation
* @param operation The operation to perform
* @param parameters The operation parameters
* @returns The operation result
*/
async processOperation(operation, parameters) {
switch (operation) {
case 'discoverAgents':
return await this.discoverAgents(parameters);
case 'executeAgent':
return await this.executeAgent(parameters);
case 'getAgentRunStatus':
return await this.getAgentRunStatus(parameters);
case 'cancelAgentRun':
return await this.cancelAgentRun(parameters);
default:
return {
success: false,
errorMessage: `Unsupported agent operation: ${operation}`
};
}
}
}
//# sourceMappingURL=AgentOperations.js.map