Skip to content

Commit b924429

Browse files
committed
Add source feature to more tools
1 parent ffeeb5f commit b924429

File tree

6 files changed

+86
-19
lines changed

6 files changed

+86
-19
lines changed

examples/toolbox/tavily.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,36 @@
1111

1212
use Symfony\AI\Agent\Agent;
1313
use Symfony\AI\Agent\Toolbox\AgentProcessor;
14+
use Symfony\AI\Agent\Toolbox\Tool\Clock;
1415
use Symfony\AI\Agent\Toolbox\Tool\Tavily;
1516
use Symfony\AI\Agent\Toolbox\Toolbox;
1617
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
1718
use Symfony\AI\Platform\Message\Message;
1819
use Symfony\AI\Platform\Message\MessageBag;
20+
use Symfony\Component\Clock\Clock as SymfonyClock;
1921

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

2224
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client());
2325

26+
$clock = new Clock(new SymfonyClock());
2427
$tavily = new Tavily(http_client(), env('TAVILY_API_KEY'));
25-
$toolbox = new Toolbox([$tavily], logger: logger());
26-
$processor = new AgentProcessor($toolbox);
27-
$agent = new Agent($platform, 'gpt-4o-mini', [$processor], [$processor]);
28+
$toolbox = new Toolbox([$clock, $tavily], logger: logger());
29+
$processor = new AgentProcessor($toolbox, includeSources: true);
30+
$agent = new Agent($platform, 'gpt-4o', [$processor], [$processor]);
2831

29-
$messages = new MessageBag(Message::ofUser('What was the latest game result of Dallas Cowboys?'));
30-
$result = $agent->call($messages);
32+
$prompt = <<<PROMPT
33+
Summarize the latest game of the Dallas Cowboys. When and where was it? Who was the opponent, what was the result,
34+
and how was the game and the weather in the city. Use tools for the research and only answer based on information
35+
given in the context - don't make up information.
36+
PROMPT;
3137

32-
echo $result->getContent().\PHP_EOL;
38+
$result = $agent->call(new MessageBag(Message::ofUser($prompt)));
39+
40+
echo $result->getContent().\PHP_EOL.\PHP_EOL;
41+
42+
echo 'Used sources:'.\PHP_EOL;
43+
foreach ($result->getMetadata()->get('sources', []) as $source) {
44+
echo sprintf(' - %s (%s)', $source->getName(), $source->getReference()).\PHP_EOL;
45+
}
46+
echo \PHP_EOL;

src/agent/src/Toolbox/Source/SourceMap.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace Symfony\AI\Agent\Toolbox\Source;
1313

