gemini_cli_sdk 1.1.0 copy "gemini_cli_sdk: ^1.1.0" to clipboard
gemini_cli_sdk: ^1.1.0 copied to clipboard

A powerful Dart SDK for interacting with Gemini CLI, providing seamless integration with AI-powered coding assistance through the Google Gemini CLI.

Gemini CLI SDK for Dart #

A powerful Dart SDK for interacting with Google Gemini CLI, providing seamless integration with AI-powered coding assistance through the Gemini CLI.

Features #

  • πŸš€ Easy Integration: Simple API for creating chat sessions with Gemini
  • πŸ“ File Support: Send files along with text prompts for context-aware responses
  • πŸ’Ύ Bytes Support: Send in-memory data as temporary files (auto-cleanup on dispose)
  • πŸ“‹ Schema Support: Get structured responses using JSON schemas
  • πŸ”„ Session Management: Automatic conversation continuity
  • πŸ› οΈ Auto-Installation: Built-in methods to check and install Gemini CLI
  • πŸ”Œ MCP Support: Full Model Context Protocol integration for connecting to external tools
  • 🧹 Resource Management: Proper cleanup and disposal of chat sessions and temp files
  • πŸ” Secure: API key management with environment variable support
  • ⚑ Reliable: Simple Process.run based implementation (no streaming complexity)
  • 🌊 Streaming: Support for streaming responses in real-time

Prerequisites #

Before using this SDK, you need:

  1. Node.js and npm (for Gemini CLI)

  2. Gemini CLI

    • Install globally: npm install -g @google/gemini-cli
    • Or via Homebrew: brew install gemini-cli
    • Or use the SDK's built-in installer (see below)
  3. Gemini API Key

    • Get your API key from Google AI Studio
    • Free tier: 60 requests/min, 1,000 requests/day (with OAuth)
    • Or use API key tier: 100 requests/day

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  gemini_cli_sdk: ^1.1.0

Then run:

dart pub get

Quick Start #

Basic Usage #

import 'package:gemini_cli_sdk/gemini_cli_sdk.dart';

void main() async {
  // Initialize the SDK with your API key
  final geminiSDK = GeminiSDK('YOUR_API_KEY');
  
  // Create a new chat session
  final geminiChat = geminiSDK.createNewChat();
  
  try {
    // Send a simple text message
    final result = await geminiChat.sendMessage([
      GeminiSdkContent.text('What is the capital of France?'),
    ]);
    
    print('Gemini says: $result');
  } finally {
    // Always dispose of the chat when done
    await geminiChat.dispose();
  }
}

Sending Files with Messages #

import 'dart:io';
import 'package:gemini_cli_sdk/gemini_cli_sdk.dart';

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');
  final geminiChat = geminiSDK.createNewChat();
  
  try {
    // Send a message with a file
    final result = await geminiChat.sendMessage([
      GeminiSdkContent.text('Please analyze this HTML file and extract the user name'),
      GeminiSdkContent.file(File('example.html')),
    ]);
    
    print('Analysis result: $result');
  } finally {
    await geminiChat.dispose();
  }
}

Using Schemas for Structured Responses #

import 'dart:io';
import 'package:gemini_cli_sdk/gemini_cli_sdk.dart';

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');
  final geminiChat = geminiSDK.createNewChat();
  
  try {
    // Define a schema with nullable properties
    final schema = SchemaObject(
      properties: {
        'userName': SchemaProperty.string(
          description: 'The name of the user found in the HTML',
          nullable: false, // Required field
        ),
        'userEmail': SchemaProperty.string(
          description: 'The email of the user if found',
          nullable: true, // Optional field
        ),
        'userRole': SchemaProperty.string(
          description: 'The role or title of the user',
          nullable: true, // Optional field
        ),
      },
    );
    
    // Send message with schema
    final result = await geminiChat.sendMessageWithSchema(
      messages: [
        GeminiSdkContent.text('Extract user information from this HTML file'),
        GeminiSdkContent.file(File('profile.html')),
      ],
      schema: schema,
    );
    
    print('Model message: ${result.modelMessage}');
    print('Extracted data: ${result.data}');
    
    // Access specific fields
    final userName = result.data['userName'];
    print('User name: $userName');
  } finally {
    await geminiChat.dispose();
  }
}

Streaming Responses #

