Extending Orbit
Orbit is designed to be extended. Use contracts, service bindings, and custom implementations to tailor the dashboard to your needs.
Contracts
Orbit defines contracts (interfaces) for core services:
AgentRegistryContract
php
use Ashrafic\AiOrbit\Contracts\AgentRegistryContract;
interface AgentRegistryContract
{
public function all(): Collection;
public function find(string $class): ?array;
public function refresh(): void;
}Bind your custom implementation:
php
// In AppServiceProvider
use Ashrafic\AiOrbit\Contracts\AgentRegistryContract;
use App\Services\CustomAgentRegistry;
public function register(): void
{
$this->app->singleton(AgentRegistryContract::class, CustomAgentRegistry::class);
}Custom Agent Registry Example
php
namespace App\Services;
use Ashrafic\AiOrbit\Contracts\AgentRegistryContract;
use Illuminate\Support\Collection;
class CustomAgentRegistry implements AgentRegistryContract
{
public function all(): Collection
{
// Load agents from your own source (database, API, etc.)
return collect([
'App\AI\Agents\SupportAgent',
'App\AI\Agents\SalesAgent',
]);
}
public function find(string $class): ?array
{
// Return custom metadata
return [
'class' => $class,
'instructions' => 'Custom instructions',
'tools' => [],
'has_schema' => false,
];
}
public function refresh(): void
{
// Clear any caches
}
}Extending Services
Custom Cost Calculator
php
use Ashrafic\AiOrbit\Services\CostCalculator;
class CustomCostCalculator extends CostCalculator
{
public function calculate(string $model, int $inputTokens, int $outputTokens): array
{
// Add your own pricing logic
if ($model === 'custom-model') {
return [
'input_cost' => 0,
'output_cost' => 0,
'total' => 0,
'currency' => 'USD',
];
}
return parent::calculate($model, $inputTokens, $outputTokens);
}
}Bind it:
php
app()->singleton(CostCalculator::class, CustomCostCalculator::class);Custom Export Service
php
use Ashrafic\AiOrbit\Services\ExportService;
class CustomExportService extends ExportService
{
public function toPest(string $conversationId): string
{
$content = parent::toPest($conversationId);
// Add custom assertions or setup
$content .= "\n // Custom assertion\n";
$content .= " expect(true)->toBeTrue();\n";
return $content;
}
public function toXml(string $conversationId): string
{
// Add a completely new export format
$conversation = $this->repository->find($conversationId);
// ... XML generation logic
}
}Custom Livewire Components
Create entirely new Livewire components that integrate with Orbit:
php
namespace App\Http\Livewire;
use Ashrafic\AiOrbit\Services\ConversationRepository;
use Livewire\Component;
class CustomAnalytics extends Component
{
public function render()
{
$repository = app(ConversationRepository::class);
// Your custom analytics logic
$stats = $this->calculateCustomStats();
return view('livewire.custom-analytics', [
'stats' => $stats,
]);
}
}Register it:
php
use Livewire\Livewire;
use App\Http\Livewire\CustomAnalytics;
Livewire::component('custom-analytics', CustomAnalytics::class);Use it in a published view:
blade
<livewire:custom-analytics />Custom Middleware
Add custom middleware to Orbit routes by extending the middleware stack:
php
// config/ai-orbit.php
'middleware' => ['web', 'auth', 'custom-middleware'],Custom Notifications
Extend Orbit's notifications:
php
use Ashrafic\AiOrbit\Notifications\BudgetExceeded;
class SlackBudgetExceeded extends BudgetExceeded
{
public function via(object $notifiable): array
{
return ['mail', 'slack'];
}
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->content("Budget alert: {$this->alert->period} threshold exceeded!");
}
}Events
Orbit dispatches events that you can listen to:
Override Events
Listen for Livewire events in your components:
php
// In your custom component
#[On('tool-call-counts-updated')]
public function handleToolCallCounts(array $counts): void
{
// React to tool call updates
}Best Practices
- Extend, don't replace — Where possible, extend existing services rather than replacing them entirely
- Use contracts — Program against interfaces (
AgentRegistryContract) rather than concrete classes - Test extensions — Write tests for your custom implementations
- Document changes — Keep a record of what you've extended for future maintainers
- Watch for updates — Major Orbit updates may change service signatures; test after updating