Skip to content

Latest commit

 

History

History
734 lines (568 loc) · 22.6 KB

File metadata and controls

734 lines (568 loc) · 22.6 KB

Loop Agent API Reference

This document provides a comprehensive reference for the Loop Agent SDK public APIs.

Table of Contents


Orchestrator

The main entry point for running PIV (Plan-Implement-Validate) loops.

PIVOrchestrator

Coordinates the complete PIV workflow for autonomous software development.

import { PIVOrchestrator } from 'loop-agent';

const orchestrator = new PIVOrchestrator(config, runCommand, fileOps);
const finalState = await orchestrator.run('Add user authentication');

Constructor

new PIVOrchestrator(
  config: OrchestratorAgentConfig,
  runCommand: (cmd: string) => Promise<CommandResult>,
  fileOps: FileOperations
)
Parameter Type Description
config OrchestratorAgentConfig Configuration including working directory and max iterations
runCommand Function Shell command executor returning stdout/stderr/exitCode
fileOps FileOperations File system operations (read, write, list)

Methods

Method Returns Description
run(userRequest: string) Promise<PIVLoopState> Execute full PIV loop for a request
getState() PIVLoopState Get current immutable state snapshot

Agents

Planner

Creates PRDs (Product Requirements Documents) and feature plans (PRPs).

import { createPlannerAgent, createPRD, createFeaturePlan } from 'loop-agent';

const plannerConfig = createPlannerAgent();
const prdResult = await createPRD(plannerConfig, 'Build a REST API');

Functions

Function Returns Description
createPlannerAgent() PlannerAgentConfig Create planner with ULTRATHINK enabled
createDiscoveryAgent() PlannerAgentConfig Create discovery agent for requirements
generateDiscoveryQuestions(config, context) Promise<AgentResult<DiscoveryQuestions>> Generate clarifying questions
hasEnoughContext(config, context) Promise<boolean> Check if ready for PRD creation
updateDiscoveryContext(context, questions, answers) DiscoveryContext Update context with new Q&A
createPRD(config, request, discovery?, projectContext?) Promise<AgentResult<PRD>> Create product requirements
extractFeatures(config, prd) Promise<AgentResult<Feature[]>> Extract features from PRD
createFeaturePlan(config, feature, codebaseContext) Promise<AgentResult<FeaturePlan>> Create detailed feature plan

Implementer

Executes tasks from feature plans.

import { createImplementerAgent, executeTask } from 'loop-agent';

const implementerConfig = createImplementerAgent();
const result = await executeTask(implementerConfig, task, plan, contextFiles);

Functions

Function Returns Description
createImplementerAgent() ImplementerAgentConfig Create implementer with ULTRATHINK
executeTask(config, task, plan, contextFiles) Promise<AgentResult<ImplementationResult>> Execute a single task
executeQuickFix(config, description, targetFile, content) Promise<AgentResult<ImplementationResult>> Apply quick fix (MICRO PIV)
applyFixes(config, task, errors, currentContent) Promise<AgentResult<ImplementationResult>> Apply validation fixes

Validator

Runs the 5-level validation pyramid.

import { createValidatorAgent, runValidationPyramid, DEFAULT_VALIDATION_COMMANDS } from 'loop-agent';

const validatorConfig = createValidatorAgent();
const result = await runValidationPyramid(validatorConfig, DEFAULT_VALIDATION_COMMANDS, runCommand);

Functions

Function Returns Description
createValidatorAgent() ValidatorAgentConfig Create validator with ULTRATHINK
runValidationPyramid(config, commands, runCommand) Promise<AgentResult<ValidationResult>> Run full validation
runValidationLevel(level, command, runCommand) Promise<{passed, output, exitCode}> Run single level
generateValidationSummary(result) string Format validation result

Constants

const DEFAULT_VALIDATION_COMMANDS: ValidationCommand[] = [
  { level: 1, command: 'npx eslint . --ext .ts,.tsx', description: 'Syntax and style checking', required: true },
  { level: 2, command: 'npx tsc --noEmit', description: 'Type safety validation', required: true },
  { level: 3, command: 'npm test', description: 'Unit test execution', required: true },
  { level: 4, command: 'npm run test:integration', description: 'Integration test execution', required: false }
];

