Skip to content

Commit dd5fcd0

Browse files
committed
kickoff platform, store and agent components and integration bundle
1 parent 4cb618f commit dd5fcd0

File tree

455 files changed

+24235
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

455 files changed

+24235
-0
lines changed

.env

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# You only need to fill in the values when running the examples, see examples/
2+
3+
# For using GPT on OpenAI
4+
OPENAI_API_KEY=
5+
6+
# For using Claude on Anthropic
7+
ANTHROPIC_API_KEY=
8+
9+
# For using Mistral
10+
MISTRAL_API_KEY=
11+
12+
# For using Voyage
13+
VOYAGE_API_KEY=
14+
15+
# For using Replicate
16+
REPLICATE_API_KEY=
17+
18+
# For using Ollama
19+
OLLAMA_HOST_URL=
20+
21+
# For using GPT on Azure
22+
AZURE_OPENAI_BASEURL=
23+
AZURE_OPENAI_KEY=
24+
AZURE_OPENAI_GPT_DEPLOYMENT=
25+
AZURE_OPENAI_GPT_API_VERSION=
26+
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT=
27+
AZURE_OPENAI_EMBEDDINGS_API_VERSION=
28+
AZURE_OPENAI_WHISPER_DEPLOYMENT=
29+
AZURE_OPENAI_WHISPER_API_VERSION=
30+
31+
# For using Llama on Azure
32+
AZURE_LLAMA_BASEURL=
33+
AZURE_LLAMA_KEY=
34+
35+
# For using Bedrock
36+
AWS_ACCESS_KEY_ID=
37+
AWS_SECRET_ACCESS_KEY=
38+
AWS_DEFAULT_REGION=
39+
40+
# Hugging Face Access Token
41+
HUGGINGFACE_KEY=
42+
43+
# For using OpenRouter
44+
OPENROUTER_KEY=
45+
46+
# For using SerpApi (tool)
47+
SERP_API_KEY=
48+
49+
# For using Tavily (tool)
50+
TAVILY_API_KEY=
51+
52+
# For using Brave (tool)
53+
BRAVE_API_KEY=
54+
55+
# For using MongoDB Atlas (store)
56+
MONGODB_URI=
57+
58+
# For using Pinecone (store)
59+
PINECONE_API_KEY=
60+
PINECONE_HOST=
61+
62+
# Some examples are expensive to run, so we disable them by default
63+
RUN_EXPENSIVE_EXAMPLES=false
64+
65+
# For using Gemini
66+
GOOGLE_API_KEY=

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.doctor-rst.cache
22
.php-cs-fixer.cache
33
.phpunit.result.cache
4+
.env.local
45

56
/composer.lock
67
/vendor

composer.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,25 @@
66
],
77
"require-dev": {
88
"php": ">=8.1",
9+
"symfony/ai-agent": "@dev",
10+
"symfony/ai-platform": "@dev",
11+
"symfony/console": "^6.4|^7.0",
12+
"symfony/css-selector": "^6.4|^7.0",
13+
"symfony/dom-crawler": "^6.4|^7.0",
14+
"symfony/dotenv": "^6.4|^7.0",
915
"symfony/filesystem": "^6.4|^7.0",
1016
"symfony/finder": "^6.4|^7.0",
17+
"symfony/process": "^6.4|^7.0",
18+
"symfony/var-dumper": "^6.4|^7.0",
1119
"php-cs-fixer/shim": "^3.75"
20+
},
21+
"repositories": [
22+
{ "type": "path", "url": "src/agent" },
23+
{ "type": "path", "url": "src/platform" }
24+
],
25+
"autoload-dev": {
26+
"psr-4": {
27+
"Symfony\\AI\\Fixtures\\": "fixtures/"
28+
}
1229
}
1330
}

