Skip to main content
The OpenAI Responses provider exposes a code interpreter tool that allows you to execute Python code in a sandboxed container environment hosted by OpenAI. If you’d like to keep state between requests, you can reuse an existing container from a previous request. Any artifacts that are generated by the code interpreter tool can be downloaded by your app.

Enable Code Interpreter

You can enable the code interpreter tool via the chatModelOptions parameter of the Agent constructor:
final agent = Agent(
  'openai-responses',
  chatModelOptions: const OpenAIResponsesChatModelOptions(
    serverSideTools: {OpenAIServerSideTool.codeInterpreter},
  ),
);

Streaming Execution

Code deltas and lifecycle events stream through metadata['code_interpreter']:
await for (final chunk in agent.sendStream(prompt)) {
  final events = chunk.metadata['code_interpreter'] as List?;
  if (events == null) continue;

  for (final event in events) {
    switch (event['type']) {
      case 'response.code_interpreter_call_code.delta':
        stdout.write(event['delta']);
      case 'response.output_item.done':
        stdout.writeln('container: ${event['item']['container_id']}');
    }
  }
}
Use these events to show live output, capture errors, or record container IDs.

Container Reuse

Containers persist across turns when you supply a containerId. The example below captures the ID from the first response and injects it into the second:
String? containerId;
await for (final chunk in agent.sendStream(prompt)) {
  containerId ??= containerIdFromMetadata(chunk.metadata);
}

final agent2 = Agent(
  'openai-responses',
  chatModelOptions: OpenAIResponsesChatModelOptions(
    serverSideTools: const {OpenAIServerSideTool.codeInterpreter},
    codeInterpreterConfig: CodeInterpreterConfig(containerId: containerId),
  ),
);

agent2.sendStream(prompt2)...;

// Helper function to extract container ID from metadata
String? containerIdFromMetadata(Map<String, dynamic> metadata) {
  final ciEvents = metadata['code_interpreter'] as List?;
  if (ciEvents != null) {
    for (final event in ciEvents) {
      // Check for container_id at the top level (older synthetic events)
      if (event['container_id'] != null) {
        return event['container_id'] as String;
      }
      // Check for container_id nested in item (response.output_item.done
      // events)
      final item = event['item'];
      if (item is Map && item['container_id'] != null) {
        return item['container_id'] as String;
      }
    }
  }
  return null;
}

Generated Files

When the interpreter saves files (e.g. images, CSVs) they are downloaded automatically and attached as DataPart instances on the assistant message. Each DataPart includes the actual filename from the interpreter (e.g., fibonacci.csv, plot.png) for easy identification and saving.
final history = <ChatMessage>[];
await for (final chunk in agent.sendStream(prompt)) {
  history.addAll(chunk.messages);
}

// Access generated files
for (final msg in history) {
  for (final part in msg.parts) {
    if (part is DataPart) {
      print('File: ${part.name}'); // e.g., "fibonacci.csv"
      print('MIME: ${part.mimeType}'); // e.g., "text/csv"
      print('Size: ${part.bytes.length} bytes');

      // Save to disk with original filename
      File('output/${part.name}').writeAsBytesSync(part.bytes);
    }
  }
}

Example