Status: Technical Analysis Complete
Date: 2025-08-01
Context: Enhancement plan for CoaiaPy Langfuse integration with output formatting and config merging
The proposed enhancement plan is technically feasible and aligns with CoaiaPy's existing architecture. All components are in place for implementation with minimal risk.
Current State:
coaiacli.pyline 231: Directprint(list_prompts())calllist_prompts()returns JSON string viajson.dumps(all_prompts, indent=2)- No existing
--jsonflag 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 formatData 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)Current Analysis:
find_existing_config()already prioritizes./coaia.jsonover$HOME/coaia.jsonread_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 resultAnalysis: Current list_prompts() pagination is comprehensive:
- Handles multiple pagination patterns (
hasNextPage,nextPage,totalPages) - Robust error handling for API failures
- Collects all pages in
all_promptsarray - Breaks appropriately when no more data
Recommendation: No changes needed. Pagination logic is production-ready.
- Risk: Loading all prompts into memory at once
- Mitigation: Current implementation acceptable for typical Langfuse usage
- Future: Consider streaming for 1000+ prompts
- 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
- Risk: Deep nested objects in config causing merge conflicts
- Mitigation: Implement recursive merge function as shown above
- Testing: Verify Langfuse keys merge correctly
- Risk: Breaking existing JSON output consumers
- Mitigation: Make
--jsonexplicit flag, default to pretty output - Alternative: Default to JSON, use
--prettyflag for table format
# 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)# 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# 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)))# 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"# 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
passdef test_pagination_edge_cases():
# Mock API responses for pagination testing
pass- Add
--jsonargument to parser - Implement
format_prompts_table()function - Update command handler logic
- Basic testing
- Implement
merge_configs()function - Update
read_config()logic - Add comprehensive tests
- Validate Langfuse key overrides
- Edge case handling
- Integration testing
- Documentation updates
- No new dependencies required
- Uses existing:
json,datetime,osmodules - Compatible with Python >=3.6 requirement
- Negligible: String formatting overhead minimal
- Memory: Table formatting requires loading full JSON (already done)
- Network: No additional API calls
- Backward Compatible:
--jsonflag preserves existing behavior - Forward Compatible: Extensible formatter pattern for future formats
- Python 3.6+: All recommended code compatible
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.