Reviewer

Performs code review and system learning.

import { createReviewerAgent, performCodeReview, performSystemReview } from 'loop-agent';

const reviewerConfig = createReviewerAgent();
const review = await performCodeReview(reviewerConfig, changedFiles, originalFiles);

Functions

Function Returns Description
createReviewerAgent() ReviewerAgentConfig Create reviewer with ULTRATHINK
performCodeReview(config, changedFiles, originalFiles) Promise<AgentResult<CodeReviewResult>> Review code changes
performSystemReview(config, state) Promise<AgentResult<SystemReviewResult>> Analyze session for patterns
generateReviewSummary(result) string Format review result

Features

Commands

Slash command discovery and execution system.

import { discoverAllCommands, parseCommand, executeCommand } from 'loop-agent';

const commands = discoverAllCommands();
const parsed = parseCommand('/plan Add authentication');
const result = executeCommand('plan', 'Add authentication');

Functions

Function Returns Description
parseCommand(input) ParsedCommand | null Parse slash command from user input
discoverAllCommands(additionalPaths?) SlashCommand[] Find all available commands
getCommand(name, commands?) SlashCommand | null Get specific command by name
executeCommand(name, args, commands?) {prompt, metadata} | null Execute command and get prompt
expandCommandTemplate(template, args, argList) string Expand template with arguments
formatCommandList(commands) string Format commands for display
clearCommandCache() void Clear cached commands

MCP Configuration

MCP (Model Context Protocol) server management.

import { buildMcpConfig, loadMcpConfig, DEFAULT_MCP_SERVERS } from 'loop-agent';

const servers = buildMcpConfig({ cloudOnly: true });
const health = await checkAllMcpServers(servers);

Functions

Function Returns Description
loadMcpConfig(projectPath?) McpServersConfig | null Load from .mcp.json
buildMcpConfig(options) McpServersConfig Build final server configuration
mergeMcpServers(defaults, user) McpServersConfig Merge configurations
checkMcpServerHealth(name, config) Promise<{connected, error?}> Check single server
checkAllMcpServers(servers) Promise<Record<string, {connected, error?}>> Check all servers
formatMcpStatus(results) string Format status for display
clearMcpCache() void Clear cached configuration

Constants

const DEFAULT_MCP_SERVERS: McpServersConfig = {
  archon: { type: 'http', url: 'http://localhost:8051/mcp' },
  crawl4ai: { type: 'sse', url: 'http://localhost:11235/mcp/sse' },
  context7: { type: 'http', url: 'https://mcp.context7.com/mcp' }
};

const CLOUD_MCP_SERVERS: McpServersConfig = {
  context7: { type: 'http', url: 'https://mcp.context7.com/mcp' }
};

Plugins

Plugin installation and management.

import { PluginManager, parsePluginSource } from 'loop-agent';

const manager = new PluginManager();
await manager.init();
const result = await manager.install('github:owner/my-plugin');

PluginManager Class

class PluginManager {
  async init(): Promise<void>;
  async install(source: string): Promise<PluginInstallResult>;
  async uninstall(name: string): Promise<{success, error?}>;
  async enable(name: string): Promise<boolean>;
  async disable(name: string): Promise<boolean>;
  list(): LoadedPlugin[];
  get(name: string): LoadedPlugin | undefined;
  async loadAll(): Promise<void>;
  getAllCommands(): SlashCommand[];
  getAllMcpServers(): McpServersConfig;
}

Functions

Function Returns Description
parsePluginSource(source) PluginSource Parse plugin source string
loadPluginManifest(pluginPath) Promise<PluginManifest | null> Load plugin manifest
loadPlugin(pluginPath, source) Promise<LoadedPlugin | null> Load plugin from directory
ensurePluginsDir() Promise<void> Create plugins directory
getInstalledPlugins() Promise<Record<string, {source, enabled}>> Get installed plugins registry
listInstalledPluginNames() Promise<string[]> List plugin names from disk
formatPluginList(plugins) string Format plugins for display

Types

Core Types

