The-Agency/lib/src/agents/agent_executor.dart

210 lines
5.1 KiB
Dart

// Agent execution engine
// Spawns and manages agent instances
import 'dart:async';
import '../api/openrouter_client.dart';
import '../chat/tool_loop_service.dart';
import '../local_state.dart';
import 'agent_context.dart';
/// Executes a single agent
class AgentExecutor {
static final AgentExecutor _instance = AgentExecutor._internal();
factory AgentExecutor() => _instance;
AgentExecutor._internal();
final Map<String, _RunningAgent> _agents = {};
int _idCounter = 1;
/// Spawn and run an agent
Future<String> spawnAgent({
required AgentDefinition definition,
required AgentContext context,
required String task,
required String apiKey,
required String model,
}) async {
final agentId = 'agent_${_idCounter++}';
final agent = _RunningAgent(
id: agentId,
definition: definition,
context: context.createChildContext(childAgentId: agentId),
task: task,
apiKey: apiKey,
model: model,
);
_agents[agentId] = agent;
// Start agent in background
agent.run().then((result) {
// Agent completed
context.recordSubAgentResult(agentId, result);
}).catchError((e) {
print('Agent $agentId failed: $e');
context.recordSubAgentResult(
agentId,
AgentResult.failure(agentId: agentId, error: e.toString()),
);
});
return agentId;
}
/// Get agent result (non-blocking)
AgentResult? getResult(String agentId) {
final agent = _agents[agentId];
if (agent == null) {
return null;
}
return agent.result;
}
/// Wait for agent completion
Future<AgentResult> waitForAgent(String agentId,
{Duration timeout = const Duration(hours: 24)}) async {
final agent = _agents[agentId];
if (agent == null) {
throw Exception('Agent $agentId not found');
}
return agent.waitForCompletion(timeout: timeout);
}
/// Get all running agents
List<Map<String, dynamic>> getAllAgents() {
return _agents.entries.map((e) {
return {
'id': e.key,
'type': e.value.definition.type,
'task': e.value.task,
'status': e.value.isComplete ? 'completed' : 'running',
'result': e.value.result?.toJson(),
};
}).toList();
}
/// Cancel an agent
Future<bool> cancelAgent(String agentId) async {
final agent = _agents[agentId];
if (agent == null) {
return false;
}
agent.cancel();
_agents.remove(agentId);
return true;
}
}
/// Represents a running agent instance
class _RunningAgent {
final String id;
final AgentDefinition definition;
final AgentContext context;
final String task;
final String apiKey;
final String model;
DateTime _startTime = DateTime.now();
DateTime? _endTime;
AgentResult? result;
bool _cancelled = false;
final Completer<AgentResult> _completer = Completer();
_RunningAgent({
required this.id,
required this.definition,
required this.context,
required this.task,
required this.apiKey,
required this.model,
});
bool get isComplete => _endTime != null;
/// Run the agent
Future<AgentResult> run() async {
try {
// Create API client for this agent
final client = OpenRouterClient(
config: OpenRouterConfig(
apiKey: apiKey,
model: model,
),
);
// Create tool loop for this agent
final toolLoop = ToolLoopService();
// Build agent-specific system prompt
final systemPrompt = '''${definition.getSystemPrompt()}
Task: $task
Context:
- Session ID: ${context.sessionId}
- Working Directory: ${context.workingDirectory}
- Parent Agent: ${context.parentAgentId}
${context.sharedState.isNotEmpty ? '- Shared State: ${context.sharedState}' : ''}
Use available tools to complete this task. Report your findings clearly.''';
// Run the tool loop for this agent
final toolResult = await toolLoop.runTurn(
client: client,
model: model,
apiKey: apiKey,
getSettings: () => context.settings,
apiMessages: context.conversationHistory,
userText: task,
workingDirectory: context.workingDirectory,
);
// Extract output
final output = toolResult.responseText;
// Create result
result = AgentResult.success(
agentId: id,
output: output,
data: {
'messages_exchanged': toolResult.apiMessages.length,
'web_searches': toolResult.webSearchRequests,
'web_fetches': toolResult.webFetchRequests,
},
duration: DateTime.now().difference(_startTime),
);
_endTime = DateTime.now();
_completer.complete(result!);
return result!;
} catch (e, st) {
result = AgentResult.failure(
agentId: id,
error: e.toString(),
duration: DateTime.now().difference(_startTime),
);
_endTime = DateTime.now();
_completer.completeError(e, st);
return result!;
}
}
/// Wait for agent to complete
Future<AgentResult> waitForCompletion({Duration timeout = const Duration(hours: 24)}) {
return _completer.future.timeout(timeout);
}
/// Cancel this agent
void cancel() {
_cancelled = true;
}
}