Files
proffesor-for-testing__agen…/docs/implementation/phase-1.2.2-baseagent-migration.md
Profa 9fd235d2e6 feat(phase-1): complete LLM Independence Phase 1 implementation
Phase 1.1 - OllamaProvider:
- Add OllamaProvider with all 13 ILLMProvider methods
- Add unit and integration tests for OllamaProvider
- Integrate with LLMProviderFactory auto-detection

Phase 1.2 - Agent Abstraction:
- Add IAgentLLM interface for provider-independent LLM access
- Add AgentLLMAdapter bridging ILLMProvider to IAgentLLM
- Update BaseAgent with getAgentLLM() method
- Migrate 4 LLM-active agents: TestGenerator, CoverageAnalyzer,
  CodeIntelligence, N8nBase
- 15 n8n agents inherit capability via N8nBaseAgent
- 17 algorithmic agents work without LLM by design

Phase 1.3 - Configuration:
- Add ProviderConfig types and ConfigLoader
- Add CLI providers commands (list, status, switch, test)
- Add example provider configurations

Documentation:
- Update implementation plan with accurate agent categorization
- Add usage examples for IAgentLLM patterns
- Add provider guides and research documents

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 11:19:04 +00:00

8.6 KiB

Phase 1.2.2: BaseAgent Migration to IAgentLLM

Status: ✅ Complete Date: 2025-12-24 Migration: BaseAgent.ts now uses IAgentLLM adapter

Overview

This migration adds the new IAgentLLM interface to BaseAgent, providing a simplified, provider-independent API for agents to make LLM calls while maintaining full backward compatibility with the existing ILLMProvider interface.

Changes Made

1. Added Imports

  • Imported IAgentLLM and AgentCompletionOptions from ./interfaces/IAgentLLM
  • Imported createAgentLLM from ./adapters/AgentLLMAdapter

File: /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts Lines: 61-63

2. Added Property

  • Added protected agentLLM?: IAgentLLM property alongside existing llmProvider
  • This provides the simplified API while keeping advanced access via llmProvider

File: /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts Line: 214

3. Updated initializeLLMProvider()

The method now creates an agentLLM wrapper after initializing any provider:

Locations updated:

  1. Injected provider (lines 777-781)
  2. HybridRouter (lines 811-815)
  3. RuvLLM provider (lines 844-848)
  4. Factory providers (lines 866-870)

All paths now execute:

this.agentLLM = createAgentLLM(this.llmProvider, {
  agentId: this.agentId.id,
  defaultModel: this.llmConfig.ruvllm?.defaultModel,
});

4. Updated hasLLM()

Now checks for both interfaces:

public hasLLM(): boolean {
  return this.llmProvider !== undefined || this.agentLLM !== undefined;
}

File: /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts Lines: 991-993

5. Added getAgentLLM() Method

New public method to access the simplified interface:

public getAgentLLM(): IAgentLLM | undefined {
  return this.agentLLM;
}

File: /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts Lines: 1002-1017

6. Updated llmComplete() Documentation

Added note about using agentLLM.complete() for simpler API:

/**
 * Make an LLM completion call
 * Uses RuvLLM's session management for 50% latency reduction on multi-turn
 *
 * NOTE: Phase 1.2.2 - Consider using this.agentLLM.complete() for a simpler API
 * that doesn't require manual message construction.
 * ...
 */

File: /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts Lines: 1019-1031

7. Created Interface Exports

Created /workspaces/agentic-qe-cf/src/agents/interfaces/index.ts to export:

  • IAgentLLM (type)
  • AgentCompletionOptions (type)
  • AgentUsageStats (type)
  • AgentModelInfo (type)
  • AgentLLMError (class)
  • isAgentLLMError (function)

Backward Compatibility

✅ 100% Backward Compatible

  1. Existing code continues to work: All existing llmComplete(), llmEmbed(), and llmBatchComplete() methods remain unchanged
  2. getLLMProvider() still available: Advanced users can still access the raw provider
  3. hasLLM() enhanced: Now returns true if either interface is available
  4. No breaking changes: All method signatures preserved

New Capabilities

Agents can now use the simpler IAgentLLM interface:

Before (Complex - still works):

const response = await this.llmProvider!.complete({
  model: 'llama-3.2-3b-instruct',
  messages: [{ role: 'user', content: prompt }],
  maxTokens: 2048,
  temperature: 0.7,
  metadata: { agentId: this.agentId.id }
});

const text = response.content
  .filter(block => block.type === 'text')
  .map(block => block.text)
  .join('\n');
const llm = this.getAgentLLM();
const text = await llm!.complete(prompt, {
  maxTokens: 2048,
  temperature: 0.7,
  complexity: 'moderate'
});

Usage Examples

Basic Completion

protected async generateTests(sourceCode: string): Promise<string> {
  const llm = this.getAgentLLM();
  if (!llm) {
    throw new Error('LLM not available');
  }

  return await llm.complete(
    `Generate Jest tests for:\n${sourceCode}`,
    {
      complexity: 'moderate',
      temperature: 0.2,
      maxTokens: 2048
    }
  );
}

With Streaming

protected async *streamResponse(prompt: string): AsyncIterableIterator<string> {
  const llm = this.getAgentLLM();
  if (!llm) return;

  for await (const chunk of llm.streamComplete(prompt, { stream: true })) {
    yield chunk;
  }
}

Embeddings

protected async findSimilarPatterns(query: string): Promise<any[]> {
  const llm = this.getAgentLLM();
  if (!llm) return [];

  const embedding = await llm.embed(query);
  return await this.searchQEPatterns(embedding, 10);
}

Model Management

protected async ensureBestModel(): Promise<void> {
  const llm = this.getAgentLLM();
  if (!llm) return;

  const models = await llm.getAvailableModels();
  const bestModel = models.find(m => m.id.includes('sonnet'));

  if (bestModel) {
    await llm.switchModel(bestModel.id);
  }
}

Usage Tracking

protected async analyzePerformance(): Promise<void> {
  const llm = this.getAgentLLM();
  if (!llm) return;

  const stats = llm.getUsageStats();
  console.log(`Requests: ${stats.requestCount}`);
  console.log(`Tokens: ${stats.tokensUsed}`);
  console.log(`Cost: $${stats.costIncurred.toFixed(4)}`);
  console.log(`Avg Latency: ${stats.averageLatency.toFixed(2)}ms`);
  console.log(`Cache Hit Rate: ${((stats.cacheHitRate || 0) * 100).toFixed(1)}%`);
}

Testing

Created comprehensive test suite: /workspaces/agentic-qe-cf/tests/unit/agents/BaseAgent.agentLLM.test.ts

Test Results: ✅ 11/11 passed

Test Coverage

  1. Initialization

    • Creates agentLLM when provider is injected
    • Skips agentLLM when LLM is disabled
    • Exposes both getLLMProvider() and getAgentLLM()
  2. API Usage

    • Simple completions via complete()
    • Usage statistics tracking
    • Embedding generation
    • Health checks
    • Model listing
    • Current model retrieval
  3. Backward Compatibility

    • hasLLM() works with both interfaces
    • getLLMProvider() still accessible for advanced usage

Build Verification

✅ TypeScript compilation passes with no errors:

npm run build
# Success - no errors

Migration Path for Agents

  1. New agents: Use getAgentLLM() exclusively for simpler code
  2. Existing agents: Can migrate incrementally by replacing llmComplete() calls with agentLLM.complete()
  3. Advanced usage: Keep using getLLMProvider() when needed (e.g., batch operations, sessions)

Example Migration

// Old approach (still works)
protected async oldMethod(prompt: string): Promise<string> {
  if (!this.llmProvider) throw new Error('LLM not available');
  const response = await this.llmProvider.complete({
    model: 'llama-3.2-3b-instruct',
    messages: [{ role: 'user', content: prompt }],
    maxTokens: 2048,
  });
  return response.content
    .filter(block => block.type === 'text')
    .map(block => block.text)
    .join('\n');
}

// New approach (recommended)
protected async newMethod(prompt: string): Promise<string> {
  const llm = this.getAgentLLM();
  if (!llm) throw new Error('LLM not available');
  return await llm.complete(prompt, { maxTokens: 2048 });
}

Benefits

  1. Simpler API: No manual message construction or text extraction
  2. Provider Independence: Agents don't need to know about specific providers
  3. Automatic Routing: HybridRouter complexity routing works transparently
  4. Usage Tracking: Built-in statistics per agent
  5. Type Safety: Full TypeScript support with clear interfaces
  6. Backward Compatible: Existing code continues to work unchanged

Next Steps

  1. ✅ BaseAgent migrated (this document)
  2. 🔄 Update specialized agents to use getAgentLLM() (optional, can be done incrementally)
  3. 🔄 Update documentation to recommend getAgentLLM() for new agents
  4. 🔄 Consider deprecation timeline for llmComplete() in favor of agentLLM.complete() (v3.0.0)
  • /workspaces/agentic-qe-cf/src/agents/BaseAgent.ts - Main implementation
  • /workspaces/agentic-qe-cf/src/agents/interfaces/IAgentLLM.ts - Interface definition
  • /workspaces/agentic-qe-cf/src/agents/adapters/AgentLLMAdapter.ts - Adapter implementation
  • /workspaces/agentic-qe-cf/src/agents/interfaces/index.ts - Interface exports
  • /workspaces/agentic-qe-cf/tests/unit/agents/BaseAgent.agentLLM.test.ts - Test suite

References

  • Phase 1.2.2 Plan: /workspaces/agentic-qe-cf/docs/phase-1.2.2-agent-llm-abstraction.md
  • LLM Providers Guide: /workspaces/agentic-qe-cf/docs/guides/llm-providers-guide.md
  • Configuration Guide: /workspaces/agentic-qe-cf/docs/guides/configuration-guide.md