interface PIVLoopState {
  sessionId: string;
  userRequest: string;
  complexity: ComplexityLevel;
  phase: PIVPhase;
  status: 'idle' | 'running' | 'paused' | 'completed' | 'failed';
  prd?: PRD;
  features: Feature[];
  currentFeature?: Feature;
  currentPlan?: FeaturePlan;
  validationResults: ValidationResult[];
  codeReviews: CodeReviewResult[];
  totalIterations: number;
  startedAt?: Date;
  completedAt?: Date;
}

type ComplexityLevel = 'small_task' | 'feature' | 'project';

type PIVPhase =
  | 'idle'
  | 'discovery'
  | 'creating_prd'
  | 'extracting_features'
  | 'planning_feature'
  | 'implementing'
  | 'validating'
  | 'reviewing'
  | 'system_review'
  | 'completed'
  | 'failed';

type ValidationLevel = 1 | 2 | 3 | 4 | 5;

Agent Result Types

interface AgentResult<T> {
  success: boolean;
  data?: T;
  error?: string;
  duration: number;
}

interface ValidationResult {
  passed: boolean;
  level: ValidationLevel;
  failures: ValidationFailure[];
  isSystemIssue: boolean;
  duration: number;
}

interface CodeReviewResult {
  passed: boolean;
  filesReviewed: number;
  issues: CodeReviewIssue[];
  stats: { filesModified: number; filesAdded: number; filesDeleted: number; linesAdded: number; linesDeleted: number };
  reviewedAt: Date;
}

Configuration Types

interface OrchestratorAgentConfig {
  workingDirectory: string;
  maxIterationsPerTask?: number;  // Default: 3
  systemPrompt?: string;
  model?: string;
}

interface McpOptions {
  useDefaultMcpServers?: boolean;  // Default: true
  cloudOnly?: boolean;             // Default: false
  mcpConfigPath?: string;
  additionalServers?: McpServersConfig;
  excludeServers?: string[];
}

type McpServerConfig =
  | { type: 'stdio'; command: string; args?: string[]; env?: Record<string, string> }
  | { type: 'http'; url: string; headers?: Record<string, string> }
  | { type: 'sse'; url: string; headers?: Record<string, string> };

Utilities

Logger

Structured logging with OpenTelemetry-compliant format.

import { createLogger, logInfo, logError, logWarning } from 'loop-agent';

const logger = createLogger('my-component');
logger.info('operation.started', { sessionId: 'abc123' });

// Or use direct functions
logInfo('component.action', 'Operation completed', { duration: 150 });
logError('component.action', 'Operation failed', new Error('reason'));

State Management

Immutable state update functions.

import {
  createInitialState,
  updatePhase,
  updateStatus,
  addValidationResult,
  addCodeReview
} from 'loop-agent';

let state = createInitialState('session-1', 'Build REST API');
state = updatePhase(state, 'implementing');
state = addValidationResult(state, validationResult);

Complexity Assessment

import { assessComplexity } from 'loop-agent';

const complexity = await assessComplexity(config, userRequest, projectContext);
// Returns: 'small_task' | 'feature' | 'project'

Constants

// Validation pyramid levels
const VALIDATION_LEVELS = {
  1: 'Syntax & Style',
  2: 'Type Safety',
  3: 'Unit Tests',
  4: 'Integration Tests',
  5: 'Human Review'
};

// Agent models
const INTELLIGENT_MODEL = 'claude-opus-4-5-20251101';
const ULTRATHINK_TOKENS = 128000;

// Cache TTLs
const COMMAND_CACHE_TTL = 30000;  // 30 seconds
const MCP_CACHE_TTL = 60000;      // 60 seconds

// Timeouts
const MCP_HEALTH_CHECK_TIMEOUT = 5000;  // 5 seconds
const GIT_CLONE_TIMEOUT = 30000;        // 30 seconds

Error Handling

All agent functions return AgentResult<T> with consistent error handling:

const result = await createPRD(config, request);

if (result.success) {
  console.log('PRD created:', result.data.title);
  console.log('Duration:', result.duration, 'ms');
} else {
  console.error('Failed:', result.error);
}

