SkillAgentSearch skills...

Sidekick

A fluent Laravel package for integrating with OpenAI, Anthropic Claude, Mistral, and Cohere AI services. Features a modern builder API, typed responses, streaming support, database-backed conversations, a RAG knowledge base system, an embeddable chat widget, and first-class testing support.

Install / Use

/learn @PapaRascal2020/Sidekick
About this skill

Quality Score

0/100

Supported Platforms

Claude Code
Claude Desktop

README

<p align="center"> <a href="https://laravel.com"><img alt="Laravel Package" src="https://img.shields.io/badge/Laravel-10%2F11%2F12-red?logo=laravel&logoColor=white"/></a>&nbsp;&nbsp;&nbsp; <img alt="PHP" src="https://img.shields.io/badge/PHP-8.2%2B-blue?logo=php&logoColor=white"/> &nbsp;&nbsp;&nbsp; <img alt="Latest Version" src="https://img.shields.io/packagist/v/paparascaldev/sidekick?label=Latest"/> &nbsp;&nbsp; <a href="https://packagist.org/packages/paparascaldev/sidekick"><img alt="Packagist" src="https://img.shields.io/badge/Packagist-F28D1A?logo=Packagist&logoColor=white"/></a> </p> <p align="center"> <img src="sidekick.png" alt="Sidekick" width="200" /> </p> <p align="center"> <a href="https://sidekickforlaravel.com"><img alt="Full Documentation" src="https://img.shields.io/badge/Full%20Documentation-sidekickforlaravel.com-ef4444?style=for-the-badge"/></a> </p>

Sidekick v2.0

A fluent Laravel package for integrating with OpenAI, Anthropic Claude, Mistral, and Cohere AI services. Features a modern builder API, typed responses, streaming support, database-backed conversations, an embeddable chat widget, and first-class testing support.

Requirements

  • PHP 8.2+
  • Laravel 10, 11, or 12

Installation

composer require paparascaldev/sidekick
php artisan sidekick:install

Or install manually:

composer require paparascaldev/sidekick
php artisan vendor:publish --tag=sidekick-config
php artisan migrate

Configuration

Add your API keys to .env (only add the providers you use):

SIDEKICK_OPENAI_TOKEN=your-openai-key
SIDEKICK_CLAUDE_TOKEN=your-anthropic-key
SIDEKICK_MISTRAL_TOKEN=your-mistral-key
SIDEKICK_COHERE_TOKEN=your-cohere-key

Publish and customize the config file:

php artisan vendor:publish --tag=sidekick-config

Config File Overview

The config/sidekick.php file includes:

return [
    // Default provider when none specified
    'default' => env('SIDEKICK_DEFAULT_PROVIDER', 'openai'),

    // Default provider + model per capability
    'defaults' => [
        'text'          => ['provider' => 'openai', 'model' => 'gpt-4o'],
        'image'         => ['provider' => 'openai', 'model' => 'dall-e-3'],
        'audio'         => ['provider' => 'openai', 'model' => 'tts-1'],
        'transcription' => ['provider' => 'openai', 'model' => 'whisper-1'],
        'embedding'     => ['provider' => 'openai', 'model' => 'text-embedding-3-small'],
        'moderation'    => ['provider' => 'openai', 'model' => 'text-moderation-latest'],
    ],

    // Provider API keys and base URLs
    'providers' => [
        'openai'    => ['api_key' => env('SIDEKICK_OPENAI_TOKEN'), 'base_url' => '...'],
        'anthropic' => ['api_key' => env('SIDEKICK_CLAUDE_TOKEN'), 'base_url' => '...'],
        'mistral'   => ['api_key' => env('SIDEKICK_MISTRAL_TOKEN'), 'base_url' => '...'],
        'cohere'    => ['api_key' => env('SIDEKICK_COHERE_TOKEN'), 'base_url' => '...'],
    ],

    // Register custom providers
    'custom_providers' => [],

    // Chat widget settings
    'widget' => [
        'enabled'       => env('SIDEKICK_WIDGET_ENABLED', false),
        'route_prefix'  => 'sidekick',
        'middleware'     => ['web'],
        'provider'      => env('SIDEKICK_WIDGET_PROVIDER', 'openai'),
        'model'         => env('SIDEKICK_WIDGET_MODEL', 'gpt-4o'),
        'system_prompt' => env('SIDEKICK_WIDGET_SYSTEM_PROMPT', 'You are a helpful assistant.'),
        'max_tokens'    => 1024,
    ],

    // HTTP timeout and retry settings
    'http' => [
        'timeout'         => env('SIDEKICK_HTTP_TIMEOUT', 30),
        'connect_timeout' => env('SIDEKICK_HTTP_CONNECT_TIMEOUT', 10),
        'retry'           => ['times' => 0, 'sleep' => 100],
    ],
];

Quick Start

You can use the Sidekick facade or the sidekick() helper function:

use PapaRascalDev\Sidekick\Facades\Sidekick;

// Using the facade
$response = Sidekick::text()->withPrompt('Hello')->generate();

// Using the helper function
$response = sidekick()->text()->withPrompt('Hello')->generate();

