Skip to content

Latest commit

 

History

History
338 lines (261 loc) · 9.9 KB

File metadata and controls

338 lines (261 loc) · 9.9 KB

MIA.md - CoaiaPy Langfuse Enhancement Technical Analysis

Status: Technical Analysis Complete
Date: 2025-08-01
Context: Enhancement plan for CoaiaPy Langfuse integration with output formatting and config merging


🔍 Technical Validation

Plan Assessment: ARCHITECTURALLY SOUND

The proposed enhancement plan is technically feasible and aligns with CoaiaPy's existing architecture. All components are in place for implementation with minimal risk.


📋 Implementation Recommendations

1. CLI Flag IntegrationLOW COMPLEXITY

Current State:

  • coaiacli.py line 231: Direct print(list_prompts()) call
  • list_prompts() returns JSON string via json.dumps(all_prompts, indent=2)
  • No existing --json flag infrastructure

Recommended Implementation:

# In coaiacli.py argument parser setup
parser_fuse_prompts.add_argument('--json', action='store_true', 
                                help="Output in JSON format (default: pretty table)")

# In command handling (line 230-231)
if args.action == 'list':
    if args.json:
        print(list_prompts())  # Existing JSON output
    else:
        print(format_prompts_pretty(list_prompts()))  # New pretty format

2. Pretty Output Formatting ⭐⭐ MEDIUM COMPLEXITY

Data Structure Analysis:

# From cofuse.py list_prompts() - returns JSON string of:
[
  {
    "name": "prompt_name",  
    "version": 1,
    "createdAt": "2024-01-01T00:00:00Z",
    "labels": ["tag1", "tag2"],
    // additional fields...
  }
]

Recommended Implementation:

def format_prompts_pretty(json_string):
    import json
    from datetime import datetime
    
    prompts = json.loads(json_string)
    if not prompts:
        return "No prompts found."
    
    # Table formatting
    headers = ["Name", "Version", "Created", "Labels"]
    rows = []
    
    for prompt in prompts:
        created = prompt.get('createdAt', 'N/A')
        if created != 'N/A':
            # Format ISO timestamp to readable date
            created = datetime.fromisoformat(created.replace('Z', '+00:00')).strftime('%Y-%m-%d')
        
        labels = ', '.join(prompt.get('labels', []) or [])
        rows.append([
            prompt.get('name', 'N/A'),
            str(prompt.get('version', 'N/A')), 
            created,
            labels or 'None'
        ])
    
    # Calculate column widths
    col_widths = [len(h) for h in headers]
    for row in rows:
        for i, cell in enumerate(row):
            col_widths[i] = max(col_widths[i], len(str(cell)))
    
    # Format table
    output = []
    header_row = " | ".join(h.ljust(col_widths[i]) for i, h in enumerate(headers))
    output.append(header_row)
    output.append("-" * len(header_row))
    
    for row in rows:
        output.append(" | ".join(str(cell).ljust(col_widths[i]) for i, cell in enumerate(row)))
    
    return "\n".join(output)

3. Config Override System ⭐⭐⭐ HIGH COMPLEXITY

Current Analysis:

  • find_existing_config() already prioritizes ./coaia.json over $HOME/coaia.json
  • read_config() loads single config file (no merging)
  • Environment variable overrides already implemented

Required Enhancement:

def read_config():
    global config
    
    if config is None:
        # Load base config from HOME first
        home_config = {}
        home_path = os.path.join(os.getenv('HOME', ''), 'coaia.json')
        if os.path.exists(home_path):
            with open(home_path) as f:
                home_config = json.load(f)
        
        # Load local config for overrides
        local_config = {}
        if os.path.exists('./coaia.json'):
            with open('./coaia.json') as f:
                local_config = json.load(f)
        
        # Merge configs (local overrides home)
        config = merge_configs(home_config, local_config)
        
        # Apply environment variable overrides (existing logic)
        apply_env_overrides(config)
    
    return config

def merge_configs(base_config, override_config):
    """Deep merge configuration objects with override precedence"""
    import copy
    result = copy.deepcopy(base_config)
    
    for key, value in override_config.items():
        if isinstance(value, dict) and key in result and isinstance(result[key], dict):
            result[key] = merge_configs(result[key], value)
        else:
            result[key] = value
    
    return result

4. Pagination ValidationALREADY ROBUST

Analysis: Current list_prompts() pagination is comprehensive:

  • Handles multiple pagination patterns (hasNextPage, nextPage, totalPages)
  • Robust error handling for API failures
  • Collects all pages in all_prompts array
  • Breaks appropriately when no more data

Recommendation: No changes needed. Pagination logic is production-ready.


⚠️ Potential Issues & Mitigations

