PHP code example of blundergoat / strands-php-client

1. Go to this page and download the library: Download blundergoat/strands-php-client library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

blundergoat / strands-php-client example snippets


use StrandsPhpClient\StrandsClient;
use StrandsPhpClient\Config\StrandsConfig;

$client = new StrandsClient(
    config: new StrandsConfig(endpoint: 'http://localhost:8081'),
);

$response = $client->invoke('Should we migrate to microservices?');

echo $response->text;
echo $response->agent;               // Which agent handled it (e.g. "analyst")
echo $response->usage->inputTokens;

use StrandsPhpClient\StrandsClient;
use StrandsPhpClient\Config\StrandsConfig;
use StrandsPhpClient\Http\PsrHttpTransport;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;

$client = new StrandsClient(
    config: new StrandsConfig(endpoint: 'http://localhost:8081'),
    transport: new PsrHttpTransport(
        httpClient: new Client(['timeout' => 120]),
        requestFactory: new HttpFactory(),
        streamFactory: new HttpFactory(),
    ),
);

$response = $client->invoke('Should we migrate to microservices?');
echo $response->text;

use StrandsPhpClient\Context\AgentInput;

// Text with an image
$input = AgentInput::text("What's in this image?")
    ->withImage(base64_encode($imageBytes), 'image/png');

$response = $client->invoke(message: $input);

// Text with a document from S3
$input = AgentInput::text('Summarise this report')
    ->withDocumentFromS3('s3://my-bucket/report.pdf', 'pdf', 'report');

// Resume after an interrupt (human-in-the-loop)
$input = AgentInput::interruptResponse($interruptId, ['approved' => true]);

use StrandsPhpClient\Context\AgentContext;

$response = $client->invoke(
    message: 'Analyse this proposal',
    context: AgentContext::create()
        ->withMetadata('persona', 'analyst')
        ->withSystemPrompt('Be concise.'),
    sessionId: 'session-001',
);

$response->text;                         // Agent's response
$response->agent;                        // Agent name (e.g. "analyst")
$response->sessionId;                    // Session ID for follow-ups
$response->usage;                        // Token usage (inputTokens, outputTokens)
$response->usage->totalTokens();         // Total tokens (input + output)
$response->toolsUsed;                    // Tools the agent called
$response->metadata;                     // Unrecognised response fields (forward-compat)

// Interrupt handling (human-in-the-loop)
if ($response->isInterrupted()) {
    foreach ($response->interrupts as $interrupt) {
        echo $interrupt->toolName;       // Tool that needs approval
        echo $interrupt->reason;         // Why the agent paused
    }
}

// Guardrail traces (content safety)
if ($response->guardrailTrace !== null) {
    echo $response->guardrailTrace->action;  // 'INTERVENED' or 'NONE'
}

use StrandsPhpClient\Streaming\StreamEvent;
use StrandsPhpClient\Streaming\StreamEventType;

$result = $client->stream(
    message: 'Explain quantum computing',
    onEvent: function (StreamEvent $event) {
        match ($event->type) {
            StreamEventType::Text     => print($event->text),
            StreamEventType::ToolUse  => print("[Using tool: {$event->toolName}]"),
            StreamEventType::Complete => print("\n[Done]"),
            StreamEventType::Error    => print("Error: {$event->errorMessage}"),
            default                   => null,
        };
    },
    sessionId: 'session-001',
);

echo $result->text;                          // Full accumulated text
echo $result->sessionId;                     // Session ID
echo $result->usage->inputTokens;            // Token usage
echo $result->usage->totalTokens();          // Total tokens (input + output)
echo $result->textEvents;                    // Number of text chunks received
echo $result->totalEvents;                   // Total events received
echo $result->timeToFirstTextTokenMs;        // Client-measured TTFT in ms
echo $result->isInterrupted() ? 'yes' : 'no'; // Whether the agent was interrupted

// Synchronous - returns raw decoded JSON array
$result = $client->postJson('/file-summarise', [
    'file_base64' => base64_encode($fileBytes),
    'file_name' => 'report.pdf',
], timeout: 120);

// Streaming - delivers raw decoded JSON arrays to the callback
$client->streamSse('/file-summarise-stream', [
    'file_base64' => base64_encode($fileBytes),
], function (array $event) {
    match ($event['type'] ?? '') {
        'text'     => print($event['content']),
        'complete' => print("\n[Done]"),
        default    => null,
    };
}, timeout: 120);

use StrandsPhpClient\Exceptions\AgentErrorException;

try {
    $client->postJson('/validate', $payload);
} catch (AgentErrorException $e) {
    $e->statusCode;    // 422
    $e->getMessage();  // "Validation failed"
    $e->responseBody;  // ['detail' => '...', 'errors' => [...]]
}

$r1 = $client->invoke('Draft a referral letter', sessionId: 'consult-001');
$r2 = $client->invoke('Make it more formal', sessionId: 'consult-001');

$context = AgentContext::create()
    ->withMetadata('clinic_id', 'CL-789')
    ->withSystemPrompt('You are a clinical documentation assistant.')
    ->withPermission('read:patients')
    ->withDocument('referral.pdf', base64_encode($pdfBytes), 'application/pdf');

$config = new StrandsConfig(
    endpoint: 'https://api.example.com/agent',
    maxRetries: 3,          // Retry up to 3 times (invoke/postJson only)
    retryDelayMs: 500,      // 500ms → 1s → 2s (exponential backoff with jitter)
    connectTimeout: 5,      // Fail fast if server is down
);

$client = new StrandsClient(config: $config, logger: $yourPsr3Logger);

use StrandsPhpClient\Auth\NullAuth;
use StrandsPhpClient\Auth\ApiKeyAuth;

// No auth (default -local development)
$config = new StrandsConfig(
    endpoint: 'http://localhost:8081',
);

// API key auth (production)
$config = new StrandsConfig(
    endpoint: 'https://api.example.com/agent',
    auth: new ApiKeyAuth('sk-your-api-key'),
);

// Custom header (e.g. X-API-Key instead of Authorization: Bearer)
$config = new StrandsConfig(
    endpoint: 'https://api.example.com/agent',
    auth: new ApiKeyAuth('sk-your-api-key', headerName: 'X-API-Key', valuePrefix: ''),
);

// AWS SigV4 auth (agents behind API Gateway with IAM)
use StrandsPhpClient\Auth\SigV4Auth;

$config = new StrandsConfig(
    endpoint: 'https://abc123.execute-api.us-east-1.amazonaws.com/prod',
    auth: new SigV4Auth(
        accessKeyId: 'AKIA...',
        secretAccessKey: 'wJalr...',
        region: 'us-east-1',
    ),
);

// SigV4 from environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
$config = new StrandsConfig(
    endpoint: 'https://abc123.execute-api.us-east-1.amazonaws.com/prod',
    auth: SigV4Auth::fromEnvironment(region: 'us-east-1'),
);

use StrandsPhpClient\StrandsClient;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class ChatController extends AbstractController
{
    public function __construct(
        #[Autowire(service: 'strands.client.analyst')]
        private readonly StrandsClient $analyst,

        #[Autowire(service: 'strands.client.skeptic')]
        private readonly StrandsClient $skeptic,
    ) {}
}

// config/bundles.php
return [
    StrandsPhpClient\Integration\Symfony\StrandsBundle::class => ['all' => true],
];

// config/strands.php (publish with: php artisan vendor:publish --tag=strands-config)
return [
    'default' => env('STRANDS_DEFAULT_AGENT', 'default'),

    'agents' => [
        'default' => [
            'endpoint' => env('STRANDS_ENDPOINT', 'http://localhost:8081'),
            'auth' => [
                'driver' => env('STRANDS_AUTH_DRIVER', 'null'),
                'api_key' => env('STRANDS_API_KEY'),
            ],
            'timeout' => (int) env('STRANDS_TIMEOUT', 120),
        ],
        'analyst' => [
            'endpoint' => env('AGENT_ENDPOINT'),
            'auth' => ['driver' => 'api_key', 'api_key' => env('AGENT_API_KEY')],
            'timeout' => 300,
        ],
    ],
];

use StrandsPhpClient\StrandsClient;

class ChatController extends Controller
{
    public function __construct(
        private readonly StrandsClient $client, // default agent
    ) {}
}

// Named agent via container
$analyst = app('strands.client.analyst');

use StrandsPhpClient\Integration\Laravel\Facades\Strands;

$response = Strands::invoke('Analyse this proposal');

composer 
mermaid
graph LR
    A["PHP Application<br/><small>Laravel · Symfony · Slim</small>"] -->|"invoke() / stream()"| B["strands-php-client"]
    B -->|"HTTP + SSE"| C["Strands Agent<br/><small>Python · FastAPI</small>"]
    C -->|"Reasoning Loop"| D["LLM Provider<br/><small>Bedrock · Ollama · OpenAI</small>"]
    C -->|"Tool Calls"| E["Tools & APIs<br/><small>DB · Search · Custom</small>"]

    style A fill:#7c3aed,color:#fff,stroke:none
    style B fill:#2563eb,color:#fff,stroke:none
    style C fill:#059669,color:#fff,stroke:none
    style D fill:#d97706,color:#fff,stroke:none
    style E fill:#d97706,color:#fff,stroke:none
bash
composer vendor:publish --tag=strands-config
bash
composer 
bash
composer