diff --git a/sdk/guides/agent-server/openai-gateway.mdx b/sdk/guides/agent-server/openai-gateway.mdx index d72f4380..7e7477f7 100644 --- a/sdk/guides/agent-server/openai-gateway.mdx +++ b/sdk/guides/agent-server/openai-gateway.mdx @@ -26,6 +26,18 @@ The gateway accepts the same session key in either OpenHands or OpenAI-compatibl - `X-Session-API-Key: ` - `Authorization: Bearer ` +OpenAI-compatible requests can also pass observability overrides for a new OpenHands conversation created behind the request: + + +Observability override headers are available in OpenHands agent-server `v1.30.0` and later. + + +- `X-OpenHands-Observability-Span-Name`: stable child span name to emit under the `conversation` root span +- `X-OpenHands-Observability-Tags`: comma-separated span tags +- `X-OpenHands-Observability-Metadata`: JSON object attached as trace metadata + +Use `X-OpenHands-Observability-Span-Name` when an observability backend, such as Laminar signals, should route or classify traces by a specific span name. The root span remains named `conversation`. + ## Prepare a Profile OpenAI-compatible traffic is backed by an agent-server LLM profile. Create one with the native profile API first: @@ -64,6 +76,9 @@ curl "$AGENT_SERVER_URL/v1/models" \ curl -i "$AGENT_SERVER_URL/v1/chat/completions" \ -H "Authorization: Bearer $SESSION_API_KEY" \ -H "Content-Type: application/json" \ + -H "X-OpenHands-Observability-Span-Name: pr_review_evaluation" \ + -H "X-OpenHands-Observability-Tags: pr-review,evaluation" \ + -H 'X-OpenHands-Observability-Metadata: {"repo":"OpenHands/software-agent-sdk"}' \ -d "{ \"model\": \"$OPENHANDS_MODEL\", \"messages\": [ @@ -99,6 +114,11 @@ response = client.chat.completions.with_raw_response.create( messages=[ {"role": "user", "content": "Summarize this repository."}, ], + extra_headers={ + "X-OpenHands-Observability-Span-Name": "repo_summary", + "X-OpenHands-Observability-Tags": "repo-summary,docs", + "X-OpenHands-Observability-Metadata": '{"source":"docs-example"}', + }, ) completion = response.parse() conversation_id = response.headers["X-OpenHands-ServerConversation-ID"] diff --git a/sdk/guides/observability.mdx b/sdk/guides/observability.mdx index 3386e55e..4b0afa12 100644 --- a/sdk/guides/observability.mdx +++ b/sdk/guides/observability.mdx @@ -140,6 +140,31 @@ Each conversation gets its own session ID (the conversation UUID), allowing you In `tool.execute`, the tool calls are traced individually, such as `bash`, `file_editor`, or `task_tracker`. +### Named Child Spans for Signals + + +`observability_span_name` is available in OpenHands SDK `v1.30.0` and later. + + +By default, each conversation trace starts with a root span named `conversation`. Keep that root span name stable for trace grouping. When you need an observability backend to route or classify a run by span name, set `observability_span_name` on the conversation. The SDK emits that value as an immediate child span under the `conversation` root. + +This is useful for Laminar signals or other backend rules that match a specific span name: + +```python icon="python" wrap +conversation = Conversation( + agent=agent, + workspace=".", + observability_span_name="pr_review_evaluation", + observability_tags=["pr-review", "evaluation"], + observability_metadata={ + "repo": "OpenHands/software-agent-sdk", + "workflow": "nightly-eval", + }, +) +``` + +Use stable, low-cardinality names such as `pr_review_evaluation`, `support_triage`, or `release_note_check`. Span names must be non-empty strings up to 128 characters and may contain letters, numbers, dots, underscores, colons, slashes, and hyphens. + ## Configuration Reference ### Environment Variables