Skip to content
Closed

Try #552

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/code-quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ jobs:
- name: Build root packages
run: php .github/build-packages.php

- name: Run PHPStan on examples
run: |
cd examples/ && $COMPOSER_UP && ../link && $PHPSTAN

- name: Run PHPStan on packages
run: |
source .github/workflows/.utils.sh

echo "$PACKAGES" | xargs -n1 | parallel -j +3 "_run_task {} '(cd src/{} && $COMPOSER_UP && $PHPSTAN)'"

- name: Run PHPStan on examples
run: |
cd examples/ && $COMPOSER_UP && $PHPSTAN
3 changes: 3 additions & 0 deletions examples/.env
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ REPLICATE_API_KEY=
# For using Ollama
OLLAMA_HOST_URL=

# For using Docker Model Runner
DOCKER_MODEL_RUNNER_HOST_URL=

# For using GPT on Azure
AZURE_OPENAI_BASEURL=
AZURE_OPENAI_KEY=
Expand Down
31 changes: 31 additions & 0 deletions examples/dockermodelrunner/chat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Platform\Bridge\DockerModelRunner\Completions;
use Symfony\AI\Platform\Bridge\DockerModelRunner\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('DOCKER_MODEL_RUNNER_HOST_URL'), http_client());
$model = new Completions();

$agent = new Agent($platform, $model, logger: logger());
$messages = new MessageBag(
Message::forSystem('You are a pirate and you write funny.'),
Message::ofUser('What is the Symfony framework?'),
);
$result = $agent->call($messages, [
'max_tokens' => 500, // specific options just for this call
]);
echo $result->getContent().\PHP_EOL;
24 changes: 24 additions & 0 deletions examples/dockermodelrunner/embeddings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\AI\Platform\Bridge\DockerModelRunner\Embeddings;
use Symfony\AI\Platform\Bridge\DockerModelRunner\PlatformFactory;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('DOCKER_MODEL_RUNNER_HOST_URL'), http_client());
$response = $platform->invoke(new Embeddings(Embeddings::NOMIC_EMBED_TEXT), <<<TEXT
Once upon a time, there was a country called Japan. It was a beautiful country with a lot of mountains and rivers.
The people of Japan were very kind and hardworking. They loved their country very much and took care of it. The
country was very peaceful and prosperous. The people lived happily ever after.
TEXT);

print_vectors($response);
34 changes: 34 additions & 0 deletions examples/dockermodelrunner/toolcall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\Toolbox\AgentProcessor;
use Symfony\AI\Agent\Toolbox\Tool\Wikipedia;
use Symfony\AI\Agent\Toolbox\Toolbox;
use Symfony\AI\Platform\Bridge\DockerModelRunner\Completions;
use Symfony\AI\Platform\Bridge\DockerModelRunner\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('DOCKER_MODEL_RUNNER_HOST_URL'), http_client());
$model = new Completions(Completions::GEMMA_3_N);

$wikipedia = new Wikipedia(http_client());
$toolbox = new Toolbox([$wikipedia]);
$processor = new AgentProcessor($toolbox);
$agent = new Agent($platform, $model, [$processor], [$processor], logger: logger());

$messages = new MessageBag(Message::ofUser('Who is the actual Prime Minister of France?'));
$result = $agent->call($messages);

echo $result->getContent().\PHP_EOL;
1 change: 1 addition & 0 deletions src/platform/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ CHANGELOG
- LM Studio (local model hosting)
- Cerebras (language models like Llama 4, Qwen 3, and more)
- Perplexity (Sonar models, supporting search results)
- Docker Model Runner (local model hosting)
* Add comprehensive message system with role-based messaging:
- `UserMessage` for user inputs with multi-modal content
- `SystemMessage` for system instructions
Expand Down
47 changes: 47 additions & 0 deletions src/platform/src/Bridge/DockerModelRunner/Completions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Bridge\DockerModelRunner;

use Symfony\AI\Platform\Capability;
use Symfony\AI\Platform\Model;

/**
* @author Mathieu Santostefano <msantostefano@proton.me>
*/
class Completions extends Model
{
public const GEMMA_3_N = 'ai/gemma3n';
public const GEMMA_3 = 'ai/gemma3';
public const QWEN_2_5 = 'ai/qwen2.5';
public const QWEN_3 = 'ai/qwen3';
public const QWEN_3_CODER = 'ai/qwen3-coder';
public const LLAMA_3_1 = 'ai/llama3.1';
public const LLAMA_3_2 = 'ai/llama3.2';
public const LLAMA_3_3 = 'ai/llama3.3';
public const MISTRAL = 'ai/mistral';
public const MISTRAL_NEMO = 'ai/mistral-nemo';
public const PHI_4 = 'ai/phi4';
public const DEEPSEEK_R_1 = 'ai/deepseek-r1-distill-llama';
public const SEED_OSS = 'ai/seed-oss';
public const GPT_OSS = 'ai/gpt-oss';
public const SMOLLM_2 = 'ai/smollm2';
public const SMOLLM_3 = 'ai/smollm3';

public function __construct(
string $name = self::SMOLLM_2,
array $options = [],
) {
// All capabilities are assumed to be supported since we cannot know in advance
// whether Docker Model Runner and/or each model allows for a particular capability.
parent::__construct($name, Capability::cases(), $options);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\AI\Platform\Bridge\DockerModelRunner\Completions;

use Symfony\AI\Platform\Bridge\DockerModelRunner\Completions;
use Symfony\AI\Platform\Model;
use Symfony\AI\Platform\ModelClientInterface;
use Symfony\AI\Platform\Result\RawHttpResult;
use Symfony\Component\HttpClient\EventSourceHttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;

/**
* @author Mathieu Santostefano <msantostefano@proton.me>
*/
final readonly class ModelClient implements ModelClientInterface
{
private EventSourceHttpClient $httpClient;

public function __construct(
HttpClientInterface $httpClient,
private string $hostUrl,
) {
$this->httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
}

public function supports(Model $model): bool
{
return $model instanceof Completions;
}

public function request(Model $model, array|string $payload, array $options = []): RawHttpResult
{
return new RawHttpResult($this->httpClient->request('POST', \sprintf('%s/engines/v1/chat/completions', $this->hostUrl), [
'json' => array_merge($options, $payload),
]));
}
}
Loading
Loading