PHP code example of assistant-engine / filament-assistant
1. Go to this page and download the library: Download assistant-engine/filament-assistant library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
assistant-engine / filament-assistant example snippets
use AssistantEngine\Filament\FilamentAssistantPlugin;
class YourPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentAssistantPlugin::make());
}
}
return [
// Set the default chat driver class. You can override this in your local config.
'chat_driver' => \AssistantEngine\Filament\Chat\Driver\DefaultChatDriver::class,
'conversation_resolver' => \AssistantEngine\Filament\Chat\Resolvers\ConversationOptionResolver::class,
'context_resolver' => \AssistantEngine\Filament\Chat\Resolvers\ContextResolver::class,
'run_processor' => \AssistantEngine\Filament\Runs\Services\RunProcessorService::class,
'default_run_queue' => env('DEFAULT_RUN_QUEUE', 'default'),
'default_assistant' => env('DEFAULT_ASSISTANT_KEY', 'food-delivery'),
// Assistants configuration: each assistance is identified by a key.
// Each assistance has a name, a instruction, and a reference to an LLM connection.
'assistants' => [
// Example assistance configuration with key "default"
'default' => [
'name' => 'Genius',
'description' => 'Your friendly assistant ready to help with any question.',
'instruction' => 'You are a helpful assistant.',
'llm_connection' => 'openai', // This should correspond to an entry in the llm_connections section.
'model' => 'gpt-4o',
'registry_meta_mode' => false, // See meta mode for details
// List the tool identifiers to load for this assistant.
'tools' => ['weather']
],
'food-delivery' => [
'name' => 'Frank',
'description' => 'Franks here to help to get you a nice meal',
'instruction' => 'Your are Frank a funny person who loves to help customers find the right food.',
'llm_connection' => 'openai', // This should correspond to an entry in the llm_connections section.
'model' => 'gpt-4o',
'registry_meta_mode' => false, // See meta mode for details
// List the tool identifiers to load for this assistant.
'tools' => ['pizza', 'burger']
],
],
// LLM Connections configuration: each connection is identified by an identifier.
// Each connection must burgers);
},
],
],
'button' => [
'show' => true,
'options' => [
'label' => 'Food Delivery',
'size' => \Filament\Support\Enums\ActionSize::ExtraLarge,
'color' => \Filament\Support\Colors\Color::Sky,
'icon' => 'heroicon-o-chat-bubble-bottom-center-text'
]
],
// Sidebar configuration
'sidebar' => [
// Whether the sidebar is enabled
'enabled' => true,
// If set to true, the sidebar will be open by default on load.
// Using 'open_by_default' instead of 'auto_visible'
'open_by_default' => false,
// The width of the sidebar, defined as a CSS dimension.
// must be an integer
'width' => 400,
],
];
'tools' => [
'weather' => [
'namespace' => 'weather',
'description' => 'Function to get informations about the weather.',
'tool' => function (\AssistantEngine\Filament\Runs\Models\Run $run) {
// Now you can access:
// $thread = $run->thread;
// $userIdentifier = $thread->user_identifier;
return new \AssistantEngine\OpenFunctions\Core\Examples\WeatherOpenFunction();
},
]
]
'tools' => [
'weather' => [
'namespace' => 'weather',
'description' => 'Function to get information about the weather.',
'tool' => function () {
return new \AssistantEngine\OpenFunctions\Core\Examples\WeatherOpenFunction();
},
'presenter' => function (\AssistantEngine\Filament\Runs\Models\Run $run) {
// Return an instance that implements MessageListExtensionInterface, if needed.
return new \AssistantEngine\OpenFunctions\Core\Examples\WeatherMessageListExtension();
},
]
]
namespace App\Factories;
class FilamentConfigFactory
{
public static function weather(Run $run)
{
return new \AssistantEngine\OpenFunctions\Core\Examples\WeatherOpenFunction();
}
// ... other methods
}
// config/filament-assistant.php
'tools' => [
'weather' => [
'namespace' => 'weather',
'description' => 'Function to get informations about the weather.',
'tool' => [\App\Factories\FilamentConfigFactory::class, 'weather'],
],
// ... other tools
]
artisan config:cache
use AssistantEngine\OpenFunctions\Core\Contracts\AbstractOpenFunction;
use AssistantEngine\OpenFunctions\Core\Models\Responses\TextResponseItem;
use AssistantEngine\OpenFunctions\Core\Helpers\FunctionDefinition;
use AssistantEngine\OpenFunctions\Core\Helpers\Parameter;
class HelloWorldOpenFunction extends AbstractOpenFunction
{
/**
* Generate function definitions.
*
* This method returns a schema that defines the "helloWorld" function.
*/
public function generateFunctionDefinitions(): array
{
// Create a new function definition for helloWorld.
$functionDef = new FunctionDefinition(
'helloWorld',
'Returns a friendly greeting.'
);
// In this simple example, no parameters are
namespace AssistantEngine\Filament\Chat\Resolvers;
use AssistantEngine\Filament\Chat\Contracts\ConversationOptionResolverInterface;
use AssistantEngine\Filament\Chat\Models\ConversationOption;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Config;
class ConversationOptionResolver implements ConversationOptionResolverInterface
{
public function resolve(Page $page): ?ConversationOption
{
$assistantKey = Config::get('filament-assistant.default_assistant');
if (!$assistantKey) {
throw new \Exception('assistant-key must be set');
}
if (!auth()->check()) {
return null;
}
return new ConversationOption($assistantKey, auth()->user()->id);
}
}
namespace AssistantEngine\Filament\Chat\Models\ConversationOption;
// Create a new ConversationOption
$options = new ConversationOption($assistantKey, $userId);
// arbitrary data you want to pass to the llm
$options->additionalRunData = [
'your_context' => 'data'
]; // default []
// add additional tools for the assistant independent of the configuration
$options->additionalTools = ['weather']; // default []
// arbitrary data without any function
$options->metadata = ['foo' => 'bar']; // default []
// if true the next time the conversation is recreated
$options->recreate = false; // default false
namespace AssistantEngine\Filament\Chat\Resolvers;
use AssistantEngine\Filament\Chat\Contracts\ContextModelInterface;
use AssistantEngine\Filament\Chat\Contracts\ContextResolverInterface;
use Filament\Pages\Page;
use Filament\Resources\Pages\ListRecords;
use Filament\Resources\Pages\ManageRelatedRecords;
use Filament\Resources\RelationManagers\RelationManager;
class ContextResolver implements ContextResolverInterface
{
public function resolve(Page $page): array
{
$result = [];
// Collect models directly related to the page's record
if (isset($page->record)) {
$this->collectFromRecord($result, $page->record);
}
// Collect models for ListRecords page
if ($page instanceof ListRecords) {
$this->collectFromListRecordsPage($result, $page);
}
// Collect models for ManageRelatedRecords page
if ($page instanceof ManageRelatedRecords) {
$this->collectFromManageRelatedRecordsPage($result, $page);
}
// Collect models from relation managers
if (method_exists($page, "getRelationManagers") && !empty($page->getRelationManagers())) {
$this->collectFromRelationManagers($result, $page);
}
return $this->resolveCollectedModels($result);
}
}
namespace App\Modules\Assistant\Resolvers;
use App\Filament\Resources\ProductResource\Pages\Ideas\IdeaPlanner;
use App\Modules\Product\Models\ProductGoal;
use App\Modules\Product\Models\ProductIdea;
use Filament\Pages\Page;
class ContextResolver extends AssistantEngine\Filament\Chat\Resolvers\ContextResolver
{
public function resolve(Page $page): array
{
$context = parent::resolve($page);
return match (get_class($page)) {
IdeaPlanner::class => $this->handleIdeaPlannerPage($page, $context),
default => $context
};
}
protected function handleIdeaPlannerPage(IdeaPlanner $page, array $context): array
{
$context['pageDescription'] = "This page shows a matrix where product goals are the rows and the roadmap phases (now, next, later)"
. " are the columns. The user can drag and drop the product ideas between different phases and product goals"
. " The Ideas you find in the context which don't belong to a goal are unassigned";
$context = array_merge_recursive($context, $this->resolveModels(ProductGoal::class, $page->goals->all()));
return array_merge_recursive($context, $this->resolveModels(ProductIdea::class, $page->ideas->all()));
}
}
namespace AssistantEngine\Filament\Chat\Contracts;
interface ContextModelInterface
{
public static function resolveModels(array $models): array;
}
namespace AssistantEngine\Filament\Chat\Traits;
use AssistantEngine\Filament\Chat\Resolvers\ContextModelResolver;
trait ContextModel
{
public static function getContextMetaData(): array
{
return [
'schema' => self::class
];
}
public static function getContextExcludes(): array
{
return [];
}
public static function resolveModels(array $models): array
{
$result = [];
$result['data'] = null;
if (count($models) > 0) {
$result['data'] = ContextModelResolver::collection($models)->resolve();
}
$result['meta'] = self::getContextMetaData();
return $result;
}
}
namespace AssistantEngine\Filament\Chat\Contracts\ContextModelInterface;
#[Schema(
schema: "Product",
properties: [
new Property(property: "id", type: "integer"),
new Property(property: "title", type: "string"),
new Property(property: "description", type: "string"),
new Property(property: "created_at", type: "string", format: "date-time"),
new Property(property: "updated_at", type: "string", format: "date-time"),
]
)]
class Product extends Model implements ContextModelInterface
{
use ContextModel;
protected $fillable = ['title', 'description', 'integration_settings', 'assistant_overwrites'];
public static function getContextExcludes(): array
{
return ['integration_settings'];
}
public static function getContextMetaData(): array
{
return ['schema' => 'Product'];
}
}
use AssistantEngine\Filament\Chat\Components\ChatPage;
use AssistantEngine\Filament\FilamentAssistantPlugin;
use Filament\Panels\Panel;
use Filament\Panels\PanelProvider;
class YourPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentAssistantPlugin::make())
// Register the dedicated chat page:
->pages([
\AssistantEngine\Filament\Chat\Pages\AssistantChat::class
])
}
}
use AssistantEngine\Filament\Chat\Components\ChatComponent;
#[On(ChatComponent::EVENT_RUN_FINISHED)]
public function onRunFinished($messages)
{
// Handle run finished event
}