| """ |
| Agent API — FastAPI endpoints for demo and dashboard interaction. |
| |
| Endpoints: |
| POST /run-episode - Run one episode and return metrics |
| POST /run-comparison - Run baseline vs memory comparison |
| GET /metrics - Get training/episode history |
| GET /memory/stats - Memory store statistics |
| GET /memory/search - Search memory for lessons |
| POST /memory/clear - Clear memory store |
| GET /health - Health check |
| """ |
|
|
| import json |
| import os |
| import sys |
| from pathlib import Path |
| from typing import Optional |
|
|
| from fastapi import FastAPI, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from pydantic import BaseModel |
|
|
| sys.path.append(str(Path(__file__).resolve().parent.parent)) |
|
|
| from memory.memory_store import MemoryStore |
|
|
| app = FastAPI(title="ToolMind Agent API", version="1.0.0") |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| DATA_DIR = Path(__file__).resolve().parent.parent / "data" |
| METRICS_FILE = DATA_DIR / "training_log.json" |
|
|
| memory_store = MemoryStore(persist_dir=str(DATA_DIR / "chroma_data")) |
|
|
|
|
| class EpisodeRequest(BaseModel): |
| task_type: str = "hard" |
| use_memory: bool = True |
| episode_num: int = 0 |
|
|
|
|
| class ComparisonRequest(BaseModel): |
| task_type: str = "hard" |
| num_episodes: int = 3 |
|
|
|
|
| class MemorySearchRequest(BaseModel): |
| query: str |
| n_results: int = 3 |
|
|
|
|
| def _load_metrics() -> list[dict]: |
| if METRICS_FILE.exists(): |
| with open(METRICS_FILE) as f: |
| return json.load(f) |
| return [] |
|
|
|
|
| def _save_metrics(metrics: list[dict]): |
| with open(METRICS_FILE, "w") as f: |
| json.dump(metrics, f, indent=2) |
|
|
|
|
| @app.get("/health") |
| def health(): |
| return { |
| "status": "ok", |
| "memory_entries": memory_store.count(), |
| "metrics_entries": len(_load_metrics()), |
| } |
|
|
|
|
| @app.post("/run-episode") |
| def run_episode(req: EpisodeRequest): |
| """Run a single episode and return results.""" |
| try: |
| from agent.combined_agent import CombinedAgent |
|
|
| agent = CombinedAgent( |
| use_memory=req.use_memory, |
| memory_dir=str(DATA_DIR / "chroma_data"), |
| ) |
| result = agent.run_episode( |
| task_type=req.task_type, |
| episode_num=req.episode_num, |
| verbose=False, |
| ) |
|
|
| metrics = _load_metrics() |
| metrics.append(result) |
| _save_metrics(metrics) |
|
|
| return result |
|
|
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
| @app.post("/run-comparison") |
| def run_comparison(req: ComparisonRequest): |
| """Run baseline vs memory comparison.""" |
| try: |
| from agent.combined_agent import CombinedAgent |
|
|
| agent = CombinedAgent( |
| use_memory=True, |
| memory_dir=str(DATA_DIR / "chroma_data"), |
| ) |
| results = agent.run_comparison( |
| task_type=req.task_type, |
| num_episodes=req.num_episodes, |
| verbose=False, |
| ) |
|
|
| return results |
|
|
| except Exception as e: |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
| @app.get("/metrics") |
| def get_metrics(): |
| """Get all logged training/episode metrics.""" |
| return _load_metrics() |
|
|
|
|
| @app.get("/memory/stats") |
| def memory_stats(): |
| """Get memory store statistics.""" |
| return memory_store.get_stats() |
|
|
|
|
| @app.post("/memory/search") |
| def memory_search(req: MemorySearchRequest): |
| """Search memory for relevant lessons.""" |
| lessons = memory_store.retrieve_lessons(req.query, n_results=req.n_results) |
| formatted = memory_store.format_lessons_for_prompt(req.query, n_results=req.n_results) |
| return { |
| "lessons": lessons, |
| "formatted_prompt": formatted, |
| } |
|
|
|
|
| @app.get("/memory/all") |
| def memory_all(): |
| """Get all stored experiences.""" |
| return memory_store.get_all_experiences(limit=200) |
|
|
|
|
| @app.post("/memory/clear") |
| def memory_clear(): |
| """Clear all memory.""" |
| memory_store.clear() |
| return {"status": "cleared", "count": 0} |
|
|
|
|
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run(app, host="0.0.0.0", port=8000) |
|
|