witness-sdk/php-sdk
Composer 安装命令:
composer require witness-sdk/php-sdk
包简介
The PHP SDK for the Witness Application.
README 文档
README
Witness PHP SDK
The PHP SDK for the Witness Application.
Repository: github.com/witness-sdk/php-sdk
Witness captures inference telemetry on a side channel: events are buffered in-process and delivered to witness.sh as a single batch at the end of the request. Your inference hot path is never blocked, and delivery failures never throw into your application — if ingestion is down, your models still answer.
Install
composer require witness-sdk/php-sdk
Requires PHP 8.1+ with ext-curl and ext-json. No other dependencies.
Quickstart
use Witness\Witness; Witness::init(['api_key' => 'w_live_...', 'project' => 'prod-chat']); $client = Witness::watch( OpenAI::factory() ->withApiKey('gsk_...') ->withBaseUri('https://api.groq.com/openai/v1') ->make(), ['provider' => 'groq'], ); $response = $client->chat()->create([ 'model' => 'llama-3.3-70b-versatile', 'messages' => [['role' => 'user', 'content' => 'Hello']], ]); // inference → your provider, direct // telemetry → witness.sh, at request end
Witness::watch() wraps an OpenAI-compatible client instance in a
transparent proxy — use the returned object in place of the original. Every
chat()->create(), embeddings()->create(), messages->create()
(Anthropic-style), and streaming call is traced automatically. Both method
style ($client->chat()->create()) and property style
($client->chat->completions->create()) clients work.
PHP cannot patch classes at runtime, so unlike the Python and Node SDKs (which patch the client class once),
watch()wraps each instance. Provider is inferred from the client's base URL when it is exposed publicly; most PHP clients keep it private, so passing['provider' => ...]explicitly is recommended.
Prefer explicit control? Use Witness::log() instead:
$chat = Witness::log( fn (array $messages) => $client->chat()->create([ 'model' => 'llama-3.3-70b-versatile', 'messages' => $messages, ]), ['provider' => 'groq'], ); $response = $chat([['role' => 'user', 'content' => 'Hello']]);
Witness::log() wraps any callable that performs an inference call. It
times the call, extracts model and token usage from the response by
duck-typing (any OpenAI-compatible response shape works — objects, arrays,
or ArrayAccess), and buffers an event. The wrapped callable's return value
and exceptions pass through untouched — failed calls are recorded with
status: "error" and re-thrown.
Provider and model are read from the response when possible; the options
(provider, model, operation, metadata) fill in whatever the
response cannot answer.
Opting out of telemetry
Skip reporting for specific calls:
// Callback scope — works with watch() and Witness::log() Witness::ignore(fn () => $client->chat()->create([...])); // Single call — watch() strips it before the provider sees it $client->chat()->create(['model' => '...', 'messages' => [...], 'witness_ignore' => true]);
To keep only a fraction of events on high-volume paths, set a sample rate:
Witness::init(['api_key' => '...', 'project' => '...', 'sample_rate' => 0.1]); // keep ~10%
Configuration
Witness::init() accepts an options array:
| Key | Default | Notes |
|---|---|---|
api_key |
WITNESS_API_KEY env var |
Required (option or env) |
project |
WITNESS_PROJECT env var |
Required (option or env) |
base_url |
https://witness.sh/api/v1 |
Override for staging / self-hosted |
queue_size |
10000 |
Bounded in-memory event buffer |
sample_rate |
1.0 |
Fraction of calls to record (per-call decision) |
If no API key or project is configured, init() logs a warning and the SDK
stays disabled: instrumented code runs normally and nothing is sent.
Your observability layer never crashes your app over a missing env var.
Witness::flush(timeout: 5.0) delivers buffered events now and keeps
running — useful in long-running workers (queue consumers, Octane, Swoole)
where the request never "ends". Witness::shutdown() flushes and stops; a
shutdown function is registered automatically by init(), so in classic
request-per-process PHP you never need to call either one.
Delivery model
PHP is request-scoped with no background threads, so this SDK buffers
events in memory (enqueueing is a plain array append) and posts them as one
{"events": [...]} batch envelope when flush() or shutdown() runs —
normally at the very end of the request, after your response is built.
Failed deliveries are retried with backoff (bounded by the flush timeout),
then dropped with a warning. Telemetry is never worth an exception.
Long-running workers should call Witness::flush() periodically (e.g.
after each job) so events do not sit in memory for hours.
Privacy
Witness sends metadata only: provider, model, latency, token counts, and status. Prompt and completion text are never transmitted.
Wire contract
The SDK posts {"events": [...]} batch envelopes to
POST {base_url}/events with a Bearer API key. The full contract lives in
schema/v1/event.json and is versioned via the
schema_version field on every event.
Roadmap
- Non-blocking delivery via curl_multi fire-and-forget
- Provider inference for clients that expose their base URL via config objects
- Time-to-last-token on streamed responses
Development
composer install
composer test
License
MIT
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-14