execute method

  1. @override
Future<AiRunResult> execute({
  1. required AiAgent agent,
  2. required AiRunContext context,
  3. required AiPlan plan,
  4. required AiToolRegistry toolRegistry,
  5. required AiToolPolicy toolPolicy,
})
override

Implementation

@override
Future<AiRunResult> execute({
  required AiAgent agent,
  required AiRunContext context,
  required AiPlan plan,
  required AiToolRegistry toolRegistry,
  required AiToolPolicy toolPolicy,
}) async {
  try {
    context.run.status = AiRunStatus.running;
    await context.addEvent('run.started', payload: {
      'agent': agent.name,
      'plan': plan.toMap(),
    });

    for (final step in plan.steps) {
      await context.addEvent('step.started', payload: step.toMap());

      if (step.toolName != null && step.toolName!.isNotEmpty) {
        context.run.status = AiRunStatus.waitingForTool;

        final tool = toolRegistry.tool(step.toolName!);
        if (tool == null) {
          throw StateError('Unknown AI tool: ${step.toolName}');
        }

        final invocation = AiToolInvocation(
          name: step.toolName!,
          runId: context.run.id,
          userId: context.userId,
          tenantId: context.tenantId,
          arguments: step.arguments,
          enabledByDefault: tool.enabledByDefault,
          requiredCapabilities: tool.requiredCapabilities,
        );
        final allowed = await toolPolicy.canExecute(invocation);
        if (!allowed) {
          throw StateError('Tool execution forbidden for ${step.toolName}');
        }

        final result = await tool.execute(
          AiToolContext(
            runId: context.run.id,
            userId: context.userId,
            tenantId: context.tenantId,
            state: context.state,
            arguments: step.arguments,
            context: context.requestContext,
            metadata: context.metadata,
            artifacts: context.artifacts,
          ),
        );
        context.state[step.id] = result;
        context.run.status = AiRunStatus.running;
        await context.addEvent('step.tool.completed', payload: {
          'stepId': step.id,
          'tool': step.toolName,
          'result': result,
        });
      } else {
        context.state[step.id] = step.arguments;
        await context.addEvent('step.completed', payload: {
          'stepId': step.id,
          'result': step.arguments,
        });
      }
    }

    final output = await agent.synthesize(context);
    context.run.status = AiRunStatus.completed;
    context.run.output = output;
    await context.addEvent('run.completed', payload: {
      'output': output,
    });

    return AiRunResult(
      run: context.run,
      output: output,
    );
  } catch (error) {
    context.run.status = AiRunStatus.failed;
    await context.addEvent('run.failed', payload: {
      'error': error.toString(),
    });
    rethrow;
  }
}