brainy/docs/augmentations-archive/AUGMENTATION-EXAMPLES.md
David Snelling 994276f09f docs: consolidate and archive redundant documentation
- Archived 13 API design iterations to docs/api-design-archive/
- Consolidated augmentation docs to docs/augmentations-archive/
- Maintained ONE definitive API doc at docs/api/README.md
- Cleaned up documentation structure for 2.0 release
- Preserved all historical documents for reference
2025-08-25 10:15:38 -07:00

20 KiB

🚀 Real-World Augmentation Examples

1. 💬 Chat Interface Augmentation

"Talk to your data through natural language"

import { BaseAugmentation } from './brainyAugmentation.js'

export class ChatInterfaceAugmentation extends BaseAugmentation {
  readonly name = 'chat-interface'
  readonly timing = 'after' as const  // Process after operations
  readonly operations = ['search', 'add', 'delete'] as const
  readonly priority = 30  // Medium priority
  
  private chatHistory: Array<{role: string, content: string}> = []
  private llmClient: any  // User's chosen LLM
  
  protected async onInitialize(): Promise<void> {
    // User provides their own LLM
    this.llmClient = this.context.config.llmClient || null
    if (!this.llmClient) {
      this.log('Chat augmentation needs LLM client in config')
    }
  }
  
  async execute<T>(operation: string, params: any, next: () => Promise<T>): Promise<T> {
    // If params include natural language query
    if (params.chatQuery) {
      // Convert natural language to Brainy operations
      const intent = await this.parseIntent(params.chatQuery)
      
      // Transform params based on intent
      if (intent.type === 'search') {
        params.query = intent.query
        params.k = intent.limit || 10
      } else if (intent.type === 'add') {
        params.content = intent.content
        params.metadata = { ...params.metadata, source: 'chat' }
      }
      
      // Store in chat history
      this.chatHistory.push({
        role: 'user',
        content: params.chatQuery
      })
    }
    
    // Execute the operation
    const result = await next()
    
    // Generate conversational response
    if (params.chatQuery && this.llmClient) {
      const response = await this.generateResponse(operation, result)
      
      this.chatHistory.push({
        role: 'assistant', 
        content: response
      })
      
      // Enhance result with chat response
      return {
        ...result,
        chatResponse: response,
        chatHistory: this.chatHistory
      } as T
    }
    
    return result
  }
  
  private async parseIntent(query: string) {
    // Use Brainy's NLP patterns + LLM to understand intent
    const prompt = `Parse this query into a Brainy operation:
    Query: ${query}
    
    Return JSON with:
    - type: 'search' | 'add' | 'delete' | 'relate'
    - query: search terms or content
    - filters: any metadata filters
    - limit: number of results`
    
    const response = await this.llmClient.complete(prompt)
    return JSON.parse(response)
  }
  
  private async generateResponse(operation: string, result: any) {
    const prompt = `Generate a friendly response for this operation:
    Operation: ${operation}
    Result: ${JSON.stringify(result).slice(0, 500)}
    Chat History: ${JSON.stringify(this.chatHistory.slice(-3))}
    
    Be conversational and helpful.`
    
    return await this.llmClient.complete(prompt)
  }
}

// Usage:
const brain = new BrainyData({
  augmentations: [
    new ChatInterfaceAugmentation()
  ],
  llmClient: openai  // Bring your own LLM
})

// Now you can chat!
const result = await brain.search({
  chatQuery: "Show me all documents about project roadmap from last week"
})
console.log(result.chatResponse)  // "I found 5 documents about the project roadmap..."

2. 🤖 MCP Agent Memory Augmentation

"Provide persistent memory for AI agents through MCP"

import { BaseAugmentation } from './brainyAugmentation.js'
import { Server } from '@modelcontextprotocol/sdk'

export class MCPAgentMemoryAugmentation extends BaseAugmentation {
  readonly name = 'mcp-agent-memory'
  readonly timing = 'around' as const  // Wrap operations
  readonly operations = ['all'] as const  // Monitor everything
  readonly priority = 70  // High priority
  