For validation errors, check isSystemIssue to distinguish between code problems and environment issues:

const validation = await runValidationPyramid(config, commands, runCommand);

if (!validation.data?.passed) {
  if (validation.data?.isSystemIssue) {
    console.log('Environment issue - check dependencies');
  } else {
    console.log('Code issue - fix and retry');
  }
}

Events

The PIV Loop SDK provides a typed event system for observability and monitoring.

PIVEventEmitter

Type-safe event emitter for PIV loop lifecycle events.

import { pivEvents, PIVEventEmitter } from 'loop-agent';

// Subscribe to specific events
pivEvents.on('lifecycle:started', (event) => {
  console.log(`Session ${event.sessionId} started at ${event.timestamp}`);
});

pivEvents.on('validation:completed', (event) => {
  console.log(`Validation ${event.result.passed ? 'passed' : 'failed'}`);
});

// Subscribe to all events (for logging/debugging)
pivEvents.onAny((event) => {
  console.log(`[${event.type}] ${event.sessionId}`);
});

// Create isolated emitter for testing
const testEmitter = new PIVEventEmitter();

Event Types

Event Description Key Payload Fields
lifecycle:started PIV loop started sessionId, request
lifecycle:completed PIV loop completed successfully sessionId, state, duration
lifecycle:failed PIV loop failed sessionId, error, state
phase:changed Phase transition occurred sessionId, from, to
status:changed Status transition occurred sessionId, from, to
validation:started Validation level started sessionId, level, command
validation:completed Validation completed sessionId, result, duration
validation:failed Validation level failed sessionId, level, error, command
iteration:started Fix iteration started sessionId, count, taskId?
iteration:completed Fix iteration completed sessionId, count, success, taskId?
task:started Task execution started sessionId, task
task:completed Task execution completed sessionId, task, success
error:occurred Error occurred sessionId, error, context, recoverable

Helper Functions

Create event payloads with these helper functions:

Function Returns Description
lifecycleStarted(sessionId, request) LifecycleStartedEvent Create lifecycle started event
lifecycleCompleted(sessionId, state, duration) LifecycleCompletedEvent Create lifecycle completed event
lifecycleFailed(sessionId, error, state) LifecycleFailedEvent Create lifecycle failed event
phaseChanged(sessionId, from, to) PhaseChangedEvent Create phase change event
statusChanged(sessionId, from, to) StatusChangedEvent Create status change event
validationStarted(sessionId, level, command) ValidationStartedEvent Create validation started event
validationCompleted(sessionId, result, duration) ValidationCompletedEvent Create validation completed event
validationFailed(sessionId, level, error, command) ValidationFailedEvent Create validation failed event
iterationStarted(sessionId, count, taskId?) IterationStartedEvent Create iteration started event
iterationCompleted(sessionId, count, success, taskId?) IterationCompletedEvent Create iteration completed event
taskStarted(sessionId, task) TaskStartedEvent Create task started event
taskCompleted(sessionId, task, success) TaskCompletedEvent Create task completed event
errorOccurred(sessionId, error, context, recoverable?) ErrorOccurredEvent Create error event

Usage Example

import { pivEvents, lifecycleStarted, validationCompleted } from 'loop-agent';

// Metrics collection
const metrics = {
  sessionsStarted: 0,
  validationsPassed: 0,
  validationsFailed: 0,
};

pivEvents.on('lifecycle:started', () => {
  metrics.sessionsStarted++;
});

pivEvents.on('validation:completed', (event) => {
  if (event.result.passed) {
    metrics.validationsPassed++;
  } else {
    metrics.validationsFailed++;
  }
});

// Emit events programmatically
pivEvents.emit('lifecycle:started', lifecycleStarted('session-123', 'Build REST API'));

Hooks

The hook system allows plugins to intercept and modify PIV loop behavior at key lifecycle points.

Registering Hooks

import { registerHooks, unregisterHooks, clearAllHooks } from 'loop-agent';

// Register hooks with optional priority (lower = first, default = 100)
registerHooks('my-plugin', {
  beforeValidation: async (ctx, state, level) => {
    console.log(`Validating at level ${level}`);
    return { continue: true };
  },
  onError: async (ctx, error, errorContext) => {
    await logErrorToMonitoring(error);
    return { continue: true, message: 'Error logged' };
  }
}, 50); // Priority: 50 (runs before default)