import 'package:gemini_cli_sdk/gemini_cli_sdk.dart';

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');
  final geminiChat = geminiSDK.createNewChat();
  
  try {
    // Stream the response
    await for (final chunk in geminiChat.streamResponse([
      GeminiSdkContent.text('Write a detailed explanation of quantum computing'),
    ])) {
      print(chunk); // Print each chunk as it arrives
    }
  } finally {
    await geminiChat.dispose();
  }
}

Advanced Configuration #

System Prompts #

The SDK supports custom system prompts that complement (not override) Gemini's default system prompt. This allows you to add additional context or instructions to guide the model's behavior:

final geminiChat = geminiSDK.createNewChat(
  options: GeminiChatOptions(
    systemPrompt: '''You are a senior software engineer with expertise in Dart.
Always consider best practices and performance implications.
Provide code examples when relevant.''',
    repeatSystemPrompt: false, // Only include in first message (default)
  ),
);

System Prompt Options:

  • systemPrompt: Additional context/instructions to complement Gemini's default behavior
  • repeatSystemPrompt: Whether to include the prompt in every message (default: false)
    • false: Include only in the first message (maintains context through conversation)
    • true: Include in every message (useful for strict formatting requirements)

Example with repeated system prompt:

final chat = geminiSDK.createNewChat(
  options: GeminiChatOptions(
    systemPrompt: 'Always respond with exactly 3 bullet points.',
    repeatSystemPrompt: true, // Ensures format consistency across all messages
  ),
);

Chat Options #

final geminiChat = geminiSDK.createNewChat(
  options: GeminiChatOptions(
    model: 'gemini-2.5-flash', // or 'gemini-2.5-pro'
    systemPrompt: 'You are a helpful coding assistant',
    repeatSystemPrompt: false, // Only in first message
    maxTurns: 5,
    allowedTools: ['Read', 'Write', 'Bash'],
    permissionMode: 'acceptEdits',
    cwd: '/path/to/project',
    outputJson: true,
    timeoutMs: 30000,
    includeDirectories: true,
    directories: ['/src', '/lib'],
    nonInteractive: true,
  ),
);

Checking and Installing Gemini SDK #

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');

  // Check if Gemini CLI is installed
  final isInstalled = await geminiSDK.isGeminiCLIInstalled();

  if (!isInstalled) {
    print('Gemini CLI is not installed. Installing...');

    try {
      // Install the CLI globally
      await geminiSDK.installGeminiCLI(global: true);
      print('Installation complete!');
    } catch (e) {
      print('Installation failed: $e');
    }
  }

  // Get SDK information
  final info = await geminiSDK.getSDKInfo();
  print('SDK Info: $info');
}

Auto-Update SDK #

The SDK provides a convenient method to automatically check for and install updates:

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');

  // Automatically check for updates and install if needed
  await geminiSDK.updateToNewestVersionIfNeeded(global: true);

  // The function will:
  // 1. Check if CLI is installed (installs if not)
  // 2. Compare current version with latest npm version
  // 3. Update if a newer version is available
}

MCP (Model Context Protocol) Support #

The SDK provides comprehensive support for MCP, allowing Gemini to connect to external tools and services.

Checking MCP Installation #

final mcpInfo = await geminiSDK.isMcpInstalled();
print('MCP enabled: ${mcpInfo.hasMcpSupport}');
print('Configured servers: ${mcpInfo.servers.length}');

for (final server in mcpInfo.servers) {
  print('  - ${server.name}: ${server.status}');
}

Listing MCP Servers #

// List all configured MCP servers
final servers = await geminiSDK.listMcpServers();

for (final server in servers) {
  print('Server: ${server.name}');
  print('  Command: ${server.command}');
  print('  Args: ${server.args.join(' ')}');
  if (server.env != null && server.env!.isNotEmpty) {
    print('  Environment: ${server.env!.keys.join(', ')}');
  }
}
// Install filesystem MCP server
await geminiSDK.installPopularMcpServer('filesystem');

// Install GitHub MCP with environment variables
await geminiSDK.installPopularMcpServer('github', 
  environment: {'GITHUB_TOKEN': 'your-github-token'}
);

// Available popular servers:
// - filesystem: File system access
// - github: GitHub integration
// - postgres: PostgreSQL database
// - git: Git operations
// - puppeteer: Web automation
// - sequential-thinking: Problem solving
// - slack: Slack integration
// - google-drive: Google Drive access