  private mcpServer: Server
  private agentSessions: Map<string, any> = new Map()
  
  protected async onInitialize(): Promise<void> {
    // Initialize MCP server
    this.mcpServer = new Server({
      name: 'brainy-memory',
      version: '1.0.0'
    })
    
    // Register MCP tools for agents
    this.mcpServer.setRequestHandler('tools/list', () => ({
      tools: [
        {
          name: 'remember',
          description: 'Store information in long-term memory',
          inputSchema: {
            type: 'object',
            properties: {
              content: { type: 'string' },
              category: { type: 'string' },
              importance: { type: 'number' }
            }
          }
        },
        {
          name: 'recall',
          description: 'Retrieve information from memory',
          inputSchema: {
            type: 'object',
            properties: {
              query: { type: 'string' },
              category: { type: 'string' },
              limit: { type: 'number' }
            }
          }
        },
        {
          name: 'forget',
          description: 'Remove information from memory',
          inputSchema: {
            type: 'object',
            properties: {
              query: { type: 'string' },
              category: { type: 'string' }
            }
          }
        }
      ]
    }))
    
    // Handle tool calls from agents
    this.mcpServer.setRequestHandler('tools/call', async (request) => {
      const { name, arguments: args } = request.params
      
      switch (name) {
        case 'remember':
          return await this.rememberForAgent(args)
        case 'recall':
          return await this.recallForAgent(args)
        case 'forget':
          return await this.forgetForAgent(args)
        default:
          throw new Error(`Unknown tool: ${name}`)
      }
    })
    
    // Start MCP server
    await this.mcpServer.connect(process.stdin, process.stdout)
    this.log('MCP Agent Memory server started')
  }
  
  async execute<T>(operation: string, params: any, next: () => Promise<T>): Promise<T> {
    // Extract agent context if present
    const agentId = params.metadata?._agentId || 'default'
    const sessionId = params.metadata?._sessionId
    
    // Track agent operations
    if (agentId && sessionId) {
      if (!this.agentSessions.has(sessionId)) {
        this.agentSessions.set(sessionId, {
          agentId,
          startTime: Date.now(),
          operations: []
        })
      }
      
      const session = this.agentSessions.get(sessionId)
      session.operations.push({
        operation,
        params: { ...params },
        timestamp: Date.now()
      })
    }
    
    // Execute with agent context
    const result = await next()
    
    // Auto-remember important operations
    if (operation === 'add' && agentId) {
      await this.autoRemember(agentId, params, result)
    }
    
    return result
  }
  
  private async rememberForAgent(args: any) {
    // Store in Brainy with agent-specific metadata
    const id = await this.context.brain.add(args.content, {
      _agentMemory: true,
      _agentId: args.agentId || 'default',
      category: args.category,
      importance: args.importance || 0.5,
      timestamp: new Date().toISOString()
    })
    
    return {
      content: [
        {
          type: 'text',
          text: `Remembered with ID: ${id}`
        }
      ]
    }
  }
  
  private async recallForAgent(args: any) {
    // Search agent's memories
    const results = await this.context.brain.search(args.query, args.limit || 10, {
      where: {
        _agentMemory: true,
        _agentId: args.agentId || 'default',
        category: args.category
      }
    })
    
    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(results, null, 2)
        }
      ]
    }
  }
  
  private async forgetForAgent(args: any) {
    // Remove specific memories
    const results = await this.context.brain.find({
      where: {
        _agentMemory: true,
        _agentId: args.agentId || 'default',
        category: args.category
      }
    })
    
    for (const item of results) {
      await this.context.brain.delete(item.id)
    }
    
    return {
      content: [
        {
          type: 'text',
          text: `Forgot ${results.length} memories`
        }
      ]
    }
  }
  
  private async autoRemember(agentId: string, params: any, result: any) {
    // Automatically remember important information
    if (params.metadata?.important) {
      await this.context.brain.add(params.content, {
        ...params.metadata,
        _agentMemory: true,
        _agentId: agentId,
        _autoRemembered: true,
        _originalOperation: 'add',
        _resultId: result
      })
    }
  }
}