example

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
use Symfony\Component\Console\Command\Command;
5+
use Symfony\Component\Console\Helper\Table;
6+
use Symfony\Component\Console\Input\InputArgument;
7+
use Symfony\Component\Console\Input\InputInterface;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use Symfony\Component\Console\SingleCommandApplication;
10+
use Symfony\Component\Console\Style\SymfonyStyle;
11+
use Symfony\Component\Finder\Finder;
12+
use Symfony\Component\Finder\SplFileInfo;
13+
use Symfony\Component\Process\Process;
14+
15+
require_once __DIR__.'/vendor/autoload.php';
16+
17+
$app = (new SingleCommandApplication('Symfony AI Example Runner'))
18+
->setDescription('Runs all Symfony AI examples in folder examples/')
19+
->addArgument('subdirectory', InputArgument::OPTIONAL, 'Subdirectory to run examples from, e.g. "anthropic" or "huggingface".')
20+
->setCode(function (InputInterface $input, OutputInterface $output) {
21+
$io = new SymfonyStyle($input, $output);
22+
$io->title('Symfony AI Examples');
23+
24+
$directory = __DIR__.'/examples';
25+
26+
if ($subdirectory = $input->getArgument('subdirectory')) {
27+
$directory .= '/'.$subdirectory;
28+
if (!is_dir($directory)) {
29+
$io->error(sprintf('Subdirectory "%s" does not exist.', $subdirectory));
30+
return Command::FAILURE;
31+
}
32+
}
33+
34+
$examples = (new Finder())
35+
->in($directory)
36+
->name('*.php')
37+
->sortByName()
38+
->files();
39+
40+
/** @var array{example: SplFileInfo, process: Process} $exampleRuns */
41+
$exampleRuns = [];
42+
foreach ($examples as $example) {
43+
$exampleRuns[] = [
44+
'example' => $example,
45+
'process' => $process = new Process(['php', $example->getRealPath()]),
46+
];
47+
$process->start();
48+
}
49+
50+
$section = $output->section();
51+
$renderTable = function () use ($exampleRuns, $section) {
52+
$section->clear();
53+
$table = new Table($section);
54+
$table->setHeaders(['Example', 'State', 'Output']);
55+
foreach ($exampleRuns as $run) {
56+
/** @var SplFileInfo $example */
57+
/** @var Process $process */
58+
['example' => $example, 'process' => $process] = $run;
59+
60+
$output = str_replace(PHP_EOL, ' ', $process->getOutput());
61+
$output = strlen($output) <= 100 ? $output : substr($output, 0, 100).'...';
62+
$emptyOutput = 0 === strlen(trim($output));
63+
64+
$state = 'Running';
65+
if ($process->isTerminated()) {
66+
$success = $process->isSuccessful() && !$emptyOutput;
67+
$state = $success ? '<info>Finished</info>'
68+
: (1 === $run['process']->getExitCode() || $emptyOutput ? '<error>Failed</error>' : '<comment>Skipped</comment>');
69+
}
70+
71+
$table->addRow([$example->getRelativePathname(), $state, $output]);
72+
}
73+
$table->render();
74+
};
75+
76+
$examplesRunning = fn () => array_reduce($exampleRuns, fn ($running, $example) => $running || $example['process']->isRunning(), false);
77+
while ($examplesRunning()) {
78+
$renderTable();
79+
sleep(1);
80+
}
81+
82+
$renderTable();
83+
$io->newLine();
84+
85+
$successCount = array_reduce($exampleRuns, function ($count, $example) {
86+
if ($example['process']->isSuccessful() && strlen(trim($example['process']->getOutput())) > 0) {
87+
return $count + 1;
88+
}
89+
return $count;
90+
}, 0);
91+
92+
$totalCount = count($exampleRuns);
93+
94+
if ($successCount < $totalCount) {
95+
$io->warning(sprintf('%d out of %d examples ran successfully.', $successCount, $totalCount));
96+
} else {
97+
$io->success(sprintf('All %d examples ran successfully!', $totalCount));
98+
}
99+
100+
foreach ($exampleRuns as $run) {
101+
if (!$run['process']->isSuccessful()) {
102+
$io->section('Error in ' . $run['example']->getRelativePathname());
103+
$io->text($run['process']->getOutput());
104+
$io->text($run['process']->getErrorOutput());
105+
}
106+
}
107+
108+
return Command::SUCCESS;
109+
})
110+
->run();

