Skip to content

docs: add Respan observability integration guide#3269

Open
drPod wants to merge 2 commits intoBoundaryML:canaryfrom
drPod:docs/add-respan-integration
Open

docs: add Respan observability integration guide#3269
drPod wants to merge 2 commits intoBoundaryML:canaryfrom
drPod:docs/add-respan-integration

Conversation

@drPod
Copy link

@drPod drPod commented Mar 24, 2026

Summary

  • Adds a new documentation page at fern/01-guide/07-observability/respan.mdx showing how to integrate BAML with Respan, an open-source LLM observability platform
  • Covers three integration approaches with Python and TypeScript examples:
    1. Respan decorators (@workflow/@task) wrapping BAML function calls
    2. on_log_event callback forwarding events to Respan's trace ingestion API
    3. Collector API for rich trace data (tokens, timing, HTTP details) sent to Respan
  • Adds the page to the Observability section in docs navigation (fern/docs.yml)

Test plan

  • fern check --strict-broken-links passes (only pre-existing custom.js error remains)
  • Verify docs preview renders correctly
  • Confirm all internal links resolve (Collector reference link verified)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added guide for integrating Respan observability platform with BAML applications, detailing three integration methods: SDK decorators for workflow spans, tracing callbacks for LLM-call events, and collectors for rich trace data capture. Includes examples and span attribute configuration.

Add a new documentation page showing how to integrate BAML with the
Respan observability platform. Covers three integration approaches:
Respan decorators, on_log_event callback forwarding, and Collector API
with rich trace data. Includes Python and TypeScript examples.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 24, 2026 03:06
@vercel
Copy link

vercel bot commented Mar 24, 2026

@drPod is attempting to deploy a commit to the Boundary Team on Vercel.

A member of the Team first needs to authorize it.

@vercel vercel bot temporarily deployed to Preview – promptfiddle March 24, 2026 03:06 Inactive
@vercel
Copy link

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
promptfiddle Skipped Skipped Mar 24, 2026 3:08am

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

Added a new documentation page introducing Respan integration approaches with BAML, covering three methods: using Respan SDK decorators to create workflow and task spans, forwarding per-LLM-call events via BAML tracing callbacks, and capturing rich trace data via BAML Collector for Respan ingestion. Updated navigation to link to this new guide.

Changes

Cohort / File(s) Summary
Respan Integration Documentation
fern/01-guide/07-observability/respan.mdx, fern/docs.yml
Added new observability guide page documenting three Respan integration approaches with BAML (SDK decorators, tracing callbacks, Collector usage), including Python and TypeScript code examples. Updated navigation YAML to include new page link under Observability section.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely describes the main change: adding documentation for Respan observability integration with BAML.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel vercel bot temporarily deployed to Preview – promptfiddle March 24, 2026 03:08 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 35ea7201-5df8-4b9e-8b1c-5eb29fdbf311

📥 Commits

Reviewing files that changed from the base of the PR and between dddd673 and a9b40c9.

📒 Files selected for processing (2)
  • fern/01-guide/07-observability/respan.mdx
  • fern/docs.yml

Comment on lines +1 to +3
---
title: Respan
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add required subtitle to frontmatter.

This guide starts with frontmatter but omits subtitle, which is required for every .mdx file.

Proposed fix
 ---
 title: Respan
+subtitle: Learn how to integrate BAML with Respan observability
 ---

As per coding guidelines: "Every .mdx file must start with frontmatter containing title and subtitle in the specified format" and "Subtitles should be concise and short, with some starting with 'Learn how to …' for guides".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
title: Respan
---
---
title: Respan
subtitle: Learn how to integrate BAML with Respan observability
---

Comment on lines +7 to +12
There are three ways to integrate BAML with Respan, depending on how much control you need:

1. **Wrap BAML calls with Respan decorators** — easiest, gives you workflow-level traces
2. **Use `on_log_event` to forward events** — real-time event streaming to Respan
3. **Use `Collector` for rich trace data** — most detailed, includes token usage, HTTP requests, and timing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten wording to a neutral technical tone.

Phrases like “easiest,” “most detailed,” and “simplest approach” read promotional. Prefer neutral, factual phrasing.

As per coding guidelines: "Use scientific research tone—professional, factual, and straightforward" and "Do not use marketing/promotional language".

Also applies to: 36-36

Comment on lines +18 to +27
<CodeGroup>
```bash Python
pip install respan-tracing
```

```bash TypeScript
npm install @respan/tracing
```
</CodeGroup>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use CodeBlocks instead of CodeGroup for multi-language snippets.

The page consistently uses CodeGroup, but the docs standard requires CodeBlocks for grouped language examples.

Example migration pattern
-<CodeGroup>
-```python Python
+<CodeBlocks>
+```python
 ...

-typescript TypeScript +typescript
...

-</CodeGroup>
+</CodeBlocks>

As per coding guidelines: "Use CodeBlocks component for groups of code with multiple languages, starting with Python as the default language".

Also applies to: 38-92, 97-187, 192-282

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Observability guide page documenting how to integrate BAML tracing data with the Respan observability platform, and wires it into the docs navigation.

Changes:

  • Added Respan documentation page with 3 integration approaches (decorators, on_log_event, Collector).
  • Updated docs navigation to include the new Respan page under Observability.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
fern/docs.yml Adds the new Respan page to the Observability navigation.
fern/01-guide/07-observability/respan.mdx New integration guide with Python/TypeScript examples and links to relevant Respan/BAML references.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +217 to +218
"input": str(log.raw_llm_response),
"output": str(result),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raw_llm_response is the model’s raw response text, not the request input. Using it as the Respan span input will invert the data in the dashboard. Consider sending the original function args / rendered prompt as input, and raw_llm_response (and/or parsed result) as output or metadata.