// Usage:
const brain = new BrainyData({
  augmentations: [
    new MCPAgentMemoryAugmentation()
  ]
})

// Now AI agents can use Brainy as memory through MCP!
// Agents connect via MCP and use remember/recall/forget tools

3. 🌐 API Server Augmentation

"Expose Brainy through REST, WebSocket, and MCP APIs"

import { BaseAugmentation } from './brainyAugmentation.js'
import { BrainyMCPService } from '../mcp/brainyMCPService.js'

export class APIServerAugmentation extends BaseAugmentation {
  readonly name = 'api-server'
  readonly timing = 'after' as const
  readonly operations = ['all'] as ('all')[]
  readonly priority = 5  // Low priority, runs after other augmentations
  
  private httpServer: any
  private wsServer: any
  private mcpService: BrainyMCPService
  
  protected async onInitialize(): Promise<void> {
    // Initialize MCP service
    this.mcpService = new BrainyMCPService(this.context.brain)
    
    // Start HTTP server with REST endpoints
    await this.startHTTPServer()
    
    // Start WebSocket server for real-time
    await this.startWebSocketServer()
    
    this.log(`API Server running on port ${this.config.port || 3000}`)
  }
  
  async execute<T>(operation: string, params: any, next: () => Promise<T>): Promise<T> {
    const result = await next()
    
    // Broadcast operation to WebSocket clients
    this.broadcast({
      type: 'operation',
      operation,
      params: this.sanitizeParams(params),
      timestamp: Date.now()
    })
    
    return result
  }
  
  private async startHTTPServer() {
    // REST endpoints: /api/search, /api/add, /api/get/:id, etc.
    // MCP endpoint: /api/mcp
    // Health check: /health
  }
  
  private async startWebSocketServer() {
    // WebSocket for real-time subscriptions
    // Clients can subscribe to specific operations
  }
}

// Usage:
const brain = new BrainyData()
brain.augmentations.register(new APIServerAugmentation({ port: 3000 }))
await brain.init()

// Now access Brainy via:
// - REST: http://localhost:3000/api/*
// - WebSocket: ws://localhost:3000/ws
// - MCP: http://localhost:3000/api/mcp

4. 📊 Graph Visualization Augmentation

"Real-time graph visualization with clustering"

import { BaseAugmentation } from './brainyAugmentation.js'
import { WebSocketServer } from 'ws'

export class GraphVisualizationAugmentation extends BaseAugmentation {
  readonly name = 'graph-visualization'
  readonly timing = 'after' as const
  readonly operations = ['all'] as const  // Monitor all changes
  readonly priority = 20
  
  private wsServer: WebSocketServer
  private graphState: {
    nodes: Map<string, any>
    edges: Map<string, any>
    clusters: Map<string, Set<string>>
  }
  private clients: Set<any> = new Set()
  
  protected async onInitialize(): Promise<void> {
    // Initialize WebSocket server for real-time updates
    this.wsServer = new WebSocketServer({ 
      port: this.context.config.visualizationPort || 8080 
    })
    
    this.graphState = {
      nodes: new Map(),
      edges: new Map(),
      clusters: new Map()
    }
    
    // Load initial graph state
    await this.loadGraphState()
    
    // Handle client connections
    this.wsServer.on('connection', (ws) => {
      this.clients.add(ws)
      
      // Send initial state
      ws.send(JSON.stringify({
        type: 'init',
        data: this.serializeGraphState()
      }))
      
      // Handle client messages
      ws.on('message', async (message) => {
        const msg = JSON.parse(message.toString())
        await this.handleClientMessage(msg, ws)
      })
      
      ws.on('close', () => {
        this.clients.delete(ws)
      })
    })
    
    // Start clustering in background
    this.startClusteringWorker()
    
    this.log('Graph visualization server started on port ' + 
             (this.context.config.visualizationPort || 8080))
  }
  
