Skip to content

docs: lead README with what the SDK does - #37

Merged
tracisiebel merged 2 commits into
mainfrom
devin/1787778716-readme-lead-with-sdk
Aug 27, 2026
Merged

tracisiebel merged 2 commits into
mainfrom
devin/1787778716-readme-lead-with-sdk

Conversation

@ld-paul

@ld-paul ld-paul commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

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 openaiMessages call, and a "What you get" list; the repository tree moved to the bottom under ## Development.

  • Intro rewritten: title → lead paragraph → runnable 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
  • Fixed two broken TOC anchors: the body had two #### 3f. headings and labelled the resolveGraph section 3e., so those headings are renumbered to 3d. and 3e. to match the TOC

Docs-only; install commands are unchanged here, since @launchdarkly/ai-node declares @launchdarkly/node-server-sdk as a hard dependency and the documented npm install genuinely 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

devin-ai-integration Bot and others added 2 commits August 26, 2026 21:11
Co-Authored-By: Paul Loeb <ploeb@launchdarkly.com>
Co-Authored-By: Paul Loeb <ploeb@launchdarkly.com>
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
@tracisiebel
tracisiebel merged commit 19816c7 into main Aug 27, 2026
8 checks passed
@tracisiebel
tracisiebel deleted the devin/1787778716-readme-lead-with-sdk branch August 27, 2026 03:49
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 -->
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