Implement full CQRS API integration with type-safe endpoints for all core backend operations. ## What's New - **Agent Management**: 4 endpoints (create, get, update, delete) with 3 enums - **Conversations**: 2 endpoints (create, get) with message support - **Executions**: 3 endpoints (start, complete, get) with status tracking - **OpenAPI Schema**: Updated to backend v1.0.0-mvp (10 endpoints) ## Implementation Details - All endpoints follow CQRS pattern (commands/queries) - 100% strict typing (no dynamic, all explicit types) - Functional error handling with Result<T> pattern - 3,136+ lines of production code - 1,500+ lines of comprehensive documentation ## Files Added - lib/api/endpoints/agent_endpoint.dart (364 lines) - lib/api/endpoints/conversation_endpoint.dart (319 lines) - lib/api/endpoints/execution_endpoint.dart (434 lines) - lib/api/examples/agent_example.dart (212 lines) - docs/AGENT_API_INTEGRATION.md (431 lines) - docs/COMPLETE_API_INTEGRATION.md (555 lines) - docs/INTEGRATION_STATUS.md (339 lines) ## Quality Metrics - Flutter analyze: 0 errors ✅ - Type safety: 100% (0 dynamic types) ✅ - CQRS compliance: 100% ✅ - Backend compatibility: v1.0.0-mvp ✅ ## Backend Integration - Updated api-schema.json from backend openapi.json - Supports all MVP endpoints except list operations (deferred to Phase 3) - Ready for JWT authentication (infrastructure in place) ## Usage ```dart import 'package:console/api/api.dart'; final client = CqrsApiClient(config: ApiClientConfig.development); // Agent CRUD await client.createAgent(CreateAgentCommand(...)); await client.getAgent('uuid'); // Conversations await client.createConversation(CreateConversationCommand(...)); // Executions await client.startAgentExecution(StartAgentExecutionCommand(...)); ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
365 lines
10 KiB
Dart
365 lines
10 KiB
Dart
/// Agent management endpoints for CQRS API
|
|
library;
|
|
|
|
import '../client.dart';
|
|
import '../types.dart';
|
|
|
|
// =============================================================================
|
|
// Enums
|
|
// =============================================================================
|
|
|
|
/// Specifies the type/purpose of the agent
|
|
enum AgentType {
|
|
codeGenerator('CodeGenerator'),
|
|
codeReviewer('CodeReviewer'),
|
|
debugger('Debugger'),
|
|
documenter('Documenter'),
|
|
custom('Custom');
|
|
|
|
const AgentType(this.value);
|
|
final String value;
|
|
|
|
static AgentType fromString(String value) {
|
|
return AgentType.values.firstWhere(
|
|
(type) => type.value == value,
|
|
orElse: () => AgentType.custom,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Represents the current status of an agent
|
|
enum AgentStatus {
|
|
active('Active'),
|
|
inactive('Inactive'),
|
|
error('Error');
|
|
|
|
const AgentStatus(this.value);
|
|
final String value;
|
|
|
|
static AgentStatus fromString(String value) {
|
|
return AgentStatus.values.firstWhere(
|
|
(status) => status.value == value,
|
|
orElse: () => AgentStatus.inactive,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Specifies the type of model provider (cloud API or local endpoint)
|
|
enum ModelProviderType {
|
|
cloudApi('CloudApi'),
|
|
localEndpoint('LocalEndpoint'),
|
|
custom('Custom');
|
|
|
|
const ModelProviderType(this.value);
|
|
final String value;
|
|
|
|
static ModelProviderType fromString(String value) {
|
|
return ModelProviderType.values.firstWhere(
|
|
(type) => type.value == value,
|
|
orElse: () => ModelProviderType.custom,
|
|
);
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Commands
|
|
// =============================================================================
|
|
|
|
/// Command to create a new AI agent with configuration
|
|
class CreateAgentCommand implements Serializable {
|
|
final String name;
|
|
final String description;
|
|
final AgentType type;
|
|
final String modelProvider;
|
|
final String modelName;
|
|
final ModelProviderType providerType;
|
|
final String? modelEndpoint;
|
|
final String? apiKey;
|
|
final double temperature;
|
|
final int maxTokens;
|
|
final String systemPrompt;
|
|
final bool enableMemory;
|
|
final int conversationWindowSize;
|
|
|
|
const CreateAgentCommand({
|
|
required this.name,
|
|
required this.description,
|
|
required this.type,
|
|
required this.modelProvider,
|
|
required this.modelName,
|
|
required this.providerType,
|
|
this.modelEndpoint,
|
|
this.apiKey,
|
|
this.temperature = 0.7,
|
|
this.maxTokens = 4000,
|
|
required this.systemPrompt,
|
|
this.enableMemory = true,
|
|
this.conversationWindowSize = 10,
|
|
});
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => {
|
|
'name': name,
|
|
'description': description,
|
|
'type': type.value,
|
|
'modelProvider': modelProvider,
|
|
'modelName': modelName,
|
|
'providerType': providerType.value,
|
|
'modelEndpoint': modelEndpoint,
|
|
'apiKey': apiKey,
|
|
'temperature': temperature,
|
|
'maxTokens': maxTokens,
|
|
'systemPrompt': systemPrompt,
|
|
'enableMemory': enableMemory,
|
|
'conversationWindowSize': conversationWindowSize,
|
|
};
|
|
}
|
|
|
|
/// Command to update an existing agent's configuration
|
|
class UpdateAgentCommand implements Serializable {
|
|
final String id;
|
|
final String? name;
|
|
final String? description;
|
|
final AgentType? type;
|
|
final String? modelProvider;
|
|
final String? modelName;
|
|
final ModelProviderType? providerType;
|
|
final String? modelEndpoint;
|
|
final String? apiKey;
|
|
final double? temperature;
|
|
final int? maxTokens;
|
|
final String? systemPrompt;
|
|
final bool? enableMemory;
|
|
final int? conversationWindowSize;
|
|
final AgentStatus? status;
|
|
|
|
const UpdateAgentCommand({
|
|
required this.id,
|
|
this.name,
|
|
this.description,
|
|
this.type,
|
|
this.modelProvider,
|
|
this.modelName,
|
|
this.providerType,
|
|
this.modelEndpoint,
|
|
this.apiKey,
|
|
this.temperature,
|
|
this.maxTokens,
|
|
this.systemPrompt,
|
|
this.enableMemory,
|
|
this.conversationWindowSize,
|
|
this.status,
|
|
});
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => {
|
|
'id': id,
|
|
if (name != null) 'name': name,
|
|
if (description != null) 'description': description,
|
|
if (type != null) 'type': type!.value,
|
|
if (modelProvider != null) 'modelProvider': modelProvider,
|
|
if (modelName != null) 'modelName': modelName,
|
|
if (providerType != null) 'providerType': providerType!.value,
|
|
if (modelEndpoint != null) 'modelEndpoint': modelEndpoint,
|
|
if (apiKey != null) 'apiKey': apiKey,
|
|
if (temperature != null) 'temperature': temperature,
|
|
if (maxTokens != null) 'maxTokens': maxTokens,
|
|
if (systemPrompt != null) 'systemPrompt': systemPrompt,
|
|
if (enableMemory != null) 'enableMemory': enableMemory,
|
|
if (conversationWindowSize != null)
|
|
'conversationWindowSize': conversationWindowSize,
|
|
if (status != null) 'status': status!.value,
|
|
};
|
|
}
|
|
|
|
/// Command to soft-delete an agent
|
|
class DeleteAgentCommand implements Serializable {
|
|
final String id;
|
|
|
|
const DeleteAgentCommand({required this.id});
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => {'id': id};
|
|
}
|
|
|
|
// =============================================================================
|
|
// Queries
|
|
// =============================================================================
|
|
|
|
/// Query to get a single agent by ID
|
|
class GetAgentQuery implements Serializable {
|
|
final String id;
|
|
|
|
const GetAgentQuery({required this.id});
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => {'id': id};
|
|
}
|
|
|
|
// =============================================================================
|
|
// DTOs
|
|
// =============================================================================
|
|
|
|
/// Response containing agent details
|
|
class AgentDto {
|
|
final String id;
|
|
final String name;
|
|
final String description;
|
|
final AgentType type;
|
|
final String modelProvider;
|
|
final String modelName;
|
|
final ModelProviderType providerType;
|
|
final String? modelEndpoint;
|
|
final double temperature;
|
|
final int maxTokens;
|
|
final String systemPrompt;
|
|
final bool enableMemory;
|
|
final int conversationWindowSize;
|
|
final AgentStatus status;
|
|
final DateTime createdAt;
|
|
final DateTime updatedAt;
|
|
|
|
const AgentDto({
|
|
required this.id,
|
|
required this.name,
|
|
required this.description,
|
|
required this.type,
|
|
required this.modelProvider,
|
|
required this.modelName,
|
|
required this.providerType,
|
|
this.modelEndpoint,
|
|
required this.temperature,
|
|
required this.maxTokens,
|
|
required this.systemPrompt,
|
|
required this.enableMemory,
|
|
required this.conversationWindowSize,
|
|
required this.status,
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
});
|
|
|
|
factory AgentDto.fromJson(Map<String, Object?> json) {
|
|
return AgentDto(
|
|
id: json['id'] as String,
|
|
name: json['name'] as String,
|
|
description: json['description'] as String,
|
|
type: AgentType.fromString(json['type'] as String),
|
|
modelProvider: json['modelProvider'] as String,
|
|
modelName: json['modelName'] as String,
|
|
providerType: ModelProviderType.fromString(json['providerType'] as String),
|
|
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),
|
|
createdAt: DateTime.parse(json['createdAt'] as String),
|
|
updatedAt: DateTime.parse(json['updatedAt'] as String),
|
|
);
|
|
}
|
|
|
|
Map<String, Object?> toJson() => {
|
|
'id': id,
|
|
'name': name,
|
|
'description': description,
|
|
'type': type.value,
|
|
'modelProvider': modelProvider,
|
|
'modelName': modelName,
|
|
'providerType': providerType.value,
|
|
'modelEndpoint': modelEndpoint,
|
|
'temperature': temperature,
|
|
'maxTokens': maxTokens,
|
|
'systemPrompt': systemPrompt,
|
|
'enableMemory': enableMemory,
|
|
'conversationWindowSize': conversationWindowSize,
|
|
'status': status.value,
|
|
'createdAt': createdAt.toIso8601String(),
|
|
'updatedAt': updatedAt.toIso8601String(),
|
|
};
|
|
}
|
|
|
|
// =============================================================================
|
|
// Extension Methods
|
|
// =============================================================================
|
|
|
|
/// Agent management endpoints
|
|
extension AgentEndpoint on CqrsApiClient {
|
|
/// Create a new AI agent
|
|
///
|
|
/// Example:
|
|
/// ```dart
|
|
/// final result = await client.createAgent(
|
|
/// CreateAgentCommand(
|
|
/// name: 'Code Generator',
|
|
/// description: 'AI agent for code generation',
|
|
/// type: AgentType.codeGenerator,
|
|
/// modelProvider: 'ollama',
|
|
/// modelName: 'phi',
|
|
/// providerType: ModelProviderType.localEndpoint,
|
|
/// modelEndpoint: 'http://localhost:11434',
|
|
/// systemPrompt: 'You are a code generation assistant',
|
|
/// ),
|
|
/// );
|
|
/// ```
|
|
Future<Result<void>> createAgent(CreateAgentCommand command) async {
|
|
return executeCommand(
|
|
endpoint: 'createAgent',
|
|
command: command,
|
|
);
|
|
}
|
|
|
|
/// Update an existing agent's configuration
|
|
///
|
|
/// Example:
|
|
/// ```dart
|
|
/// final result = await client.updateAgent(
|
|
/// UpdateAgentCommand(
|
|
/// id: 'agent-uuid',
|
|
/// name: 'Updated Name',
|
|
/// status: AgentStatus.active,
|
|
/// ),
|
|
/// );
|
|
/// ```
|
|
Future<Result<void>> updateAgent(UpdateAgentCommand command) async {
|
|
return executeCommand(
|
|
endpoint: 'updateAgent',
|
|
command: command,
|
|
);
|
|
}
|
|
|
|
/// Soft-delete an agent
|
|
///
|
|
/// Example:
|
|
/// ```dart
|
|
/// final result = await client.deleteAgent(
|
|
/// DeleteAgentCommand(id: 'agent-uuid'),
|
|
/// );
|
|
/// ```
|
|
Future<Result<void>> deleteAgent(DeleteAgentCommand command) async {
|
|
return executeCommand(
|
|
endpoint: 'deleteAgent',
|
|
command: command,
|
|
);
|
|
}
|
|
|
|
/// Get a single agent by ID
|
|
///
|
|
/// Example:
|
|
/// ```dart
|
|
/// final result = await client.getAgent('agent-uuid');
|
|
///
|
|
/// result.when(
|
|
/// success: (agent) => print('Agent: ${agent.name}'),
|
|
/// error: (error) => print('Error: ${error.message}'),
|
|
/// );
|
|
/// ```
|
|
Future<Result<AgentDto>> getAgent(String id) async {
|
|
return executeQuery<AgentDto>(
|
|
endpoint: 'getAgent',
|
|
query: GetAgentQuery(id: id),
|
|
fromJson: (json) => AgentDto.fromJson(json as Map<String, Object?>),
|
|
);
|
|
}
|
|
}
|