  async execute<T>(operation: string, params: any, next: () => Promise<T>): Promise<T> {
    const result = await next()
    
    // Update graph state based on operation
    switch (operation) {
      case 'add':
      case 'addNoun':
        await this.handleNodeAdded(result, params)
        break
        
      case 'relate':
      case 'addVerb':
        await this.handleEdgeAdded(params)
        break
        
      case 'delete':
        await this.handleNodeDeleted(params)
        break
        
      case 'search':
        await this.handleSearchPerformed(params, result)
        break
    }
    
    return result
  }
  
  private async handleNodeAdded(id: string, data: any) {
    // Add node to graph
    const node = {
      id,
      label: data.content?.slice(0, 50) || id,
      type: data.metadata?.type || 'default',
      metadata: data.metadata,
      position: this.calculatePosition(id),
      clusterId: null
    }
    
    this.graphState.nodes.set(id, node)
    
    // Broadcast to clients
    this.broadcast({
      type: 'nodeAdded',
      data: node
    })
    
    // Trigger re-clustering
    this.scheduleReClustering()
  }
  
  private async handleEdgeAdded(params: any) {
    const edge = {
      id: `${params.source}-${params.verb}-${params.target}`,
      source: params.source,
      target: params.target,
      label: params.verb,
      weight: params.weight || 1
    }
    
    this.graphState.edges.set(edge.id, edge)
    
    this.broadcast({
      type: 'edgeAdded',
      data: edge
    })
  }
  
  private async handleSearchPerformed(params: any, results: any) {
    // Highlight search results in visualization
    const highlightNodes = results.map((r: any) => r.id)
    
    this.broadcast({
      type: 'highlight',
      data: {
        nodes: highlightNodes,
        query: params.query,
        duration: 5000  // Highlight for 5 seconds
      }
    })
  }
  
  private async loadGraphState() {
    // Load all nodes (nouns)
    const nouns = await this.context.brain.getAllNouns()
    for (const noun of nouns) {
      this.graphState.nodes.set(noun.id, {
        id: noun.id,
        label: noun.content?.slice(0, 50) || noun.id,
        type: noun.type,
        metadata: noun.metadata,
        position: this.calculatePosition(noun.id)
      })
    }
    
    // Load all edges (verbs/relationships)
    const verbs = await this.context.brain.getAllVerbs()
    for (const verb of verbs) {
      this.graphState.edges.set(verb.id, {
        id: verb.id,
        source: verb.source,
        target: verb.target,
        label: verb.type,
        weight: verb.weight
      })
    }
    
    // Initial clustering
    await this.performClustering()
  }
  
  private async performClustering() {
    // Use Brainy's clustering capabilities
    const clusteringResult = await this.context.brain.cluster({
      algorithm: 'hierarchical',
      threshold: 0.7
    })
    
    // Update cluster state
    this.graphState.clusters.clear()
    for (const [clusterId, nodeIds] of Object.entries(clusteringResult)) {
      this.graphState.clusters.set(clusterId, new Set(nodeIds as string[]))
      
      // Update nodes with cluster IDs
      for (const nodeId of nodeIds as string[]) {
        const node = this.graphState.nodes.get(nodeId)
        if (node) {
          node.clusterId = clusterId
        }
      }
    }
    
    // Broadcast cluster update
    this.broadcast({
      type: 'clustersUpdated',
      data: this.serializeClusters()
    })
  }
  
  private startClusteringWorker() {
    // Re-cluster periodically or when graph changes significantly
    setInterval(async () => {
      if (this.graphState.nodes.size > 0) {
        await this.performClustering()
      }
    }, 30000)  // Every 30 seconds
  }
  
  private scheduleReClustering = (() => {
    let timeout: NodeJS.Timeout
    return () => {
      clearTimeout(timeout)
      timeout = setTimeout(() => this.performClustering(), 5000)
    }
  })()
  
  private calculatePosition(id: string) {
    // Simple force-directed layout position
    const hash = id.split('').reduce((a, b) => {
      a = ((a << 5) - a) + b.charCodeAt(0)
      return a & a
    }, 0)
    
    return {
      x: (hash % 1000) - 500,
      y: ((hash * 7) % 1000) - 500
    }
  }
  