Copilot uses AI. Check for mistakes.
Comment on lines +266 to +268
span_name: log.functionName,
input: log.rawLlmResponse,
output: JSON.stringify(result),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: log.rawLlmResponse is the model output, not the input. Mapping it to input will swap request/response in Respan. Prefer using the function args/prompt as input and the raw response / parsed result as output or metadata.

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +131
requests.post(
RESPAN_INGEST_URL,
headers={
"Authorization": f"Bearer {RESPAN_API_KEY}",
"Content-Type": "application/json",
},
json=[
{
"trace_unique_id": event.metadata.root_event_id,
"span_unique_id": event.metadata.event_id,
"span_parent_id": event.metadata.parent_id,
"span_name": "baml_llm_call",
"input": event.prompt,
"output": event.raw_output,
"start_time": event.start_time,
"timestamp": event.start_time,
"metadata": {
"source": "baml",
"parsed_output": event.parsed_output,
},
}
],
)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The on_log_event callback runs synchronously in the tracing pipeline; making a blocking network call (requests.post) here will add latency to every LLM call and can stall the app if the ingest endpoint is slow. Consider enqueueing events to a background worker/batch sender, and at minimum set a short timeout + handle non-2xx responses/exceptions.

Suggested change
requests.post(
RESPAN_INGEST_URL,
headers={
"Authorization": f"Bearer {RESPAN_API_KEY}",
"Content-Type": "application/json",
},
json=[
{
"trace_unique_id": event.metadata.root_event_id,
"span_unique_id": event.metadata.event_id,
"span_parent_id": event.metadata.parent_id,
"span_name": "baml_llm_call",
"input": event.prompt,
"output": event.raw_output,
"start_time": event.start_time,
"timestamp": event.start_time,
"metadata": {
"source": "baml",
"parsed_output": event.parsed_output,
},
}
],
)
try:
response = requests.post(
RESPAN_INGEST_URL,
headers={
"Authorization": f"Bearer {RESPAN_API_KEY}",
"Content-Type": "application/json",
},
json=[
{
"trace_unique_id": event.metadata.root_event_id,
"span_unique_id": event.metadata.event_id,
"span_parent_id": event.metadata.parent_id,
"span_name": "baml_llm_call",
"input": event.prompt,
"output": event.raw_output,
"start_time": event.start_time,
"timestamp": event.start_time,
"metadata": {
"source": "baml",
"parsed_output": event.parsed_output,
},
}
],
timeout=2.0,
)
if not (200 <= response.status_code < 300):
# In a real app, consider using structured logging instead of print
print(
f"Respan ingest returned status {response.status_code}: "
f"{response.text}"
)
except requests.exceptions.RequestException as exc:
# Swallow exceptions to avoid breaking the tracing pipeline
print(f"Error sending event to Respan: {exc}")

Copilot uses AI. Check for mistakes.
Comment on lines +314 to +318
| Approach | Effort | Detail Level | Best For |
|----------|--------|-------------|----------|
| **Respan decorators** | Low | Workflow-level spans | Quick setup, structured traces |
| **`on_log_event`** | Medium | Per-LLM-call events | Real-time streaming, custom filtering |
| **`Collector` + API** | Medium | Full LLM metadata (tokens, HTTP, timing) | Cost tracking, debugging, detailed analytics |
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comparison table is written with double leading pipes (|| ...), which renders as an extra empty column in Markdown. Use a single leading | for the header/separator/rows so the table displays correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +204 to +207
result = await b.ExtractResume(
"John Doe, Software Engineer...",
baml_options={"collector": collector},
)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example uses await at top-level (result = await ...). Top-level await is not valid in normal Python scripts, so readers copying this will get a syntax error. Wrap the snippet in an async def main() + asyncio.run(main()), or remove await and show the synchronous call style used elsewhere in the docs.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +220
span = {
"trace_unique_id": f"baml-{log.id}",
"span_unique_id": log.id,
"span_name": log.function_name,
"input": str(log.raw_llm_response),
"output": str(result),
"start_time": log.timing.start_time.isoformat(),
"latency": log.timing.duration_ms / 1000,
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log.timing.start_time does not exist on the Python Timing object; the public fields are start_time_utc_ms and duration_ms (and duration_ms can be None). Update this snippet to use start_time_utc_ms (convert to ISO-8601 if needed) and handle a missing duration_ms safely.

Suggested change
span = {
"trace_unique_id": f"baml-{log.id}",
"span_unique_id": log.id,
"span_name": log.function_name,
"input": str(log.raw_llm_response),
"output": str(result),
"start_time": log.timing.start_time.isoformat(),
"latency": log.timing.duration_ms / 1000,
from datetime import datetime, timezone
start_time_iso = datetime.fromtimestamp(
log.timing.start_time_utc_ms / 1000.0, tz=timezone.utc
).isoformat()
latency_seconds = (
log.timing.duration_ms / 1000.0 if log.timing.duration_ms is not None else None
)
span = {
"trace_unique_id": f"baml-{log.id}",
"span_unique_id": log.id,
"span_name": log.function_name,
"input": str(log.raw_llm_response),
"output": str(result),
"start_time": start_time_iso,
"latency": latency_seconds,

Copilot uses AI. Check for mistakes.
"output": str(result),
"start_time": log.timing.start_time.isoformat(),
"latency": log.timing.duration_ms / 1000,
"model": log.calls[-1].model if log.calls else None,
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log.calls[-1].model is not a field on the Python collector call objects. Use an available field (e.g. client_name / provider info) or omit model if it can’t be derived reliably from the collector call.

Suggested change
"model": log.calls[-1].model if log.calls else None,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants