docs: lead README with what the SDK does - #37
Merged
Merged
Conversation
Co-Authored-By: Paul Loeb <ploeb@launchdarkly.com>
Co-Authored-By: Paul Loeb <ploeb@launchdarkly.com>
tracisiebel
approved these changes
Aug 26, 2026
tracisiebel
added a commit
to launchdarkly/python-ai-sdk
that referenced
this pull request
Aug 27, 2026
## Summary Two independent things: a correctness fix to the documented install commands, and the same README restructure as launchdarkly/js-ai-sdk#37. **Install fix (the part that matters)** The documented `pip install launchdarkly-ai-python launchdarkly-ai-openai-messages` installs fine and then fails on the first call: ``` RuntimeError: LaunchDarkly server SDK not installed. Run `pip install launchdarkly-server-sdk` or pass a pre-initialized client. ``` The base Python SDK is an optional peer dependency, not bundled, so both install commands now include `launchdarkly-server-sdk`. The accompanying sentence dropped the false "no extra setup required" claim, and two references to the unpublished `launchdarkly-ai` package name are corrected to `launchdarkly-ai-python` (Quick Start prose and the Core table row). **Copy changes** - Intro rewritten: title → lead paragraph → runnable `openai_messages` snippet → `## What you get` → TOC - `## Repository Layout` moved to the end of `## Development` as `### Repository layout` - `## Package Structure` → `## Packages`, tier sentence no longer leads with "monorepo", `### Handler Packages` → `### Pick your providers` **Follow-up needed (docs site)** The published docs at https://launchdarkly.com/docs/sdk/ai/python still tell people to install `launchdarkly-ai-server` and claim it bundles the base Python SDK, which the package metadata does not support. A docs ticket is needed; Paul is filing it. <details> <summary>Implementation details</summary> Verified in two clean virtualenvs against the published packages (`launchdarkly-ai-python` 0.1.3, `launchdarkly-ai-openai-messages` 0.1.4): - Original command → `await init_client()` raises the `RuntimeError` above. - Corrected command (adds `launchdarkly-server-sdk`, resolved 9.16.1) → `init_client()` returns an `LDClient`, getting past the SDK import (it then logs the expected 401 for the dummy `LD_SDK_KEY`). Also confirmed every TOC anchor resolves after the move, including `#what-you-get`, `#packages`, and `#repository-layout`. </details> Link to Devin session: https://app.devin.ai/sessions/dcb17f68bb444b0da0e445e406d9c37f Requested by: @ld-paul
apucacao
added a commit
that referenced
this pull request
Sep 17, 2026
> [!WARNING] > This content was written by AI. Three carriers describe the same conversation on a span, and `content.ts` says they are written from the same messages so they cannot disagree. They did. The canonical carrier omits an absent tool result, because the key is simply not there. The OpenLLMetry pair and the legacy content events ran the same part through `partToText`, which coerced the missing result to `null` and then serialised it, so both rendered the literal text `null`. That is the pair the LaunchDarkly LLM trace view and conversation view read today. So a tool that returned nothing was displayed to a user as a tool that returned a null value. ## Why it is reachable Every handler builds the part straight from a provider field, and the field is optional: - `claude-messages` and `claude-agents` read `block.content` off an Anthropic `tool_result` block, which may be omitted. - `openai-messages` reads `raw.output`, and `openai-agents` reads `item.output`, off a function call result. A tool that returns nothing is the ordinary case, not a contrived one. ## What changed An absent result now contributes nothing, so it drops out of the flattened text and the flat carriers say what the canonical one already says: there is no result. A result the tool explicitly returned as `null` still renders as `null`, because the canonical carrier keeps `"result": null` for it. Those are two different claims, and only one of them says anything about what the tool returned. ## Verification Three tests. An absent result leaves the transcript empty and agrees with the canonical attribute. An explicit `null` still reports `null`. A falsy result that is not absent survives. I checked both directions by mutation. The first test fails without the fix. The second fails if the fix also swallows an explicit `null`, which is the obvious way to get this wrong. ## Parity The Python SDK is being brought to telemetry parity in `launchdarkly/python-ai-sdk#27` through `#37`, and that stack introduces this same `partToText` flattening to Python for the first time. It carries the matching fix, so neither SDK ships the behaviour. Found by Bugbot, reviewing the Python port. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Fixes a mismatch between **canonical** `gen_ai.*.messages` attributes and the **flat OpenLLMetry** carriers (`gen_ai.prompt/completion.{i}.content`) that LaunchDarkly’s trace view reads. > > `partToText` for `tool_call_response` parts no longer coerces a **missing** `result` to the literal string `null`. **`undefined`** now yields empty text (so the transcript shows no result), while an **explicit** `null` still flattens to `null`, and other falsy values like `0` still serialize correctly. > > Three tests lock in absent vs explicit-null vs falsy behavior and parity with `gen_ai.output.messages`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 29f209c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The README opened with contributor material — a TOC starting at "Repository Layout" and a one-liner describing the repo as "A Node.js monorepo…". It now opens with what a developer gets from the SDK, a minimal
openaiMessagescall, and a "What you get" list; the repository tree moved to the bottom under## Development.## What you get→ TOC## Repository Layoutmoved to the end of## Developmentas### Repository layout## Package Structure→## Packages, tier sentence no longer leads with "monorepo",### Handler Packages→### Pick your providers#### 3f.headings and labelled theresolveGraphsection3e., so those headings are renumbered to3d.and3e.to match the TOCDocs-only; install commands are unchanged here, since
@launchdarkly/ai-nodedeclares@launchdarkly/node-server-sdkas a hard dependency and the documentednpm installgenuinely works. The Python README needed an install fix — see launchdarkly/python-ai-sdk#55.Implementation details
Verified every TOC anchor in the file resolves against a heading after the move (GitHub slug rules: lowercase, strip punctuation, spaces → hyphens), including
#what-you-get,#packages, and#repository-layout.The oddly formatted Quick Start sub-entries (e.g.
- [3b. `config(args)](#3b-configargs)`with the trailing backtick outside the link) are left as-is — the anchors resolve, only the backtick placement is cosmetic.Link to Devin session: https://app.devin.ai/sessions/dcb17f68bb444b0da0e445e406d9c37f
Requested by: @ld-paul