  private broadcast(message: any) {
    const data = JSON.stringify(message)
    for (const client of this.clients) {
      client.send(data)
    }
  }
  
  private async handleClientMessage(msg: any, ws: any) {
    switch (msg.type) {
      case 'requestClustering':
        await this.performClustering()
        break
        
      case 'search':
        const results = await this.context.brain.search(msg.query)
        ws.send(JSON.stringify({
          type: 'searchResults',
          data: results
        }))
        break
        
      case 'getNodeDetails':
        const node = await this.context.brain.get(msg.nodeId)
        ws.send(JSON.stringify({
          type: 'nodeDetails',
          data: node
        }))
        break
        
      case 'expandNode':
        const connections = await this.context.brain.getConnections(msg.nodeId)
        ws.send(JSON.stringify({
          type: 'nodeConnections',
          data: connections
        }))
        break
    }
  }
  
  private serializeGraphState() {
    return {
      nodes: Array.from(this.graphState.nodes.values()),
      edges: Array.from(this.graphState.edges.values()),
      clusters: this.serializeClusters()
    }
  }
  
  private serializeClusters() {
    const clusters: any = {}
    for (const [id, nodeIds] of this.graphState.clusters) {
      clusters[id] = Array.from(nodeIds)
    }
    return clusters
  }
  
  protected async onShutdown() {
    this.wsServer.close()
    this.clients.clear()
  }
}

// Usage:
const brain = new BrainyData({
  augmentations: [
    new GraphVisualizationAugmentation()
  ],
  visualizationPort: 8080
})

// Now connect a web-based graph viz tool to ws://localhost:8080
// It receives real-time updates as data changes!

4. 🌐 Multi-Agent Team Coordination

"Multiple AI agents sharing knowledge and coordinating tasks"

export class TeamCoordinationAugmentation extends BaseAugmentation {
  readonly name = 'team-coordination'
  readonly timing = 'around' as const
  readonly operations = ['all'] as const
  readonly priority = 85
  
  private agents: Map<string, AgentState> = new Map()
  private tasks: Map<string, Task> = new Map()
  private sharedMemory: Map<string, any> = new Map()
  
  async execute<T>(operation: string, params: any, next: () => Promise<T>): Promise<T> {
    const agentId = params.metadata?._agentId
    
    if (agentId) {
      // Track agent activity
      this.updateAgentState(agentId, operation, params)
      
      // Check if operation needs coordination
      if (await this.needsCoordination(operation, params)) {
        return await this.coordinatedExecute(agentId, operation, params, next)
      }
    }
    
    return next()
  }
  
  private async coordinatedExecute<T>(
    agentId: string,
    operation: string,
    params: any,
    next: () => Promise<T>
  ): Promise<T> {
    // Acquire distributed lock
    const lockId = await this.acquireLock(operation, params)
    
    try {
      // Check shared memory for related work
      const relatedWork = await this.findRelatedWork(params)
      if (relatedWork) {
        params.metadata._relatedWork = relatedWork
      }
      
      // Execute with team context
      const result = await next()
      
      // Update shared memory
      await this.updateSharedMemory(agentId, operation, params, result)
      
      // Notify other agents
      await this.notifyTeam(agentId, operation, result)
      
      return result
    } finally {
      await this.releaseLock(lockId)
    }
  }
}

🎯 Key Patterns

All these augmentations follow the same pattern:

  1. Extend BaseAugmentation
  2. Define timing & operations
  3. Initialize resources in onInitialize()
  4. Intercept operations in execute()
  5. Clean up in onShutdown()

They can:

  • Add APIs (REST, WebSocket, MCP)
  • Transform data (chat queries → operations)
  • Coordinate agents (distributed locking, shared memory)
  • Visualize in real-time (WebSocket broadcasts)
  • Integrate any service (LLMs, databases, APIs)

The beauty is they all use the same simple interface but achieve vastly different goals!