| from fastapi import APIRouter, Depends, HTTPException |
| from typing import Dict, Any |
| from pydantic import BaseModel |
|
|
| from ..core.neo4j_store import Neo4jStore |
| from ..core.llm_factory import UnifiedLLMProvider |
|
|
| router = APIRouter(prefix="/api/v1/simulation", tags=["Simulation Interaction"]) |
|
|
| def get_global_store(): |
| |
| from .server import graph_store |
| if graph_store is None: |
| raise HTTPException(status_code=500, detail="Neo4j connection not initialized.") |
| return graph_store |
|
|
| def get_global_llm(): |
| return UnifiedLLMProvider() |
|
|
| class InterviewRequest(BaseModel): |
| agent_id: str |
| user_query: str |
|
|
|
|
| @router.post("/interview", response_model=Dict[str, Any]) |
| async def live_interview_agent( |
| request: InterviewRequest, |
| store: Neo4jStore = Depends(get_global_store), |
| llm: UnifiedLLMProvider = Depends(get_global_llm) |
| ): |
| """ |
| MiroFish Point 5: 'Live Interviews' with Simulated Personas. |
| Allows users to chat with a graph entity in character, |
| injecting their exact Neo4j memory into the system prompt. |
| """ |
| |
| query_agent = """ |
| MATCH (a:Entity {id: $agent_id}) |
| RETURN a.name as name, a.persona as persona |
| """ |
| results = await store.execute_query(query_agent, {"agent_id": request.agent_id}) |
| if not results: |
| raise HTTPException(status_code=404, detail="Agent persona not found.") |
| |
| agent = results[0] |
| |
| |
| query_memory = """ |
| MATCH (a:Entity {id: $agent_id})-[r]->(t:Entity) |
| WITH t.name as target, type(r) as relation, coalesce(r.content, r.properties) as details, r.valid_from as timestamp |
| ORDER BY timestamp DESC |
| LIMIT 5 |
| RETURN relation, target, details |
| """ |
| memories = await store.execute_query(query_memory, {"agent_id": request.agent_id}) |
| |
| memory_string = "Your recent memories/actions in the simulation sandbox:\n" |
| for m in memories: |
| memory_string += f"- You {m['relation']} ({m['target']}): {m['details']}\n" |
|
|
| |
| system_prompt = ( |
| f"You are engaging in a live roleplay interview.\n" |
| f"Your Name: {agent['name']}\n" |
| f"Your Psychological Profile & Background:\n{agent['persona']}\n\n" |
| f"{memory_string if memories else 'You have no recent memories recorded.'}\n\n" |
| f"Answer the user's question completely in character based ONLY on your profile and memories." |
| ) |
| |
| |
| try: |
| response_text = await llm.complete( |
| prompt=request.user_query, |
| system_prompt=system_prompt, |
| temperature=0.8 |
| ) |
| return { |
| "agent_id": request.agent_id, |
| "agent_name": agent['name'], |
| "response": response_text |
| } |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=f"LLM Interaction Failed: {str(e)}") |
|
|
|
|
| from ..retrieval.report_agent import ReportAgent |
|
|
| @router.get('/report', response_model=Dict[str, Any]) |
| async def get_sandbox_report( |
| store: Neo4jStore = Depends(get_global_store), |
| llm: UnifiedLLMProvider = Depends(get_global_llm) |
| ): |
| ''' |
| MiroFish Point 3: Dedicated ReAct Reporting Agent & Tooling. |
| Triggers the analytical engine to build a report off the recent sandbox events. |
| ''' |
| try: |
| agent = ReportAgent(store, llm) |
| report = await agent.generate_sandbox_report() |
| return report.model_dump() |
| except Exception as e: |
| raise HTTPException(status_code=500, detail=f'Report generation failed: {str(e)}') |
|
|
|
|
| from ..workers.celery_worker import celery_app |
|
|
| @router.post('/generate_personas') |
| async def start_persona_generation(): |
| '''Trigger background Celery task to generate personas.''' |
| task = celery_app.send_task('generate_personas') |
| return {'status': 'accepted', 'task_id': task.id} |
|
|
| @router.post('/tick') |
| async def start_simulation_tick(): |
| '''Trigger background Celery task to run a simulation loop tick.''' |
| task = celery_app.send_task('run_simulation_tick') |
| return {'status': 'accepted', 'task_id': task.id} |
|
|
|
|