feat: Integrate backend list agents endpoint
Backend team successfully fixed Swagger conflicts and implemented simple GET endpoints. Frontend now integrates with GET /api/agents to list all agents. Changes: - agent_endpoint.dart: - Added fromInt() methods to all enums (AgentType, AgentStatus, ModelProviderType) - Updated AgentDto.fromJson() to handle integer enum values from backend - Added listAgents() method using HTTP GET /api/agents - Added imports: dart:async, dart:convert, dart:io, package:http - agents_page.dart: - Updated _loadAgents() to call listAgents() API method - Removed placeholder delay, now uses real data from backend - Removed unused getwidget import Backend Integration: ✅ Backend returns 5 test agents (seeded successfully) ✅ Enums transmitted as integers (CodeGenerator=0, Active=0, etc.) ✅ Frontend properly parses integer enums to Dart enum types ✅ GET /api/agents endpoint working and tested ✅ Full CRUD cycle now functional Testing: - Flutter analyze: 0 errors, 0 warnings - Backend health check: ✅ passing - List endpoint: ✅ returns 5 agents - App running: http://localhost:8080 Phase 2 Complete: Frontend can now display agents from backend! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f5a5c5697c
commit
30575c6f77
@ -1,6 +1,12 @@
|
||||
/// Agent management endpoints for CQRS API
|
||||
library;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../client.dart';
|
||||
import '../types.dart';
|
||||
|
||||
@ -25,6 +31,15 @@ enum AgentType {
|
||||
orElse: () => AgentType.custom,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert from integer value (backend enum representation)
|
||||
/// Backend: CodeGenerator=0, CodeReviewer=1, Debugger=2, Documenter=3, Custom=4
|
||||
static AgentType fromInt(int value) {
|
||||
if (value >= 0 && value < AgentType.values.length) {
|
||||
return AgentType.values[value];
|
||||
}
|
||||
return AgentType.custom;
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the current status of an agent
|
||||
@ -42,6 +57,15 @@ enum AgentStatus {
|
||||
orElse: () => AgentStatus.inactive,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert from integer value (backend enum representation)
|
||||
/// Backend: Active=0, Inactive=1, Error=2
|
||||
static AgentStatus fromInt(int value) {
|
||||
if (value >= 0 && value < AgentStatus.values.length) {
|
||||
return AgentStatus.values[value];
|
||||
}
|
||||
return AgentStatus.inactive;
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies the type of model provider (cloud API or local endpoint)
|
||||
@ -59,6 +83,15 @@ enum ModelProviderType {
|
||||
orElse: () => ModelProviderType.custom,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert from integer value (backend enum representation)
|
||||
/// Backend: CloudApi=0, LocalEndpoint=1, Custom=2
|
||||
static ModelProviderType fromInt(int value) {
|
||||
if (value >= 0 && value < ModelProviderType.values.length) {
|
||||
return ModelProviderType.values[value];
|
||||
}
|
||||
return ModelProviderType.custom;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -239,21 +272,40 @@ class AgentDto {
|
||||
});
|
||||
|
||||
factory AgentDto.fromJson(Map<String, Object?> json) {
|
||||
// Helper to parse enum from either int or string
|
||||
AgentType parseAgentType(Object? value) {
|
||||
if (value is int) return AgentType.fromInt(value);
|
||||
if (value is String) return AgentType.fromString(value);
|
||||
return AgentType.custom;
|
||||
}
|
||||
|
||||
AgentStatus parseAgentStatus(Object? value) {
|
||||
if (value is int) return AgentStatus.fromInt(value);
|
||||
if (value is String) return AgentStatus.fromString(value);
|
||||
return AgentStatus.inactive;
|
||||
}
|
||||
|
||||
ModelProviderType parseProviderType(Object? value) {
|
||||
if (value is int) return ModelProviderType.fromInt(value);
|
||||
if (value is String) return ModelProviderType.fromString(value);
|
||||
return ModelProviderType.custom;
|
||||
}
|
||||
|
||||
return AgentDto(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String,
|
||||
type: AgentType.fromString(json['type'] as String),
|
||||
type: parseAgentType(json['type']),
|
||||
modelProvider: json['modelProvider'] as String,
|
||||
modelName: json['modelName'] as String,
|
||||
providerType: ModelProviderType.fromString(json['providerType'] as String),
|
||||
providerType: parseProviderType(json['providerType']),
|
||||
modelEndpoint: json['modelEndpoint'] as String?,
|
||||
temperature: (json['temperature'] as num).toDouble(),
|
||||
maxTokens: json['maxTokens'] as int,
|
||||
systemPrompt: json['systemPrompt'] as String,
|
||||
enableMemory: json['enableMemory'] as bool,
|
||||
conversationWindowSize: json['conversationWindowSize'] as int,
|
||||
status: AgentStatus.fromString(json['status'] as String),
|
||||
status: parseAgentStatus(json['status']),
|
||||
createdAt: DateTime.parse(json['createdAt'] as String),
|
||||
updatedAt: DateTime.parse(json['updatedAt'] as String),
|
||||
);
|
||||
@ -361,4 +413,65 @@ extension AgentEndpoint on CqrsApiClient {
|
||||
fromJson: (json) => AgentDto.fromJson(json as Map<String, Object?>),
|
||||
);
|
||||
}
|
||||
|
||||
/// List all agents
|
||||
///
|
||||
/// Returns a list of all active agents from the backend.
|
||||
/// Backend endpoint: GET /api/agents
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// final result = await client.listAgents();
|
||||
///
|
||||
/// result.when(
|
||||
/// success: (agents) => print('Found ${agents.length} agents'),
|
||||
/// error: (error) => print('Error: ${error.message}'),
|
||||
/// );
|
||||
/// ```
|
||||
Future<Result<List<AgentDto>>> listAgents() async {
|
||||
try {
|
||||
final Uri url = Uri.parse('${config.baseUrl}/api/agents');
|
||||
final http.Response response = await http
|
||||
.get(url, headers: config.defaultHeaders)
|
||||
.timeout(config.timeout);
|
||||
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
final Object? jsonData = jsonDecode(response.body);
|
||||
if (jsonData is! List) {
|
||||
return ApiError<List<AgentDto>>(ApiErrorInfo(
|
||||
message: 'Expected array response, got ${jsonData.runtimeType}',
|
||||
type: ApiErrorType.serialization,
|
||||
));
|
||||
}
|
||||
|
||||
final List<AgentDto> agents = jsonData
|
||||
.map((item) => AgentDto.fromJson(item as Map<String, Object?>))
|
||||
.toList();
|
||||
|
||||
return ApiSuccess<List<AgentDto>>(agents);
|
||||
}
|
||||
|
||||
// Handle error responses
|
||||
return ApiError<List<AgentDto>>(ApiErrorInfo(
|
||||
message: 'Failed to load agents',
|
||||
type: ApiErrorType.http,
|
||||
statusCode: response.statusCode,
|
||||
));
|
||||
} on TimeoutException {
|
||||
return ApiError<List<AgentDto>>(ApiErrorInfo(
|
||||
message: 'Request timed out',
|
||||
type: ApiErrorType.timeout,
|
||||
));
|
||||
} on SocketException {
|
||||
return ApiError<List<AgentDto>>(ApiErrorInfo(
|
||||
message: 'No internet connection',
|
||||
type: ApiErrorType.network,
|
||||
));
|
||||
} catch (e) {
|
||||
return ApiError<List<AgentDto>>(ApiErrorInfo(
|
||||
message: 'Unexpected error: $e',
|
||||
type: ApiErrorType.unknown,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iconsax/iconsax.dart';
|
||||
import 'package:animate_do/animate_do.dart';
|
||||
import 'package:getwidget/getwidget.dart';
|
||||
import '../api/api.dart';
|
||||
import '../dialogs/create_agent_dialog.dart';
|
||||
|
||||
@ -43,14 +42,26 @@ class _AgentsPageState extends State<AgentsPage> {
|
||||
_errorMessage = null;
|
||||
});
|
||||
|
||||
// TODO: Implement list agents endpoint when available
|
||||
// For now, show empty state
|
||||
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||
final Result<List<AgentDto>> result = await _apiClient.listAgents();
|
||||
|
||||
setState(() {
|
||||
_agents = [];
|
||||
_isLoading = false;
|
||||
});
|
||||
result.when(
|
||||
success: (List<AgentDto> agents) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_agents = agents;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (ApiErrorInfo error) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_errorMessage = error.message;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _createAgent(CreateAgentCommand command) async {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user