Opik Wave 1 Commit 3: Version bump, docs, and hook registration
Version & Changelog: - prautoblogger.php: 0.11.0 → 0.12.0 - Add Opik PHP constants (PRAUTOBLOGGER_OPIK_API_KEY, WORKSPACE, URL_OVERRIDE) with fallback empty defaults so wp-config.php can override - CHANGELOG.md: v0.12.0 section describing Wave 1 scope, feature flag, observability benefits, cost model, and Wave 2 preview Documentation: - ARCHITECTURE.md: New 'Opik LLM Observability (Optional)' section with feature-flag design, credential isolation, span lifecycle, call sites, cost/performance implications, and code structure overview - CONVENTIONS.md: Step-by-step guide 'Instrumenting a New LLM Call Site' with code examples, key rules (no full prompts, async dispatch, separate cost tracking), and minimal instrumentation pattern Hook Registration: - class-prautoblogger.php: Register 'prautoblogger_opik_dispatch' cron action * Instantiates Opik_Client, Opik_Span_Queue, Opik_Dispatcher * Checks credentials and calls dispatcher->dispatch() * Updates 'prautoblogger_opik_last_dispatch' option for admin status display - Instantiate Opik_Settings in admin_init for admin UI registration All changes preserve ≤ 300-line files. Part of Wave 1 (observability skeleton). Target: v0.12.0
This commit is contained in:
102
CONVENTIONS.md
102
CONVENTIONS.md
@@ -332,4 +332,104 @@ curl -s -X POST -H "Authorization: token $GH_TOKEN" \
|
||||
|
||||
### When this changes
|
||||
|
||||
If the peptiderepo GitHub account is ever upgraded to Pro (or the repo goes public), replace this soft-enforcement section with a note pointing to the real branch protection rules in repo settings.
|
||||
If the peptiderepo GitHub account is ever upgraded to Pro (or the repo goes public), replace this soft-enforcement section with a note pointing to the real branch protection rules in repo settings.
|
||||
## Instrumenting a New LLM Call Site for Opik (v0.12.0+)
|
||||
|
||||
When you add a new LLM call (via `$llm->send_chat_completion()`), follow this pattern to capture it in Opik:
|
||||
|
||||
### 1. Get the trace context
|
||||
|
||||
At the start of your method, grab the per-request singleton:
|
||||
|
||||
```php
|
||||
$ctx = PRAutoBlogger_Opik_Trace_Context::current();
|
||||
```
|
||||
|
||||
### 2. Start the span
|
||||
|
||||
Before the LLM call, declare a span with metadata:
|
||||
|
||||
```php
|
||||
$span_id = $ctx->start_span(
|
||||
array(
|
||||
'name' => 'my_llm_operation', // kebab-case, descriptive
|
||||
'type' => 'llm',
|
||||
'model' => $model, // e.g. 'gpt-4', from get_option()
|
||||
'provider' => 'openrouter', // or the actual provider name
|
||||
'input' => array( 'key' => 'value' ), // optional metadata (no full prompts!)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### 3. Make the LLM call (unchanged)
|
||||
|
||||
```php
|
||||
$response = $this->llm->send_chat_completion(
|
||||
array(
|
||||
array( 'role' => 'system', 'content' => $system_prompt ),
|
||||
array( 'role' => 'user', 'content' => $user_prompt ),
|
||||
),
|
||||
$model,
|
||||
array( 'temperature' => 0.7, 'max_tokens' => 4000 )
|
||||
);
|
||||
```
|
||||
|
||||
### 4. End the span with output
|
||||
|
||||
After the response, record the outcome:
|
||||
|
||||
```php
|
||||
$ctx->end_span(
|
||||
$span_id,
|
||||
array(
|
||||
'output' => array( 'response_length' => strlen( $response['content'] ?? '' ) ),
|
||||
'usage' => array(
|
||||
'prompt_tokens' => $response['prompt_tokens'],
|
||||
'completion_tokens' => $response['completion_tokens'],
|
||||
'total_tokens' => $response['prompt_tokens'] + $response['completion_tokens'],
|
||||
),
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Key rules
|
||||
|
||||
- **Never log full prompts.** Use prompt hashes or version tags in `input`. Full text blows payload size and leaks content policy.
|
||||
- **Check the feature flag at call-site level?** No. The singleton is always available; Opik_Dispatcher checks the flag before dispatch.
|
||||
- **Async dispatch?** Yes. Spans are queued; dispatch happens via `prautoblogger_opik_dispatch` cron (no blocking).
|
||||
- **Cost logging?** Unchanged. Your `cost_tracker->log_api_call()` remains separate from Opik; Opik is observability-only.
|
||||
|
||||
### Example: minimal instrumentation
|
||||
|
||||
```php
|
||||
public function my_operation( $input ) {
|
||||
$model = get_option( 'my_model', 'default-model' );
|
||||
$ctx = PRAutoBlogger_Opik_Trace_Context::current();
|
||||
|
||||
$span_id = $ctx->start_span(
|
||||
array(
|
||||
'name' => 'my_operation',
|
||||
'type' => 'llm',
|
||||
'model' => $model,
|
||||
'provider' => 'openrouter',
|
||||
)
|
||||
);
|
||||
|
||||
$response = $this->llm->send_chat_completion( /* ... */ );
|
||||
|
||||
$ctx->end_span(
|
||||
$span_id,
|
||||
array(
|
||||
'usage' => array(
|
||||
'prompt_tokens' => $response['prompt_tokens'],
|
||||
'completion_tokens' => $response['completion_tokens'],
|
||||
'total_tokens' => $response['prompt_tokens'] + $response['completion_tokens'],
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return $response['content'];
|
||||
}
|
||||
```
|
||||
|
||||
That's it. No config, no feature-flag checks, no try/catch needed.
|
||||
|
||||
Reference in New Issue
Block a user