BaseAgent¶
Abstract base class for all agents in the framework. Provides execution lifecycle management, automatic timeout handling, error recovery, execution statistics, and opt-in distributed tracing.
Import¶
Constructor¶
abstract class BaseAgent {
constructor(
name: string,
version: string,
toolRegistry: ToolRegistry
)
}
| Parameter | Type | Description |
|---|---|---|
name | string | Unique identifier for the agent |
version | string | Semantic version string (e.g. "1.0.0") |
toolRegistry | ToolRegistry | Registry of tools available to this agent |
The constructor initializes a default AgentConfig with a 60-second timeout and debug mode disabled.
Class Signature¶
abstract class BaseAgent {
// -- Read-only properties --
readonly name: string;
readonly version: string;
description: string;
// -- Core execution --
async execute(context: AgentContext): Promise<AgentResult>;
protected abstract executeInternal(context: AgentContext): Promise<any>;
// -- Tool access --
protected async useTool(name: string, params: Record<string, any>): Promise<any>;
protected getToolMetadata(name: string): ToolMetadata | undefined;
getAvailableTools(): string[];
// -- Capabilities --
getCapabilities(): AgentCapability[];
hasCapability(capability: AgentCapability): boolean;
// -- Configuration --
getConfig(): AgentConfig;
setConfig(config: Partial<AgentConfig>): void;
// -- Statistics --
getStats(): AgentStats;
resetStats(): void;
// -- Introspection --
getInfo(): AgentInfo;
// -- Lifecycle hooks --
async initialize(): Promise<void>;
async cleanup(): Promise<void>;
// -- Tracing --
setTraceStore(
store: TraceStore,
configSnapshotId?: string,
costCalculator?: CostCalculator
): void;
get traceStore(): TraceStore | undefined;
// -- Cloning --
abstract clone(toolRegistry: ToolRegistry): BaseAgent;
}
Methods¶
Core Execution¶
| Method | Returns | Description |
|---|---|---|
execute(context) | Promise<AgentResult> | Public entry point. Validates context, runs executeInternal() with timeout, tracks statistics, and optionally records a trace. Do not override this method. |
executeInternal(context) | Promise<any> | Abstract. Implement your agent's logic here. The return value is wrapped in AgentResult.data. |
Tool Access¶
| Method | Returns | Description |
|---|---|---|
useTool(name, params) | Promise<any> | Invoke a registered tool by name. Throws if the tool is not found. Automatically tracked in AgentResult.toolsUsed. |
getToolMetadata(name) | ToolMetadata \| undefined | Retrieve metadata for a registered tool. Useful for inspecting parameter schemas at runtime. |
getAvailableTools() | string[] | List all tool names in the agent's registry. |
Capabilities¶
| Method | Returns | Description |
|---|---|---|
getCapabilities() | AgentCapability[] | Returns a copy of the agent's declared capabilities. |
hasCapability(capability) | boolean | Checks whether all tools required by the capability are present in the registry. |
Configuration¶
| Method | Returns | Description |
|---|---|---|
getConfig() | AgentConfig | Returns a copy of the current agent configuration. |
setConfig(config) | void | Merges partial config into the current configuration. Use this to change timeout, enable debug mode, etc. |
Statistics¶
| Method | Returns | Description |
|---|---|---|
getStats() | AgentStats | Returns execution statistics: count, success/failure counts, average duration, and success rate. |
resetStats() | void | Resets all counters to zero. |
AgentStats shape:
{
executionCount: number;
averageExecutionTime: number; // milliseconds
successRate: number; // 0.0 to 1.0
successCount: number;
failureCount: number;
}
Introspection¶
| Method | Returns | Description |
|---|---|---|
getInfo() | AgentInfo | Returns a summary of the agent: name, version, description, capabilities, available tools, and stats. |
Lifecycle Hooks¶
| Method | Returns | Description |
|---|---|---|
initialize() | Promise<void> | Called before the first execution. Override to perform setup (e.g., verify tool availability, warm caches). |
cleanup() | Promise<void> | Called during shutdown. Override to release resources. |
Tracing¶
| Method | Returns | Description |
|---|---|---|
setTraceStore(store, configSnapshotId?, costCalculator?) | void | Attach a trace store. Once set, every execute() call automatically creates and finalizes a trace. |
traceStore (getter) | TraceStore \| undefined | Read-only access to the configured trace store. |
Tracing is opt-in
If no TraceStore is attached, the agent runs identically but without recording traces. This keeps the framework lightweight for development and testing.
Cloning¶
| Method | Returns | Description |
|---|---|---|
clone(toolRegistry) | BaseAgent | Abstract. Create a copy of this agent with a different tool registry. Used by the orchestrator to create isolated agent instances. |
Execution Lifecycle¶
When you call agent.execute(context), the following happens in order:
- Context validation --
userId,auditingId, andpromptare checked - Trace start -- if a
TraceStoreis attached, a new trace is created with a unique ID - Timeout race --
executeInternal()races against the configured timeout (default: 60s) - Tool tracking -- every
useTool()call is recorded inAgentResult.toolsUsed - Statistics update -- execution count, duration, and success/failure counters are updated
- Trace finalization -- the trace is marked as
completedorfailedwith duration and cost data - Result return -- an
AgentResultis returned withsuccess,dataorerror, and metadata
sequenceDiagram
participant Caller
participant BaseAgent
participant executeInternal
participant TraceStore
Caller->>BaseAgent: execute(context)
BaseAgent->>BaseAgent: validateContext()
opt TraceStore attached
BaseAgent->>TraceStore: startTrace()
end
BaseAgent->>executeInternal: executeInternal(context)
executeInternal-->>BaseAgent: result data
BaseAgent->>BaseAgent: updateStats()
opt TraceStore attached
BaseAgent->>TraceStore: endTrace()
end
BaseAgent-->>Caller: AgentResult Complete Example¶
The following example shows how to create a custom agent that uses tools and tracing:
import {
BaseAgent,
ToolRegistry,
AgentContext,
AgentResult,
AgentCapability,
} from "@modernpath/agent-framework";
import type { GeminiClient } from "@modernpath/agent-framework";
class SentimentAgent extends BaseAgent {
// Declare capabilities so callers can inspect what this agent can do
protected capabilities: AgentCapability[] = [
{
name: "sentiment-analysis",
description: "Analyzes sentiment of user-provided text",
requiredTools: ["gemini-generate"], // (1)!
examples: ["Analyze the sentiment of this review"],
},
];
constructor(
toolRegistry: ToolRegistry,
private readonly gemini: GeminiClient,
) {
super("SentimentAgent", "1.0.0", toolRegistry);
this.description = "Analyzes text sentiment using Gemini.";
}
protected async executeInternal(context: AgentContext): Promise<any> {
const text = context.parameters.text || context.prompt;
// Use the Gemini client to classify sentiment
const response = await this.gemini.generateContent(
`Classify the sentiment of the following text as positive, negative, or neutral. ` +
`Return JSON: { "sentiment": "...", "confidence": 0.0-1.0 }\n\nText: ${text}`,
{ temperature: 0.1, maxOutputTokens: 256 },
);
// Parse the LLM response
const parsed = JSON.parse(response.text);
return {
sentiment: parsed.sentiment,
confidence: parsed.confidence,
inputLength: text.length,
};
}
clone(toolRegistry: ToolRegistry): BaseAgent {
return new SentimentAgent(toolRegistry, this.gemini);
}
}
// --- Usage ---
const registry = new ToolRegistry();
const agent = new SentimentAgent(registry, geminiClient);
// Optional: enable tracing
agent.setTraceStore(myTraceStore);
// Optional: adjust timeout
agent.setConfig({ timeout: 30_000, debug: true });
const result: AgentResult = await agent.execute({
userId: 42,
auditingId: 1001,
prompt: "Analyze this review",
parameters: {
text: "This product exceeded my expectations. Highly recommended!",
},
});
if (result.success) {
console.log(result.data);
// { sentiment: "positive", confidence: 0.95, inputLength: 57 }
}
console.log(agent.getStats());
// { executionCount: 1, successCount: 1, failureCount: 0, ... }
- The
requiredToolsarray declares which tools must be present in the registry for this capability to be available.hasCapability()checks this at runtime.
Timeout Handling¶
The default timeout is 60 seconds. If executeInternal() does not resolve within the timeout, the execution is rejected with an error:
To change the timeout:
Timeout does not cancel the internal promise
The timeout mechanism uses Promise.race. The underlying executeInternal() call is not cancelled -- it will continue running in the background. Design your agent logic to handle this gracefully if needed.
Error Handling¶
If executeInternal() throws, the error is caught and returned as a failed AgentResult:
const result = await agent.execute(context);
if (!result.success) {
console.error(result.error); // The error message string
}
The agent's failureCount statistic is incremented, and if tracing is enabled, the trace is marked with status "failed".
Related Pages¶
- AgentContext & AgentResult -- the data interfaces
- ToolRegistry -- managing tools
- Tracing -- attaching trace stores
- Built-in Agents -- pre-built agents that extend
BaseAgent