<?php
require 'examples/boot.php';
use Cognesy\Agents\Builder\AgentBuilder;
use Cognesy\Agents\Capability\Bash\UseBash;
use Cognesy\Agents\Capability\Core\UseContextConfig;
use Cognesy\Agents\Capability\Core\UseGuards;
use Cognesy\Agents\Capability\Core\UseLLMConfig;
use Cognesy\Agents\Capability\Subagent\UseSubagents;
use Cognesy\Agents\Collections\NameList;
use Cognesy\Agents\Data\AgentState;
use Cognesy\Agents\Enums\ExecutionStatus;
use Cognesy\Agents\Events\SubagentCompleted;
use Cognesy\Agents\Events\SubagentSpawning;
use Cognesy\Agents\Events\Support\AgentEventConsoleObserver;
use Cognesy\Agents\Telemetry\AgentsTelemetryProjector;
use Cognesy\Agents\Template\AgentDefinitionRegistry;
use Cognesy\Agents\Template\Data\AgentDefinition;
use Cognesy\Config\Env;
use Cognesy\Events\Dispatchers\EventDispatcher;
use Cognesy\Http\Telemetry\HttpClientTelemetryProjector;
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\LLMProvider;
use Cognesy\Polyglot\Telemetry\PolyglotTelemetryProjector;
use Cognesy\Telemetry\Adapters\Langfuse\LangfuseConfig;
use Cognesy\Telemetry\Adapters\Langfuse\LangfuseExporter;
use Cognesy\Telemetry\Adapters\Langfuse\LangfuseHttpTransport;
use Cognesy\Telemetry\Application\Registry\TraceRegistry;
use Cognesy\Telemetry\Application\Telemetry;
use Cognesy\Telemetry\Application\Projector\CompositeTelemetryProjector;
use Cognesy\Telemetry\Application\Projector\RuntimeEventBridge;
$serviceName = 'examples.d05.subagent-telemetry-langfuse';
$baseUrl = (string) Env::get('LANGFUSE_BASE_URL', '');
if ($baseUrl === '') {
throw new RuntimeException('Set LANGFUSE_BASE_URL in .env to run this example.');
}
$publicKey = (string) Env::get('LANGFUSE_PUBLIC_KEY', '');
if ($publicKey === '') {
throw new RuntimeException('Set LANGFUSE_PUBLIC_KEY in .env to run this example.');
}
$secretKey = (string) Env::get('LANGFUSE_SECRET_KEY', '');
if ($secretKey === '') {
throw new RuntimeException('Set LANGFUSE_SECRET_KEY in .env to run this example.');
}
$events = new EventDispatcher($serviceName);
$hub = new Telemetry(
registry: new TraceRegistry(),
exporter: new LangfuseExporter(
transport: new LangfuseHttpTransport(new LangfuseConfig(
baseUrl: $baseUrl,
publicKey: $publicKey,
secretKey: $secretKey,
)),
),
);
(new RuntimeEventBridge(new CompositeTelemetryProjector([
new AgentsTelemetryProjector($hub),
new PolyglotTelemetryProjector($hub),
new HttpClientTelemetryProjector($hub),
])))->attachTo($events);
$logger = new AgentEventConsoleObserver(
useColors: true,
showTimestamps: true,
showContinuation: true,
showToolArgs: true,
);
$workDir = dirname(__DIR__, 3);
$registry = new AgentDefinitionRegistry();
$registry->register(new AgentDefinition(
name: 'repo_inspector',
description: 'Inspects repository paths with bash and reports concise evidence',
systemPrompt: <<<'SYSTEM'
You inspect repositories with the bash tool.
Every factual claim must come from bash output.
Use bash at least 3 separate times.
Never combine commands with && or ;.
SYSTEM,
tools: NameList::fromArray(['bash']),
));
$subagentSpawns = [];
$subagentCompletions = [];
$agent = AgentBuilder::base($events)
->withCapability(new UseContextConfig(systemPrompt: <<<'SYSTEM'
You are an orchestration agent.
If `repo_inspector` is available, you must delegate repository inspection to it.
Your first tool call must be `spawn_subagent`.
Do not use bash directly when `repo_inspector` can do the work.
If you skip delegation, the task is incomplete.
Summarize delegated findings clearly and briefly.
SYSTEM))
->withCapability(new UseLLMConfig(llm: LLMProvider::using('openai')))
->withCapability(new UseBash(baseDir: $workDir))
->withCapability(new UseSubagents(provider: $registry))
->withCapability(new UseGuards(maxSteps: 8, maxTokens: 12288, maxExecutionTime: 60))
->build()
->wiretap($logger->wiretap())
->wiretap(static function (object $event) use (&$subagentSpawns, &$subagentCompletions): void {
if ($event instanceof SubagentSpawning) {
$subagentSpawns[] = $event;
}
if ($event instanceof SubagentCompleted) {
$subagentCompletions[] = $event;
}
});
$task = <<<'TASK'
You must call `spawn_subagent` as your first tool call.
Use subagent `repo_inspector`.
Do not call bash yourself.
Pass this task to the subagent:
Inspect this repository with bash.
Requirements:
- Use bash at least 3 separate times.
- Do not combine commands with && or ;.
- Run these as separate bash calls:
1. pwd
2. ls examples/D05_AgentTroubleshooting
3. rg -n "UseSubagents|SpawnSubagentTool|SubagentSpawning" packages/agents/src/Capability/Subagent/*.php packages/agents/src/Events/Subagent*.php
Return exactly 3 short bullets:
1. What kind of repository this is
2. Where the agent telemetry examples live
3. What the subagent telemetry path records
After the subagent returns, provide only its 3 bullets as the final answer.
TASK;
$state = AgentState::empty()->withMessages(Messages::fromString($task));
echo "=== Agent Execution Log ===\n\n";
$finalState = $agent->execute($state);
$hub->flush();
$collectToolNames = function (AgentState $state) use (&$collectToolNames): array {
return array_reduce(
$state->stepExecutions()->all(),
static function (array $names, $stepExecution) use (&$collectToolNames): array {
$stepNames = [];
foreach ($stepExecution->step()->toolExecutions()->all() as $toolExecution) {
$stepNames[] = $toolExecution->name();
$value = $toolExecution->value();
if ($value instanceof AgentState) {
$stepNames = [...$stepNames, ...$collectToolNames($value)];
}
}
return [...$names, ...$stepNames];
},
[],
);
};
$toolNames = $collectToolNames($finalState);
$toolCallCount = count($toolNames);
$bashCallCount = count(array_filter($toolNames, static fn(string $name): bool => $name === 'bash'));
$spawnSubagentCount = count(array_filter($toolNames, static fn(string $name): bool => $name === 'spawn_subagent'));
echo "\n=== Result ===\n";
$response = $finalState->finalResponse()->toString() ?: 'No response';
echo "Answer: {$response}\n";
echo "Status: {$finalState->status()->value}\n";
echo "Steps: {$finalState->stepCount()}\n";
echo "Tools used: " . implode(' > ', $toolNames) . "\n";
echo "Total tool calls: {$toolCallCount}\n";
echo "Bash calls across parent/child runs: {$bashCallCount}\n";
echo "spawn_subagent calls: {$spawnSubagentCount}\n";
echo "Subagents spawned: " . count($subagentSpawns) . "\n";
echo "Subagents completed: " . count($subagentCompletions) . "\n";
echo "Telemetry: flushed to Langfuse\n";
assert($finalState->status() === ExecutionStatus::Completed);
assert($response !== '');
assert($spawnSubagentCount >= 1);
assert(count($subagentSpawns) >= 1);
assert(count($subagentCompletions) >= 1);
assert($bashCallCount >= 3);
?>