<?php
require 'examples/boot.php';
use Cognesy\Agents\Builder\AgentBuilder;
use Cognesy\Agents\Capability\Bash\UseBash;
use Cognesy\Agents\Capability\Core\UseGuards;
use Cognesy\Agents\Capability\Core\UseHook;
use Cognesy\Agents\Data\AgentState;
use Cognesy\Agents\Events\Support\AgentConsoleLogger;
use Cognesy\Agents\Hook\Collections\HookTriggers;
use Cognesy\Agents\Hook\Data\HookContext;
use Cognesy\Agents\Hook\Hooks\CallableHook;
// Create console logger for execution visibility
$logger = new AgentConsoleLogger(
useColors: true,
showTimestamps: true,
showContinuation: true,
showToolArgs: false, // We'll show args in our custom hook output
);
// Dangerous patterns to block
$blockedPatterns = [
'rm -rf',
'rm -r /',
'sudo rm',
'> /dev/sda',
'mkfs',
'dd if=',
':(){:|:&};:', // Fork bomb
];
$blockedPatterns = array_map(
static fn(string $pattern): string => strtolower(trim($pattern)),
$blockedPatterns,
);
// Build agent with bash capability and security hook
$agent = AgentBuilder::base()
->withCapability(new UseBash())
->withCapability(new UseHook(
hook: new CallableHook(function (HookContext $ctx) use ($blockedPatterns): HookContext {
$toolCall = $ctx->toolCall();
if ($toolCall === null) {
return $ctx;
}
$args = $toolCall->args();
$rawCommand = match (true) {
is_array($args) && isset($args['command']) && is_string($args['command']) => $args['command'],
default => '',
};
$command = strtolower(trim((string) preg_replace('/\s+/', ' ', $rawCommand)));
if ($command === '') {
return $ctx;
}
// Check for dangerous patterns
foreach ($blockedPatterns as $pattern) {
if (str_contains($command, $pattern)) {
echo " [HOOK] BLOCKED - Dangerous pattern detected: {$pattern}\n";
return $ctx->withToolExecutionBlocked("Dangerous command: {$pattern}");
}
}
echo " [HOOK] ALLOWED - {$rawCommand}\n";
return $ctx;
}),
triggers: HookTriggers::beforeToolUse(),
priority: 100, // High priority = runs first
))
->withCapability(new UseGuards(maxSteps: 8, maxTokens: 4096, maxExecutionTime: 30))
->build()
->wiretap($logger->wiretap());
// Test with safe commands
$state = AgentState::empty()->withUserMessage(
'List the files in the current directory and show the date'
);
echo "=== Test 1: Safe Commands ===\n\n";
$finalState = $agent->execute($state);
echo "\n=== Result ===\n";
$response = $finalState->finalResponse()->toString() ?: 'No response';
echo "Answer: {$response}\n";
echo "Steps: {$finalState->stepCount()}\n";
echo "Status: {$finalState->status()->value}\n";
// Test with dangerous command (simulated prompt)
echo "\n=== Test 2: Dangerous Command Detection ===\n\n";
$state2 = AgentState::empty()->withUserMessage(
'Delete all files with: rm -rf /'
);
$finalState2 = $agent->execute($state2);
echo "\n=== Result ===\n";
$hasErrors = $finalState2->currentStep()?->hasErrors() ?? false;
echo "Command was " . ($hasErrors ? "BLOCKED (security hook worked!)" : "executed") . "\n";
echo "Steps: {$finalState2->stepCount()}\n";
echo "Status: {$finalState2->status()->value}\n";
// Assertions
assert(!empty($finalState->finalResponse()->toString()), 'Expected non-empty response from safe commands');
assert($finalState->stepCount() >= 1, 'Expected at least 1 step for safe commands');
assert($finalState2->stepCount() >= 1, 'Expected at least 1 step for dangerous command test');
?>