examples/anthropic/chat.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
use Symfony\AI\Agent\Agent;
4+
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
5+
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
6+
use Symfony\AI\Platform\Message\Message;
7+
use Symfony\AI\Platform\Message\MessageBag;
8+
use Symfony\Component\Dotenv\Dotenv;
9+
10+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
11+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
12+
13+
if (empty($_ENV['ANTHROPIC_API_KEY'])) {
14+
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
15+
exit(1);
16+
}
17+
18+
$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
19+
$model = new Claude(Claude::SONNET_37);
20+
21+
$agent = new Agent($platform, $model);
22+
$messages = new MessageBag(
23+
Message::forSystem('You are a pirate and you write funny.'),
24+
Message::ofUser('What is the Symfony framework?'),
25+
);
26+
$response = $agent->call($messages);
27+
28+
echo $response->getContent().\PHP_EOL;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Symfony\AI\Agent\Agent;
4+
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
5+
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
6+
use Symfony\AI\Platform\Message\Content\Image;
7+
use Symfony\AI\Platform\Message\Message;
8+
use Symfony\AI\Platform\Message\MessageBag;
9+
use Symfony\Component\Dotenv\Dotenv;
10+
11+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
12+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
13+
14+
if (empty($_ENV['ANTHROPIC_API_KEY'])) {
15+
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
16+
exit(1);
17+
}
18+
19+
$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
20+
$model = new Claude(Claude::SONNET_37);
21+
22+
$agent = new Agent($platform, $model);
23+
$messages = new MessageBag(
24+
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
25+
Message::ofUser(
26+
Image::fromFile(dirname(__DIR__, 2).'/tests/Fixture/image.jpg'),
27+
'Describe this image.',
28+
),
29+
);
30+
$response = $agent->call($messages);
31+
32+
echo $response->getContent().\PHP_EOL;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Symfony\AI\Agent\Agent;
4+
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
5+
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
6+
use Symfony\AI\Platform\Message\Content\ImageUrl;
7+
use Symfony\AI\Platform\Message\Message;
8+
use Symfony\AI\Platform\Message\MessageBag;
9+
use Symfony\Component\Dotenv\Dotenv;
10+
11+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
12+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
13+
14+
if (empty($_ENV['ANTHROPIC_API_KEY'])) {
15+
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
16+
exit(1);
17+
}
18+
19+
$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
20+
$model = new Claude(Claude::SONNET_37);
21+
22+
$agent = new Agent($platform, $model);
23+
$messages = new MessageBag(
24+
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
25+
Message::ofUser(
26+
new ImageUrl('https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg'),
27+
'Describe this image.',
28+
),
29+
);
30+
$response = $agent->call($messages);
31+
32+
echo $response->getContent().\PHP_EOL;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Symfony\AI\Agent\Agent;
4+
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
5+
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
6+
use Symfony\AI\Platform\Message\Content\Document;
7+
use Symfony\AI\Platform\Message\Message;
8+
use Symfony\AI\Platform\Message\MessageBag;
9+
use Symfony\Component\Dotenv\Dotenv;
10+
11+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
12+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
13+
14+
if (empty($_ENV['ANTHROPIC_API_KEY'])) {
15+
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
16+
exit(1);
17+
}
18+
19+
$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
20+
$model = new Claude(Claude::SONNET_37);
21+
22+
$agent = new Agent($platform, $model);
23+
$messages = new MessageBag(
24+
Message::ofUser(
25+
Document::fromFile(dirname(__DIR__, 2).'/tests/Fixture/document.pdf'),
26+
'What is this document about?',
27+
),
28+
);
29+
$response = $agent->call($messages);
30+
31+
echo $response->getContent().\PHP_EOL;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Symfony\AI\Agent\Agent;
4+
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
5+
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
6+
use Symfony\AI\Platform\Message\Content\DocumentUrl;
7+
use Symfony\AI\Platform\Message\Message;
8+
use Symfony\AI\Platform\Message\MessageBag;
9+
use Symfony\Component\Dotenv\Dotenv;
10+
11+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
12+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
13+
14+
if (empty($_ENV['ANTHROPIC_API_KEY'])) {
15+
echo 'Please set the ANTHROPIC_API_KEY environment variable.'.\PHP_EOL;
16+
exit(1);
17+
}
18+
19+
$platform = PlatformFactory::create($_ENV['ANTHROPIC_API_KEY']);
20+
$model = new Claude(Claude::SONNET_37);
21+
22+
$agent = new Agent($platform, $model);
23+
$messages = new MessageBag(
24+
Message::ofUser(
25+
new DocumentUrl('https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf'),
26+
'What is this document about?',
27+
),
28+
);
29+
$response = $agent->call($messages);
30+
31+
echo $response->getContent().\PHP_EOL;

0 commit comments

Comments
 (0)