1. Memory Usage with Large Prompt Lists

  • Risk: Loading all prompts into memory at once
  • Mitigation: Current implementation acceptable for typical Langfuse usage
  • Future: Consider streaming for 1000+ prompts

2. Table Formatting Edge Cases

  • Risk: Very long prompt names or labels breaking table layout
  • Mitigation: Add truncation with ellipsis for cells > 50 characters
  • Implementation: cell[:47] + "..." if len(cell) > 50 else cell

3. Config Merge Complexity

  • Risk: Deep nested objects in config causing merge conflicts
  • Mitigation: Implement recursive merge function as shown above
  • Testing: Verify Langfuse keys merge correctly

4. Backward Compatibility

  • Risk: Breaking existing JSON output consumers
  • Mitigation: Make --json explicit flag, default to pretty output
  • Alternative: Default to JSON, use --pretty flag for table format

🏗️ Code Architecture Recommendations

1. Modular Design

# New module: coaiapy/formatters.py
def format_prompts_table(prompts_data):
    """Pretty table formatting for prompts"""
    pass

def format_prompts_json(prompts_data):
    """JSON formatting for prompts (existing logic)"""
    pass

def format_output(data, format_type='pretty'):
    """Unified formatter dispatcher"""
    formatters = {
        'json': format_prompts_json,
        'pretty': format_prompts_table,
        'table': format_prompts_table
    }
    return formatters.get(format_type, format_prompts_pretty)(data)

2. Configuration Architecture

# Enhanced coaiamodule.py structure
class ConfigManager:
    def __init__(self):
        self.config = None
        self.config_sources = []
    
    def load_config(self):
        """Load and merge configuration from multiple sources"""
        pass
    
    def get_config(self):
        """Get merged configuration with caching"""
        pass

3. CLI Integration Pattern

# In coaiacli.py - consistent pattern for output formatting
def handle_fuse_prompts_list(args):
    prompts_json = list_prompts()
    if args.json:
        print(prompts_json)
    else:
        print(format_prompts_table(json.loads(prompts_json)))

🧪 Testing Strategy Recommendations

1. Unit Tests

# test_formatters.py
def test_format_prompts_table():
    sample_data = [{"name": "test", "version": 1, "createdAt": "2024-01-01T00:00:00Z", "labels": ["tag1"]}]
    result = format_prompts_table(json.dumps(sample_data))
    assert "Name" in result
    assert "test" in result

def test_config_merge():
    base = {"langfuse_secret_key": "base", "other": "value"}
    override = {"langfuse_secret_key": "override"}
    result = merge_configs(base, override)
    assert result["langfuse_secret_key"] == "override"
    assert result["other"] == "value"

2. Integration Tests

# test_cli_integration.py
def test_prompts_list_json_flag():
    # Test --json flag produces JSON output
    pass

def test_prompts_list_pretty_default():
    # Test default pretty output format
    pass

def test_config_override_integration():
    # Test HOME + local config merging
    pass

3. Mock Testing for API

def test_pagination_edge_cases():
    # Mock API responses for pagination testing
    pass

🎯 Implementation Priority

Phase 1: CLI Flag & Pretty Output (2-3 hours)

  1. Add --json argument to parser
  2. Implement format_prompts_table() function
  3. Update command handler logic
  4. Basic testing

Phase 2: Config Merging (3-4 hours)

  1. Implement merge_configs() function
  2. Update read_config() logic
  3. Add comprehensive tests
  4. Validate Langfuse key overrides

Phase 3: Polish & Testing (1-2 hours)

  1. Edge case handling
  2. Integration testing
  3. Documentation updates

📊 Technical Specifications

Dependencies

  • No new dependencies required
  • Uses existing: json, datetime, os modules
  • Compatible with Python >=3.6 requirement

Performance Impact

  • Negligible: String formatting overhead minimal
  • Memory: Table formatting requires loading full JSON (already done)
  • Network: No additional API calls

Compatibility

  • Backward Compatible: --json flag preserves existing behavior
  • Forward Compatible: Extensible formatter pattern for future formats
  • Python 3.6+: All recommended code compatible

✅ Conclusion

The enhancement plan is technically sound and ready for implementation. The existing codebase provides solid foundations:

  • ✅ Pagination already robust and complete
  • ✅ Configuration loading architecture easily extensible
  • ✅ CLI argument parsing framework in place
  • ✅ Error handling patterns established

Recommended Approach: Implement in 3 phases as outlined above, with Phase 1 providing immediate user value and Phase 2 completing the configuration enhancement.

Risk Assessment: LOW - All changes are additive and maintain backward compatibility.


Implementation Ready: All technical requirements validated and implementation path clear.