Complete reference for pytest-agents's TypeScript agent APIs.
All agents share common interfaces for consistency.
Standard request format received from Python via stdin.
interface AgentRequest {
action: string;
params: Record<string, unknown>;
}Example:
{
"action": "list_tasks",
"params": {
"path": "./src",
"filter": "pending"
}
}Standard response format sent to Python via stdout.
interface AgentResponse {
status: 'success' | 'error';
data: Record<string, unknown>;
agent?: string; // Set by Python bridge
}Example Success:
{
"status": "success",
"data": {
"tasks": [
{"id": 1, "name": "Task 1", "status": "pending"}
]
}
}Example Error:
{
"status": "error",
"data": {
"error": "Invalid path provided",
"code": "INVALID_PATH"
}
}All agents follow this pattern:
export class BaseAgent {
async handle(action: string, params: any): Promise<AgentResponse> {
try {
switch (action) {
case 'ping':
return this.ping();
case 'action_name':
return this.actionName(params);
default:
return {
status: 'error',
data: { error: `Unknown action: ${action}` }
};
}
} catch (error) {
return {
status: 'error',
data: {
error: error instanceof Error ? error.message : String(error)
}
};
}
}
protected ping(): AgentResponse {
return {
status: 'success',
data: { message: 'pong' }
};
}
}Project Management agent for task tracking and planning.
Location: pm/src/
// pm/src/types.ts
export interface Task {
id: string;
title: string;
description: string;
status: 'pending' | 'in_progress' | 'completed';
priority: 'low' | 'medium' | 'high';
dependencies: string[];
assignee?: string;
created: Date;
updated: Date;
}
export interface Milestone {
id: string;
name: string;
description: string;
tasks: string[];
dueDate?: Date;
completed: boolean;
}
export interface ProjectState {
tasks: Task[];
milestones: Milestone[];
metadata: Record<string, unknown>;
}// pm/src/agent.ts
export class PMAgent {
constructor(private state: ProjectState = { tasks: [], milestones: [], metadata: {} }) {}
async handle(action: string, params: any): Promise<AgentResponse> {
// Implementation
}
// Actions
async listTasks(params: ListTasksParams): Promise<AgentResponse>;
async createTask(params: CreateTaskParams): Promise<AgentResponse>;
async updateTask(params: UpdateTaskParams): Promise<AgentResponse>;
async deleteTask(params: DeleteTaskParams): Promise<AgentResponse>;
async analyzeDependencies(params: AnalyzeDepsParams): Promise<AgentResponse>;
async planMilestone(params: PlanMilestoneParams): Promise<AgentResponse>;
}Health check action.
Parameters: None
Returns:
{
status: 'success',
data: { message: 'pong' }
}List tasks with optional filtering.
Parameters:
{
filter?: {
status?: 'pending' | 'in_progress' | 'completed';
priority?: 'low' | 'medium' | 'high';
assignee?: string;
};
sort?: 'created' | 'updated' | 'priority';
}Returns:
{
status: 'success',
data: {
tasks: Task[];
count: number;
}
}Create a new task.
Parameters:
{
title: string;
description: string;
priority?: 'low' | 'medium' | 'high';
assignee?: string;
dependencies?: string[];
}Returns:
{
status: 'success',
data: {
task: Task;
}
}Analyze task dependencies.
Parameters:
{
taskId?: string; // Specific task, or all if omitted
}Returns:
{
status: 'success',
data: {
graph: {
nodes: { id: string; title: string }[];
edges: { from: string; to: string }[];
};
cycles: string[][]; // Circular dependencies
criticalPath: string[];
}
}Located in pm/src/capabilities/:
// pm/src/capabilities/task-tracking.ts
export class TaskTracking {
track(tasks: Task[]): TaskMetrics;
prioritize(tasks: Task[]): Task[];
filter(tasks: Task[], criteria: FilterCriteria): Task[];
}// pm/src/capabilities/dependency-analysis.ts
export class DependencyAnalysis {
buildGraph(tasks: Task[]): DependencyGraph;
findCycles(graph: DependencyGraph): string[][];
findCriticalPath(graph: DependencyGraph): string[];
}// pm/src/capabilities/milestone-planning.ts
export class MilestonePlanning {
plan(tasks: Task[], goal: string): Milestone;
estimate(milestone: Milestone): { duration: number; resources: string[] };
track(milestone: Milestone): MilestoneProgress;
}AI-powered research and documentation analysis.
Location: research/src/
// research/src/types.ts
export interface Document {
id: string;
title: string;
content: string;
url?: string;
metadata: Record<string, unknown>;
analyzed: boolean;
}
export interface Citation {
documentId: string;
text: string;
context: string;
relevance: number;
}
export interface ResearchResult {
query: string;
documents: Document[];
citations: Citation[];
summary: string;
}// research/src/agent.ts
export class ResearchAgent {
async handle(action: string, params: any): Promise<AgentResponse> {
// Implementation
}
// Actions
async analyzeDocument(params: AnalyzeDocParams): Promise<AgentResponse>;
async search(params: SearchParams): Promise<AgentResponse>;
async summarize(params: SummarizeParams): Promise<AgentResponse>;
async extractCitations(params: CitationParams): Promise<AgentResponse>;
}Analyze a document.
Parameters:
{
content: string;
title?: string;
url?: string;
}Returns:
{
status: 'success',
data: {
document: Document;
analysis: {
topics: string[];
entities: { name: string; type: string }[];
sentiment: 'positive' | 'neutral' | 'negative';
readability: number;
};
}
}Search documents.
Parameters:
{
query: string;
filters?: {
analyzed?: boolean;
minRelevance?: number;
};
}Returns:
{
status: 'success',
data: {
results: Document[];
count: number;
}
}Summarize documents.
Parameters:
{
documentIds: string[];
maxLength?: number;
}Returns:
{
status: 'success',
data: {
summary: string;
keyPoints: string[];
}
}Located in research/src/capabilities/:
// research/src/capabilities/document-analysis.ts
export class DocumentAnalysis {
analyze(content: string): DocumentAnalysisResult;
extractTopics(content: string): string[];
extractEntities(content: string): Entity[];
}// research/src/capabilities/citation-tracker.ts
export class CitationTracker {
track(document: Document): Citation[];
validate(citation: Citation): boolean;
format(citation: Citation, style: 'APA' | 'MLA' | 'Chicago'): string;
}Code indexing and intelligent search.
Location: index/src/
// index/src/types.ts
export interface CodeSymbol {
name: string;
kind: 'function' | 'class' | 'variable' | 'interface' | 'type';
file: string;
line: number;
column: number;
signature?: string;
documentation?: string;
}
export interface SearchResult {
symbol: CodeSymbol;
score: number;
context: string[];
}
export interface IndexStats {
totalFiles: number;
totalSymbols: number;
languages: Record<string, number>;
lastIndexed: Date;
}// index/src/agent.ts
export class IndexAgent {
async handle(action: string, params: any): Promise<AgentResponse> {
// Implementation
}
// Actions
async indexProject(params: IndexParams): Promise<AgentResponse>;
async search(params: SearchParams): Promise<AgentResponse>;
async findSymbol(params: FindSymbolParams): Promise<AgentResponse>;
async getStats(params: StatsParams): Promise<AgentResponse>;
}Index a project directory.
Parameters:
{
path: string;
include?: string[]; // Glob patterns
exclude?: string[]; // Glob patterns
languages?: string[]; // ['typescript', 'python', etc.]
}Returns:
{
status: 'success',
data: {
stats: IndexStats;
duration: number;
}
}Search indexed code.
Parameters:
{
query: string;
kind?: 'function' | 'class' | 'variable' | 'interface' | 'type';
file?: string; // Filter by file path
limit?: number;
}Returns:
{
status: 'success',
data: {
results: SearchResult[];
count: number;
}
}Find a specific symbol.
Parameters:
{
name: string;
kind?: string;
}Returns:
{
status: 'success',
data: {
symbol: CodeSymbol | null;
}
}Located in index/src/capabilities/:
// index/src/capabilities/code-indexer.ts
export class CodeIndexer {
index(path: string): IndexResult;
update(file: string): void;
remove(file: string): void;
}// index/src/capabilities/symbol-mapper.ts
export class SymbolMapper {
map(ast: AST): CodeSymbol[];
resolve(symbolName: string): CodeSymbol | null;
findReferences(symbol: CodeSymbol): Reference[];
}my-agent/
├── src/
│ ├── index.ts # Entry point
│ ├── agent.ts # Main agent class
│ ├── types.ts # Type definitions
│ ├── capabilities/ # Agent capabilities
│ ├── tools/ # Helper tools
│ └── utils/ # Utilities
├── __tests__/ # Jest tests
├── package.json
└── tsconfig.json
// src/index.ts
import { MyAgent } from './agent';
async function main() {
const agent = new MyAgent();
// Read request from stdin
let input = '';
process.stdin.setEncoding('utf8');
for await (const chunk of process.stdin) {
input += chunk;
}
try {
const request = JSON.parse(input);
const response = await agent.handle(request.action, request.params);
console.log(JSON.stringify(response));
process.exit(0);
} catch (error) {
console.log(JSON.stringify({
status: 'error',
data: {
error: error instanceof Error ? error.message : String(error)
}
}));
process.exit(1);
}
}
main();// src/agent.ts
import { AgentResponse } from './types';
export class MyAgent {
async handle(action: string, params: any): Promise<AgentResponse> {
try {
switch (action) {
case 'ping':
return this.ping();
case 'my_action':
return this.myAction(params);
default:
return {
status: 'error',
data: { error: `Unknown action: ${action}` }
};
}
} catch (error) {
return {
status: 'error',
data: {
error: error instanceof Error ? error.message : String(error)
}
};
}
}
protected ping(): AgentResponse {
return {
status: 'success',
data: { message: 'pong' }
};
}
private async myAction(params: any): Promise<AgentResponse> {
// Implement your action
return {
status: 'success',
data: { result: 'action completed' }
};
}
}// src/types.ts
export interface AgentRequest {
action: string;
params: Record<string, unknown>;
}
export interface AgentResponse {
status: 'success' | 'error';
data: Record<string, unknown>;
}
export interface MyActionParams {
// Define your parameter types
input: string;
options?: {
flag: boolean;
};
}// __tests__/agent.test.ts
import { MyAgent } from '../src/agent';
describe('MyAgent', () => {
let agent: MyAgent;
beforeEach(() => {
agent = new MyAgent();
});
it('should respond to ping', async () => {
const response = await agent.handle('ping', {});
expect(response.status).toBe('success');
expect(response.data.message).toBe('pong');
});
it('should handle my_action', async () => {
const response = await agent.handle('my_action', { input: 'test' });
expect(response.status).toBe('success');
});
it('should handle unknown action', async () => {
const response = await agent.handle('unknown', {});
expect(response.status).toBe('error');
});
});// package.json
{
"name": "my-agent",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"test": "jest",
"dev": "ts-node src/index.ts"
},
"devDependencies": {
"@types/node": "^20.0.0",
"jest": "^29.0.0",
"ts-jest": "^29.0.0",
"ts-node": "^10.0.0",
"typescript": "^5.0.0"
}
}// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "__tests__"]
}# In pytest-agents/config.py
agent_myagent_enabled: bool = True
agent_myagent_path: Optional[Path] = None
# In pytest-agents/agent_bridge.py
if self.config.agent_myagent_enabled and self.config.agent_myagent_path:
self.agents["myagent"] = AgentClient(
"myagent",
self.config.agent_myagent_path,
self.config.agent_timeout
)- Always handle errors: Wrap logic in try-catch
- Validate input: Check params before using
- Return consistent responses: Always use AgentResponse format
- Log appropriately: Use console.error for errors, not console.log
- Type everything: Use TypeScript strict mode
- Test thoroughly: Unit tests for all actions
- Document actions: Add JSDoc comments
- Keep it simple: One responsibility per action
- Review Python API Reference
- Study Architecture Overview
- Read Developer Guide