14-
class SourceMap
14+
final class SourceMap
1515
{
1616
/**
1717
* @var Source[]

src/agent/src/Toolbox/Tool/Brave.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,27 @@
1212
namespace Symfony\AI\Agent\Toolbox\Tool;
1313

1414
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesInterface;
16+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesTrait;
17+
use Symfony\AI\Agent\Toolbox\Source\Source;
1518
use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With;
1619
use Symfony\Contracts\HttpClient\HttpClientInterface;
1720

1821
/**
1922
* @author Christopher Hertel <mail@christopher-hertel.de>
2023
*/
2124
#[AsTool('brave_search', 'Tool that searches the web using Brave Search')]
22-
final readonly class Brave
25+
final class Brave implements HasSourcesInterface
2326
{
27+
use HasSourcesTrait;
28+
2429
/**
2530
* @param array<string, mixed> $options See https://api-dashboard.search.brave.com/app/documentation/web-search/query#WebSearchAPIQueryParameters
2631
*/
2732
public function __construct(
28-
private HttpClientInterface $httpClient,
29-
#[\SensitiveParameter] private string $apiKey,
30-
private array $options = [],
33+
private readonly HttpClientInterface $httpClient,
34+
#[\SensitiveParameter] private readonly string $apiKey,
35+
private readonly array $options = [],
3136
) {
3237
}
3338

@@ -61,6 +66,13 @@ public function __invoke(
6166
]);
6267

6368
$data = $result->toArray();
69+
$results = $data['web']['results'] ?? [];
70+
71+
foreach ($results as $result) {
72+
$this->addSource(
73+
new Source($result['title'] ?? '', $result['url'] ?? '', $result['description'] ?? '')
74+
);
75+
}
6476

6577
return array_map(static function (array $result) {
6678
return ['title' => $result['title'], 'description' => $result['description'], 'url' => $result['url']];

src/agent/src/Toolbox/Tool/Clock.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@
1212
namespace Symfony\AI\Agent\Toolbox\Tool;
1313

1414
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesInterface;
16+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesTrait;
17+
use Symfony\AI\Agent\Toolbox\Source\Source;
1518
use Symfony\Component\Clock\Clock as SymfonyClock;
1619
use Symfony\Component\Clock\ClockInterface;
1720

1821
/**
1922
* @author Christopher Hertel <mail@christopher-hertel.de>
2023
*/
2124
#[AsTool('clock', description: 'Provides the current date and time.')]
22-
final readonly class Clock
25+
final class Clock implements HasSourcesInterface
2326
{
27+
use HasSourcesTrait;
28+
2429
public function __construct(
25-
private ClockInterface $clock = new SymfonyClock(),
26-
private ?string $timezone = null,
30+
private readonly ClockInterface $clock = new SymfonyClock(),
31+
private readonly ?string $timezone = null,
2732
) {
2833
}
2934

@@ -35,6 +40,10 @@ public function __invoke(): string
3540
$now = $now->setTimezone(new \DateTimeZone($this->timezone));
3641
}
3742

43+
$this->addSource(
44+
new Source('Current Time', 'Clock', $now->format('Y-m-d H:i:s'))
45+
);
46+
3847
return \sprintf(
3948
'Current date is %s (YYYY-MM-DD) and the time is %s (HH:MM:SS).',
4049
$now->format('Y-m-d'),

src/agent/src/Toolbox/Tool/SimilaritySearch.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
namespace Symfony\AI\Agent\Toolbox\Tool;
1313

1414
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesInterface;
16+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesTrait;
17+
use Symfony\AI\Agent\Toolbox\Source\Source;
1518
use Symfony\AI\Store\Document\VectorDocument;
1619
use Symfony\AI\Store\Document\VectorizerInterface;
1720
use Symfony\AI\Store\StoreInterface;
@@ -20,8 +23,10 @@
2023
* @author Christopher Hertel <mail@christopher-hertel.de>
2124
*/
2225
#[AsTool('similarity_search', description: 'Searches for documents similar to a query or sentence.')]
23-
final class SimilaritySearch
26+
final class SimilaritySearch implements HasSourcesInterface
2427
{
28+
use HasSourcesTrait;
29+
2530
/**
2631
* @var VectorDocument[]
2732
*/
@@ -47,6 +52,12 @@ public function __invoke(string $searchTerm): string
4752

4853
$result = 'Found documents with following information:'.\PHP_EOL;
4954
foreach ($this->usedDocuments as $document) {
55+
if ($document->metadata->hasSource() && $document->metadata->hasText()) {
56+
$this->addSource(
57+
new Source($document->metadata->getSource(), $document->id, $document->metadata->getText())
58+
);
59+
}
60+
5061
$result .= json_encode($document->metadata);
5162
}
5263

src/agent/src/Toolbox/Tool/Tavily.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
namespace Symfony\AI\Agent\Toolbox\Tool;
1313

1414
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesInterface;
16+
use Symfony\AI\Agent\Toolbox\Source\HasSourcesTrait;
17+
use Symfony\AI\Agent\Toolbox\Source\Source;
1518
use Symfony\Contracts\HttpClient\HttpClientInterface;
1619

1720
/**
@@ -21,15 +24,17 @@
2124
*/
2225
#[AsTool('tavily_search', description: 'search for information on the internet', method: 'search')]
2326
#[AsTool('tavily_extract', description: 'fetch content from websites', method: 'extract')]
24-
final readonly class Tavily
27+
final class Tavily implements HasSourcesInterface
2528
{
29+
use HasSourcesTrait;
30+
2631
/**
2732
* @param array<string, string|string[]|int|bool> $options
2833
*/
2934
public function __construct(
30-
private HttpClientInterface $httpClient,
31-
private string $apiKey,
32-
private array $options = ['include_images' => false],
35+
private readonly HttpClientInterface $httpClient,
36+
private readonly string $apiKey,
37+
private readonly array $options = ['include_images' => false],
3338
) {
3439
}
3540

@@ -45,6 +50,14 @@ public function search(string $query): string
4550
]),
4651
]);
4752

53+
$data = $result->toArray();
54+
55+
foreach ($data['results'] ?? [] as $item) {
56+
$this->addSource(
57+
new Source($item['title'] ?? '', $item['url'] ?? '', $item['raw_content'] ?? '')
58+
);
59+
}
60+
4861
return $result->getContent();
4962
}
5063

@@ -60,6 +73,14 @@ public function extract(array $urls): string
6073
],
6174
]);
6275

76+
$data = $result->toArray();
77+
78+
foreach ($data['results'] ?? [] as $item) {
79+
$this->addSource(
80+
new Source($item['title'] ?? '', $item['url'] ?? '', $item['raw_content'] ?? '')
81+
);
82+
}
83+
6384
return $result->getContent();
6485
}
6586
}

0 commit comments

Comments
 (0)