Adding Custom MCP Servers #

// Add a custom MCP server
final customServer = McpServer(
  name: 'my-custom-server',
  command: 'node',
  args: ['path/to/server.js'],
  env: {'API_KEY': 'your-api-key'},
);

await geminiSDK.addMcpServer(
  'my-custom-server',
  customServer: customServer,
);

// Or add an npm package as MCP server
await geminiSDK.addMcpServer(
  'my-npm-server',
  packageName: '@company/mcp-server',
  options: McpAddOptions(
    scope: McpScope.user,
    useNpx: true,
    environment: {'CONFIG': 'value'},
  ),
);

Removing MCP Servers #

// Remove an MCP server
await geminiSDK.removeMcpServer('my-custom-server');

Getting MCP Server Details #

// Get details about a specific MCP server
final details = await geminiSDK.getMcpServerDetails('filesystem');

if (details != null) {
  print('Server: ${details.name}');
  print('Command: ${details.command}');
  print('Args: ${details.args}');
}

Using MCP in Chat Sessions #

Once MCP servers are configured, they're automatically available in chat sessions:

final chat = geminiSDK.createNewChat();

// Gemini can now use the configured MCP tools
final result = await chat.sendMessage([
  GeminiSdkContent.text(
    'List all files in my Documents folder' // Works if filesystem MCP is installed
  ),
]);

Schema Building #

The SDK provides convenient factory methods for building schemas with nullable control:

final schema = SchemaObject(
  properties: {
    'name': SchemaProperty.string(
      description: 'User name',
      defaultValue: 'Anonymous',
      nullable: false, // Required field
    ),
    'age': SchemaProperty.number(
      description: 'User age',
      nullable: false, // Required field
    ),
    'email': SchemaProperty.string(
      description: 'User email',
      nullable: true, // Optional field (default)
    ),
    'isActive': SchemaProperty.boolean(
      description: 'Whether the user is active',
      defaultValue: true,
      nullable: false, // Required with default value
    ),
    'tags': SchemaProperty.array(
      items: SchemaProperty.string(),
      description: 'List of tags',
      nullable: true, // Optional array
    ),
    'metadata': SchemaProperty.object(
      properties: {
        'created': SchemaProperty.string(nullable: false),
        'updated': SchemaProperty.string(nullable: true),
      },
      description: 'Metadata object',
      nullable: true, // Optional nested object
    ),
  },
  // The 'required' array is automatically generated from nullable: false properties
  description: 'User information schema',
);

Nullable Property Behavior #

  • nullable: false - The property is required and must be present in the response
  • nullable: true (default) - The property is optional and may be omitted or null
  • Properties with nullable: false are automatically added to the JSON schema's required array
  • You can still use the legacy required parameter on SchemaObject for backward compatibility

Error Handling #

The SDK provides specific exception types for different error scenarios:

import 'package:gemini_cli_sdk/gemini_cli_sdk.dart';

void main() async {
  final geminiSDK = GeminiSDK('YOUR_API_KEY');
  final geminiChat = geminiSDK.createNewChat();
  
  try {
    final result = await geminiChat.sendMessage([
      GeminiSdkContent.text('Hello, Gemini!'),
    ]);
    print(result);
  } on CLINotFoundException {
    print('Gemini CLI is not installed. Please install it first.');
  } on ProcessException catch (e) {
    print('Process error: ${e.message}');
    if (e.exitCode != null) {
      print('Exit code: ${e.exitCode}');
    }
  } on JSONDecodeException catch (e) {
    print('Failed to parse response: ${e.message}');
  } on GeminiSDKException catch (e) {
    print('SDK error: ${e.message}');
  } finally {
    await geminiChat.dispose();
  }
}

Authentication Methods #

The SDK supports multiple authentication methods:

1. Direct API Key #

final geminiSDK = GeminiSDK('YOUR_API_KEY');

2. Environment Variable #

export GEMINI_API_KEY="your-api-key-here"
final apiKey = Platform.environment['GEMINI_API_KEY'] ?? '';
final geminiSDK = GeminiSDK(apiKey);

3. OAuth (Via CLI) #

The Gemini CLI also supports OAuth authentication with your Google account for higher rate limits.

4. Vertex AI #

For enterprise features, you can use Vertex AI authentication:

export GOOGLE_API_KEY="your-vertex-api-key"
export GOOGLE_GENAI_USE_VERTEXAI=true

Model Selection #

The SDK supports different Gemini models:

  • gemini-2.5-pro - Most capable model with 1M token context window
  • gemini-2.5-flash - Faster, lighter model for quick responses
final chat = geminiSDK.createNewChat(
  options: GeminiChatOptions(
    model: 'gemini-2.5-flash', // or 'gemini-2.5-pro'
  ),
);

Resource Management #

Important: Always Dispose Chat Sessions #

Always dispose of chat sessions when done to ensure proper cleanup:

// Method 1: Using try-finally
final chat = geminiSDK.createNewChat();
try {
  // Use the chat
  await chat.sendMessage([...]);
} finally {
  await chat.dispose();
}

// Method 2: Dispose all sessions at once
await geminiSDK.dispose(); // Disposes all active sessions

API Reference #

GeminiSDK Class #

  • GeminiSDK(String apiKey) - Creates a new SDK instance
  • createNewChat({GeminiChatOptions? options}) - Creates a new chat session
  • isGeminiCLIInstalled() - Checks if Gemini CLI is installed
  • installGeminiCLI({bool global = true}) - Installs the Gemini CLI
  • updateToNewestVersionIfNeeded({bool global = true}) - Updates SDK to newest version if available
  • getSDKInfo() - Gets information about installed SDKs
  • isMcpInstalled() - Checks MCP installation status
  • listMcpServers() - Lists all configured MCP servers
  • installPopularMcpServer(name, {environment}) - Installs a popular MCP server
  • addMcpServer(name, {packageName, customServer, options}) - Adds an MCP server
  • getMcpServerDetails(name) - Gets details about a specific server
  • removeMcpServer(name) - Removes an MCP server
  • dispose() - Disposes all active chat sessions

GeminiChat Class #

  • sendMessage(List<GeminiSdkContent> contents) - Sends a message and returns the response
  • sendMessageWithSchema({messages, schema}) - Sends a message with a schema for structured response
  • streamResponse(List<GeminiSdkContent> contents) - Streams the response
  • get sessionId - Gets the current session ID (null until first message)
  • resetConversation() - Resets the conversation, starting a new session
  • dispose() - Disposes the chat session and cleans up resources (including temp files)

GeminiSdkContent #

  • GeminiSdkContent.text(String text) - Creates text content
  • GeminiSdkContent.file(File file) - Creates file content
  • GeminiSdkContent.bytes({data, fileExtension}) - Creates content from bytes (temporary file)

Troubleshooting #

Gemini CLI not found #

If you get a CLINotFoundException, make sure Gemini CLI is installed:

npm install -g @google/gemini-cli

Or use the SDK's built-in installer:

await geminiSDK.installGeminiSDK();

Permission Errors #

On Unix-like systems, you might need to use sudo for global npm installations:

sudo npm install -g @google/gemini-cli

Process Cleanup #

Always dispose of chat sessions to prevent resource leaks:

await geminiChat.dispose();
// or
await geminiSDK.dispose(); // Disposes all sessions

Rate Limits #

Be aware of the rate limits for your authentication method:

  • OAuth (free): 60 requests/min, 1,000 requests/day
  • API Key (free): 100 requests/day
  • Vertex AI: Higher limits based on your plan

Examples #

Check the example/ directory for more comprehensive examples:

  • example/basic_usage.dart - Simple text messaging
  • example/file_analysis.dart - Analyzing files with Gemini
  • example/schema_example.dart - Using schemas for structured responses
  • example/system_prompt_example.dart - Using custom system prompts
  • example/streaming_example.dart - Streaming responses
  • example/installation_check.dart - Checking and installing dependencies
  • example/mcp_management.dart - Managing MCP servers
  • example/bytes_content_example.dart - Working with in-memory data

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Support #

For issues and questions:

Acknowledgments #

  • Built on top of the official Gemini CLI by Google
  • Inspired by the Claude Code SDK architecture
  • Supports Model Context Protocol (MCP) for extensibility
0
likes
150
points
118
downloads

Publisher

unverified uploader

Weekly Downloads

A powerful Dart SDK for interacting with Gemini CLI, providing seamless integration with AI-powered coding assistance through the Google Gemini CLI.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

path, uuid

More

Packages that depend on gemini_cli_sdk