# Complete API Integration Guide - Codex ADK **Status:** ✅ **PRODUCTION-READY** (All MVP Endpoints Implemented) **Last Updated:** 2025-10-26 **Backend Version:** v1.0.0-mvp --- ## Overview This guide covers the complete integration of all 13 backend API endpoints: - **6 Commands** (write operations) - **4 Queries** (read operations - CQRS pattern) - **3 List Endpoints** (GET - simple reads, not yet implemented in frontend) --- ## Quick Reference ```dart import 'package:console/api/api.dart'; final CqrsApiClient client = CqrsApiClient( config: ApiClientConfig.development, // http://localhost:5246 ); // Always dispose when done client.dispose(); ``` --- ## 1. Agent Management ### Create Agent ```dart final Result result = await client.createAgent( CreateAgentCommand( name: 'Code Generator', description: 'AI code generation assistant', type: AgentType.codeGenerator, modelProvider: 'ollama', modelName: 'phi', providerType: ModelProviderType.localEndpoint, modelEndpoint: 'http://localhost:11434', systemPrompt: 'You are a code generation expert', temperature: 0.7, maxTokens: 4000, enableMemory: true, conversationWindowSize: 10, ), ); ``` ### Get Agent ```dart final Result result = await client.getAgent('agent-uuid'); result.when( success: (AgentDto agent) { print('Name: ${agent.name}'); print('Status: ${agent.status.value}'); print('Model: ${agent.modelProvider}/${agent.modelName}'); }, error: (ApiErrorInfo error) => print('Error: ${error.message}'), ); ``` ### Update Agent ```dart await client.updateAgent( UpdateAgentCommand( id: 'agent-uuid', name: 'Updated Name', temperature: 0.8, status: AgentStatus.active, ), ); ``` ### Delete Agent ```dart await client.deleteAgent( DeleteAgentCommand(id: 'agent-uuid'), ); ``` **See:** `docs/AGENT_API_INTEGRATION.md` for complete Agent documentation. --- ## 2. Conversation Management ### Create Conversation ```dart final Result result = await client.createConversation( CreateConversationCommand( title: 'Code Review Session', summary: 'Reviewing authentication module', ), ); result.when( success: (CreateConversationResult created) { print('Conversation ID: ${created.id}'); }, error: (ApiErrorInfo error) => print('Error: ${error.message}'), ); ``` ### Get Conversation ```dart final Result result = await client.getConversation('conversation-uuid'); result.when( success: (ConversationDto conversation) { print('Title: ${conversation.title}'); print('Messages: ${conversation.messageCount}'); print('Started: ${conversation.startedAt}'); print('Last message: ${conversation.lastMessageAt}'); for (final ConversationMessageDto message in conversation.messages) { print('${message.role}: ${message.content}'); } }, error: (ApiErrorInfo error) => print('Error: ${error.message}'), ); ``` --- ## 3. Agent Execution ### Start Agent Execution ```dart final Result result = await client.startAgentExecution( StartAgentExecutionCommand( agentId: 'agent-uuid', conversationId: 'conversation-uuid', // Optional userPrompt: 'Generate a function to calculate factorial in Dart', ), ); result.when( success: (StartExecutionResult started) { print('Execution started: ${started.id}'); }, error: (ApiErrorInfo error) => print('Error: ${error.message}'), ); ``` ### Complete Agent Execution ```dart await client.completeAgentExecution( CompleteAgentExecutionCommand( executionId: 'execution-uuid', status: ExecutionStatus.completed, response: 'Here is the factorial function: ...', inputTokens: 150, outputTokens: 300, estimatedCost: 0.0045, ), ); ``` ### Get Agent Execution ```dart final Result result = await client.getAgentExecution('execution-uuid'); result.when( success: (AgentExecutionDto execution) { print('Status: ${execution.status.value}'); print('Prompt: ${execution.userPrompt}'); print('Response: ${execution.response}'); print('Tokens: ${execution.inputTokens} in, ${execution.outputTokens} out'); print('Cost: \$${execution.estimatedCost}'); print('Duration: ${execution.completedAt?.difference(execution.startedAt)}'); }, error: (ApiErrorInfo error) => print('Error: ${error.message}'), ); ``` --- ## 4. Health Check ```dart final Result result = await client.checkHealth(); result.when( success: (bool isHealthy) => print('API healthy: $isHealthy'), error: (ApiErrorInfo error) => print('API unavailable: ${error.message}'), ); ``` --- ## Complete Workflow Example ```dart Future completeAgentWorkflow() async { final CqrsApiClient client = CqrsApiClient( config: ApiClientConfig.development, ); try { // 1. Create an agent print('1. Creating agent...'); await client.createAgent( CreateAgentCommand( name: 'Code Generator', description: 'AI code generation assistant', type: AgentType.codeGenerator, modelProvider: 'ollama', modelName: 'phi', providerType: ModelProviderType.localEndpoint, modelEndpoint: 'http://localhost:11434', systemPrompt: 'You are a helpful code generation assistant', temperature: 0.7, maxTokens: 4000, ), ); // Note: In real app, you'd get the agent ID from a list or create response final String agentId = 'your-agent-uuid'; // 2. Create a conversation print('2. Creating conversation...'); final Result convResult = await client.createConversation( CreateConversationCommand( title: 'Factorial Function Development', ), ); String? conversationId; convResult.when( success: (CreateConversationResult created) { conversationId = created.id; print(' Conversation ID: $conversationId'); }, error: (ApiErrorInfo error) => print(' Failed: ${error.message}'), ); // 3. Start agent execution print('3. Starting agent execution...'); final Result execResult = await client.startAgentExecution( StartAgentExecutionCommand( agentId: agentId, conversationId: conversationId, userPrompt: 'Generate a Dart function to calculate factorial recursively', ), ); String? executionId; execResult.when( success: (StartExecutionResult started) { executionId = started.id; print(' Execution ID: $executionId'); }, error: (ApiErrorInfo error) => print(' Failed: ${error.message}'), ); // 4. Simulate agent processing (in real app, agent would process this) await Future.delayed(Duration(seconds: 2)); // 5. Complete the execution if (executionId != null) { print('4. Completing execution...'); await client.completeAgentExecution( CompleteAgentExecutionCommand( executionId: executionId!, status: ExecutionStatus.completed, response: ''' int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); } ''', inputTokens: 50, outputTokens: 100, estimatedCost: 0.0015, ), ); } // 6. Get execution details if (executionId != null) { print('5. Fetching execution details...'); final Result detailsResult = await client.getAgentExecution(executionId!); detailsResult.when( success: (AgentExecutionDto execution) { print(' Status: ${execution.status.value}'); print(' Response: ${execution.response}'); print(' Tokens: ${execution.inputTokens} → ${execution.outputTokens}'); }, error: (ApiErrorInfo error) => print(' Failed: ${error.message}'), ); } // 7. Get conversation with all messages if (conversationId != null) { print('6. Fetching conversation...'); final Result convDetailsResult = await client.getConversation(conversationId!); convDetailsResult.when( success: (ConversationDto conv) { print(' Title: ${conv.title}'); print(' Messages: ${conv.messageCount}'); print(' Executions: ${conv.executionCount}'); }, error: (ApiErrorInfo error) => print(' Failed: ${error.message}'), ); } print('\n✓ Workflow complete!'); } finally { client.dispose(); } } ``` --- ## Enums Reference ### AgentType ```dart AgentType.codeGenerator // 'CodeGenerator' AgentType.codeReviewer // 'CodeReviewer' AgentType.debugger // 'Debugger' AgentType.documenter // 'Documenter' AgentType.custom // 'Custom' ``` ### AgentStatus ```dart AgentStatus.active // 'Active' AgentStatus.inactive // 'Inactive' AgentStatus.error // 'Error' ``` ### ModelProviderType ```dart ModelProviderType.cloudApi // 'CloudApi' - OpenAI, Anthropic ModelProviderType.localEndpoint // 'LocalEndpoint' - Ollama ModelProviderType.custom // 'Custom' ``` ### ExecutionStatus ```dart ExecutionStatus.pending // 'Pending' ExecutionStatus.running // 'Running' ExecutionStatus.completed // 'Completed' ExecutionStatus.failed // 'Failed' ExecutionStatus.cancelled // 'Cancelled' ``` --- ## Error Handling Patterns ### Pattern 1: when() Method ```dart result.when( success: (data) { // Handle success }, error: (ApiErrorInfo error) { switch (error.type) { case ApiErrorType.network: showSnackbar('No internet connection'); case ApiErrorType.timeout: showSnackbar('Request timed out - try again'); case ApiErrorType.http: if (error.statusCode == 404) { showSnackbar('Resource not found'); } else if (error.statusCode == 400) { showSnackbar('Invalid request: ${error.details}'); } case ApiErrorType.validation: showValidationErrors(error.details); case ApiErrorType.serialization: logger.error('JSON parsing error: ${error.details}'); case ApiErrorType.unknown: showSnackbar('Unexpected error occurred'); } }, ); ``` ### Pattern 2: Switch Expression ```dart final String message = switch (result) { ApiSuccess(value: final data) => 'Success: $data', ApiError(error: final err) when err.statusCode == 404 => 'Not found', ApiError(error: final err) when err.type == ApiErrorType.network => 'Network error', ApiError(error: final err) => 'Error: ${err.message}', }; ``` --- ## Configuration ### Development ```dart final CqrsApiClient client = CqrsApiClient( config: ApiClientConfig.development, // http://localhost:5246 ); ``` ### Android Emulator ```dart final CqrsApiClient client = CqrsApiClient( config: ApiClientConfig( baseUrl: 'http://10.0.2.2:5246', timeout: Duration(seconds: 30), ), ); ``` ### Production (with JWT) ```dart final CqrsApiClient client = CqrsApiClient( config: ApiClientConfig( baseUrl: 'https://api.svrnty.com', timeout: Duration(seconds: 30), defaultHeaders: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $jwtToken', }, ), ); ``` --- ## Implementation Status ### ✅ Implemented (Phase 1 & 2) - [x] Agent CRUD (create, get, update, delete) - [x] Conversation creation and retrieval - [x] Execution start, complete, and retrieval - [x] Health check - [x] All DTOs with strict typing - [x] All enums - [x] Functional error handling with Result ### ⏳ Not Yet Implemented (Phase 3) - [ ] List agents (GET /api/agents) - [ ] List conversations (GET /api/conversations) - [ ] List executions (GET /api/executions) - [ ] Filter executions by status (GET /api/executions/status/{status}) - [ ] Agent-specific lists (GET /api/agents/{id}/conversations) **Note:** Phase 3 endpoints use simple GET requests and return arrays. They can be added later based on UI requirements. --- ## Files Reference ### Implementation - `lib/api/client.dart` - CQRS client core - `lib/api/types.dart` - Result and error types - `lib/api/endpoints/agent_endpoint.dart` - Agent CRUD - `lib/api/endpoints/conversation_endpoint.dart` - Conversation ops - `lib/api/endpoints/execution_endpoint.dart` - Execution ops - `lib/api/endpoints/health_endpoint.dart` - Health check - `lib/api/api.dart` - Main export file ### Documentation - `docs/AGENT_API_INTEGRATION.md` - Agent-specific guide - `docs/COMPLETE_API_INTEGRATION.md` - This file - `README_API.md` - CQRS architecture overview - `CLAUDE.md` - Project conventions and rules ### Backend Contract - `api-schema.json` - OpenAPI spec (source of truth) - `../BACKEND/docs/openapi.json` - Backend source - `../BACKEND/docs/COMPLETE-API-REFERENCE.md` - Backend API docs - `../BACKEND/docs/CHANGELOG.md` - Breaking changes log --- ## Testing ### Run Analysis ```bash flutter analyze ``` ### Run Tests ```bash flutter test ``` ### Test Backend Connection ```bash # Start backend first cd ../BACKEND dotnet run # Then test from Flutter app flutter run ``` --- ## Important Notes ### CQRS Pattern - All commands/queries use **POST** with JSON body - Commands return `Result` (except create operations that return IDs) - Queries return `Result` with typed data - Always send JSON body, even empty `{}` ### Strict Typing - No `dynamic` types allowed - All variables have explicit type annotations - All functions have typed parameters and return values - See `CLAUDE.md` for complete typing rules ### Functional Error Handling - Use `Result` pattern matching - Never use try-catch for API calls - Use `when()` or switch expressions ### Backend Monitoring ```bash # Always check backend changes before updating cat ../BACKEND/docs/CHANGELOG.md # Update API schema when backend changes cp ../BACKEND/docs/openapi.json ./api-schema.json ``` --- ## Next Steps 1. **Phase 3:** Implement list endpoints (GET operations) 2. **Authentication:** Add JWT token management (v2) 3. **Real-time:** WebSocket/SignalR for execution updates (v2) 4. **UI Components:** Build agent/conversation management screens 5. **State Management:** Integrate with Provider/Riverpod/Bloc --- **Status:** ✅ **All Core Endpoints Implemented and Production-Ready** **Last Updated:** 2025-10-26 **Backend Version:** v1.0.0-mvp