// Remove hooks
unregisterHooks('my-plugin');

// Clear all hooks (useful for testing)
clearAllHooks();

Hook Types

Hook When Called Can Modify
beforeStart Before PIV loop starts Request string
afterComplete After PIV loop completes (void)
beforePlanning Before feature planning Skip planning
afterPlanning After plan created FeaturePlan
beforeImplementation Before task execution Task
afterImplementation After task execution (void)
beforeValidation Before validation runs Validation level
afterValidation After validation completes ValidationResult
onError When error occurs Recovery signal

HookResult

Hooks that can modify behavior return HookResult:

interface HookResult<T = void> {
  continue: boolean;  // false = abort operation
  data?: T;           // Modified data (optional)
  message?: string;   // Logging message (optional)
}

Hook Context

All hooks receive a HookContext:

interface HookContext {
  sessionId: string;
  timestamp: Date;
}

Complete Hook Example

import { registerHooks, type PIVHooks } from 'loop-agent';

const myPluginHooks: PIVHooks = {
  // Modify request before starting
  beforeStart: async (ctx, request) => {
    console.log(`[${ctx.sessionId}] Starting: ${request}`);
    return {
      continue: true,
      data: request.trim(), // Clean up request
    };
  },

  // Skip planning for small fixes
  beforePlanning: async (ctx, state) => {
    if (state.complexity === 'small_task') {
      return { continue: false, message: 'Skipping planning for small task' };
    }
    return { continue: true };
  },

  // Add metadata to plan
  afterPlanning: async (ctx, state, plan) => {
    return {
      continue: true,
      data: {
        ...plan,
        metadata: { ...plan.metadata, plugin: 'my-plugin' }
      }
    };
  },

  // Log task execution
  beforeImplementation: async (ctx, state, task) => {
    console.log(`[${ctx.sessionId}] Executing task: ${task.id}`);
    return { continue: true };
  },

  afterImplementation: async (ctx, state, task, success) => {
    console.log(`[${ctx.sessionId}] Task ${task.id}: ${success ? 'success' : 'failed'}`);
  },

  // Skip validation level 4 in dev mode
  beforeValidation: async (ctx, state, level) => {
    if (level === 4 && process.env.NODE_ENV === 'development') {
      return { continue: false, message: 'Skipping integration tests in dev' };
    }
    return { continue: true };
  },

  // Force pass certain validations
  afterValidation: async (ctx, state, result) => {
    if (!result.passed && result.isSystemIssue) {
      return {
        continue: true,
        data: { ...result, passed: true },
        message: 'Ignoring system issue'
      };
    }
    return { continue: true };
  },

  // Handle errors gracefully
  onError: async (ctx, error, errorContext) => {
    await sendToErrorTracking(error, {
      sessionId: ctx.sessionId,
      context: errorContext
    });
    return {
      continue: error.message.includes('recoverable'),
      message: 'Error reported to monitoring'
    };
  },

  // Cleanup after completion
  afterComplete: async (ctx, state) => {
    console.log(`[${ctx.sessionId}] Completed with status: ${state.status}`);
    await reportSessionMetrics(ctx.sessionId, state);
  }
};

// Register with high priority
registerHooks('my-plugin', myPluginHooks, 25);

Hook Utility Functions

Function Returns Description
registerHooks(name, hooks, priority?) void Register hook set (priority default: 100)
unregisterHooks(name) boolean Remove hooks by name
clearAllHooks() void Remove all hooks
getRegisteredHookNames() string[] List registered hook names
getHookCount() number Count of registered hook sets

Execution Order

Hooks execute in priority order (lower = first):

registerHooks('first', hooks1, 10);   // Executes 1st
registerHooks('second', hooks2, 50);  // Executes 2nd
registerHooks('third', hooks3, 100);  // Executes 3rd (default)
registerHooks('fourth', hooks4, 200); // Executes 4th

If a hook returns continue: false, subsequent hooks for that checkpoint are skipped