Text Generation

$response = Sidekick::text()
    ->using('openai', 'gpt-4o')
    ->withSystemPrompt('You are a helpful assistant.')
    ->withPrompt('What is Laravel?')
    ->generate();

echo $response->text;                // "Laravel is a PHP web framework..."
echo $response->usage->totalTokens;  // 150
echo $response->meta->latencyMs;     // 523.4
echo $response->finishReason;        // "stop"
echo (string) $response;             // Same as $response->text

All TextBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and model | | withPrompt(string $prompt) | Add a user message | | withSystemPrompt(string $prompt) | Set the system prompt | | withMessages(array $messages) | Set the full message history (array of Message objects or arrays) | | addMessage(Role $role, string $content) | Append a single message with a specific role | | withMaxTokens(int $maxTokens) | Set max tokens (default: 1024) | | withTemperature(float $temp) | Set temperature (default: 1.0) | | generate(): TextResponse | Execute and return a TextResponse | | stream(): StreamResponse | Execute and return a streamable StreamResponse |

Streaming

$stream = Sidekick::text()
    ->using('anthropic', 'claude-sonnet-4-20250514')
    ->withPrompt('Write a haiku about coding')
    ->stream();

// Iterate over chunks
foreach ($stream as $chunk) {
    echo $chunk;
}

// Get the full buffered text after iteration
$fullText = $stream->text();

// Or return as an SSE response from a controller
return $stream->toResponse();

Conversations (with DB persistence)

// Start a conversation
$convo = Sidekick::conversation()
    ->using('openai', 'gpt-4o')
    ->withSystemPrompt('You are a travel advisor.')
    ->withMaxTokens(2048)
    ->begin();

$response = $convo->send('I want to visit Japan.');
echo $response->text;

// Get the conversation ID to resume later
$conversationId = $convo->getConversation()->id;

// Resume later
$convo = Sidekick::conversation()->resume($conversationId);
$response = $convo->send('What about accommodation?');

// Delete a conversation
$convo->delete();

All ConversationBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and model | | withSystemPrompt(string $prompt) | Set the system prompt | | withMaxTokens(int $maxTokens) | Set max tokens (default: 1024) | | begin(): self | Start a new conversation (persisted to DB) | | resume(string $id): self | Resume an existing conversation by UUID | | send(string $message): TextResponse | Send a message and get a response | | delete(): bool | Delete the conversation and its messages | | getConversation(): ?Conversation | Get the underlying Eloquent model |

Image Generation

$response = Sidekick::image()
    ->using('openai', 'dall-e-3')
    ->withPrompt('A sunset over mountains')
    ->withSize('1024x1024')
    ->withQuality('hd')
    ->count(2)
    ->generate();

echo $response->url();           // First image URL
echo $response->urls;            // Array of all URLs
echo $response->revisedPrompt;   // DALL-E's revised prompt (if any)

All ImageBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and model | | withPrompt(string $prompt) | Set the image prompt | | withSize(string $size) | Set dimensions (default: 1024x1024) | | withQuality(string $quality) | Set quality: standard or hd (default: standard) | | count(int $count) | Number of images to generate (default: 1) | | generate(): ImageResponse | Execute and return an ImageResponse |

Audio (Text-to-Speech)

$response = Sidekick::audio()
    ->using('openai', 'tts-1')
    ->withText('Hello, welcome to Sidekick!')
    ->withVoice('nova')
    ->withFormat('mp3')
    ->generate();

$response->save('audio/welcome.mp3');       // Save to default disk
$response->save('audio/welcome.mp3', 's3'); // Save to specific disk
echo $response->format;                     // "mp3"

All AudioBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and model | | withText(string $text) | Set the text to speak | | withVoice(string $voice) | Set the voice (default: alloy) | | withFormat(string $format) | Set audio format (default: mp3) | | generate(): AudioResponse | Execute and return an AudioResponse |

Transcription

$response = Sidekick::transcription()
    ->using('openai', 'whisper-1')
    ->withFile('/path/to/audio.mp3')
    ->withLanguage('en')
    ->generate();

echo $response->text;       // Transcribed text
echo $response->language;   // "en"
echo $response->duration;   // Duration in seconds
echo (string) $response;    // Same as $response->text

All TranscriptionBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and model | | withFile(string $filePath) | Path to the audio file | | withLanguage(string $language) | Hint the language (optional) | | generate(): TranscriptionResponse | Execute and return a TranscriptionResponse |

Embeddings

$response = Sidekick::embedding()
    ->using('openai', 'text-embedding-3-small')
    ->withInput('Laravel is a great framework')
    ->generate();

$vector = $response->vector();      // First embedding vector (array of floats)
$all = $response->embeddings;       // All embedding vectors
echo $response->usage->totalTokens; // Token usage

All EmbeddingBuilder methods:

| Method | Description | |--------|-------------| | using(string $provider, ?string $model) | Set provider and mod

Related Skills

View on GitHub
GitHub Stars31
CategoryDevelopment
Updated1mo ago
Forks0

Languages

PHP

Security Score

95/100

Audited on Mar 4, 2026

No findings