Skip to content

chore: Align server-ai examples with EXAM-SDK-example spec#1379

Merged
jsonbailey merged 12 commits into
mainfrom
jb/aic-2383/align-server-ai-examples
May 14, 2026
Merged

chore: Align server-ai examples with EXAM-SDK-example spec#1379
jsonbailey merged 12 commits into
mainfrom
jb/aic-2383/align-server-ai-examples

Conversation

@jsonbailey

@jsonbailey jsonbailey commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Aligns the server-ai examples with the new EXAM-SDK-example spec, mirroring the patterns already landed in hello-python-ai (#27, #28) and improving on Python's config-key/env-var naming.

  • Physical reorganizationexamples/getting-started/{provider}/{method}/ and examples/features/{create-method}/; 10 examples down to 7 (observability examples folded in universally, chat-judge merged into create-model to match Python).
  • Standardized config keys + env varsLAUNCHDARKLY_COMPLETION_KEY/sample-completion, LAUNCHDARKLY_AGENT_KEY/sample-agent, LAUNCHDARKLY_AGENT_GRAPH_KEY/sample-agent-graph, LAUNCHDARKLY_JUDGE_KEY/sample-judge. Cleaner than Python's; will be back-ported in a follow-up hello-python-ai PR.
  • Standardized output — init success line, sample-question framing, metric summary block (Duration, Success, token counts, Tool calls), judge result bullet format. Matches the Python format.
  • Lifecycleawait ldClient.flush(); ldClient.close() in a finally block, everywhere. Several examples weren't flushing or closing before.
  • Observability@launchdarkly/observability-node wired into every example with a unique serviceName. Dedicated observability examples removed since the pattern is now universal.
  • ESM + tsx — uniform module system; no per-example tsc step or dist/ output. Each example has a bootstrap script that builds only the SDK packages it depends on, so users don't need to build the whole monorepo.
  • dotenv + .env.example — every example reads from a local .env and ships a .env.example documenting required vars.
  • READMEs — top-level examples/README.md index with Getting Started / Features tables, and a 4-section per-example README (Prerequisites / Setup / Run, plus an "Adding judges" section on create-model).

No version bumps and no CHANGELOG changes — this is examples-only.

Test plan

  • yarn install at repo root resolves cleanly
  • npx tsc --noEmit passes for all 7 examples
  • getting-started/openai/chat-completions runs end-to-end against an AI Config
  • features/create-model runs end-to-end and prints judge results in the standardized format

Note

Low Risk
Examples-only restructuring plus CI/workspace config updates; main risk is broken example builds/type-checks or CI due to the new workspace names and path globbing.

Overview
Replaces the existing packages/sdk/server-ai/examples/* set with a smaller, reorganized set under examples/getting-started/... and examples/features/..., adding a top-level examples/README.md index and new per-example .env.example/README files.

Updates the example implementations to a consistent pattern: ESM + tsx execution, standardized env var/config key names (e.g. LAUNCHDARKLY_COMPLETION_KEY, LAUNCHDARKLY_AGENT_KEY, etc.), always wiring @launchdarkly/observability-node, printing a uniform metrics/judge-results summary, and ensuring flush()/close() happen in finally.

Adjusts repo plumbing to match: root package.json workspaces now point at the new example packages, and .github/workflows/server-ai.yml replaces per-example build steps with a globbed loop that focuses each example workspace, builds required dependencies, and runs tsc --noEmit.

Reviewed by Cursor Bugbot for commit a82d87c. Bugbot is set up for automated code reviews on this repo. Configure here.

jsonbailey and others added 8 commits May 12, 2026 17:09
Restructure examples to align with the EXAM-SDK-example spec and mirror
the layout in hello-python-ai:
- getting-started/ holds provider examples
- features/ holds managed-API and standalone capability examples

Renames (history preserved via git mv):
- openai → getting-started/openai/chat-completions
- bedrock → getting-started/bedrock/converse
- vercel-ai → getting-started/vercel-ai/generate-text
- managed-agent → features/create-agent
- agent-graph-traversal → features/create-agent-graph
- direct-judge → features/create-judge
- tracked-chat → features/create-model (judge logic from chat-judge will
  be folded in by a follow-up commit)

Removed:
- chat-judge/ (judge support is folded into features/create-model)
- chat-observability/ and openai-observability/ (observability will be
  wired into every remaining example)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Align every server-ai example with the spec contract:
- Switch to cleaner env vars and defaults: LAUNCHDARKLY_COMPLETION_KEY,
  LAUNCHDARKLY_AGENT_KEY, LAUNCHDARKLY_AGENT_GRAPH_KEY, LAUNCHDARKLY_JUDGE_KEY
  with defaults sample-completion / sample-agent / sample-agent-graph /
  sample-judge.
- Use the standard disabled-config error message everywhere a config is
  missing or disabled.
- Use a try/finally with ldClient.flush() + ldClient.close() so events are
  delivered on every exit path.
- Use the spec's question/response framing ("Sending sample question",
  "Waiting for response...", "Model response:") and a single
  "*** SDK successfully initialized" line.
- Fold judge result handling into create-model and create-agent (replaces
  the deleted chat-judge example) using the standardized result bullets.

Diverges from the Python SDK's env var naming intentionally - these clean
names ("completion key", "agent key", etc.) are the new shared standard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…i examples

Every example now wires the LaunchDarkly Observability plugin during SDK
init with a unique service name, replacing the dedicated observability
examples that were removed.

Examples that have a tracker (provider examples and the managed model /
agent examples) print a standardized end-of-run metric summary block
with duration, success, token usage, and tool calls. The block mirrors
the Python reference implementation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Unify the example projects on ESM (type: "module", ESNext modules, ES2022
target) and replace per-example tsc + node invocations with tsx. tsx
executes the TypeScript entry directly, so each example loses its build
script, dist/ output, and tsconfig.eslint.json overlay.

Every example now uses:
- "private": true and an unscoped slug as its name (publishing is never
  intended for examples)
- workspace:^ for all LaunchDarkly packages so local SDK changes are
  picked up automatically
- "bootstrap" script that builds the SDK workspace dependencies before
  the first run
- "start" script that runs the TypeScript source directly via tsx

Drops dotenv and per-example .env.example files; environment variables
are passed in via the shell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a new top-level examples/README.md that indexes every example and
mirrors the Python repo's two-table layout (Getting Started by provider,
Features by managed-API).

Rewrite each per-example README on a consistent four-section template
(Title, Prerequisites, Setup, Run) so customers can scan any example
the same way. The create-model README also documents how to enable
judges via the AI Config UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "yarn workspaces foreach -R --from ..." form expanded to no targets
in this monorepo (no error, just exited "Done in 0s"). Add the -A flag
so foreach considers all workspaces, and start the recursive build from
each example's own slug plus @launchdarkly/node-server-sdk-otel so the
example's local workspace deps (and the otel package that observability-
node loads at runtime) are all built before "yarn start" runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous map filter ('item.role !== "system"') didn't narrow the
type of role for the consumer, so the Message[] cast failed under
"strict": true. Use a typed type guard so the system role is removed
both at runtime and at the type level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
External users following these examples will reach for .env files
rather than exporting variables in their shell, and the Python SDK's
examples all use python-dotenv -- this aligns the JS examples with
the same UX.

For every example:
- Add dotenv to dependencies.
- Import 'dotenv/config' as the first import in src/index.ts so values
  from a local .env are loaded before any environment lookups.
- Add a .env.example listing only the env vars that example actually
  reads, with empty placeholders and a brief comment per var.
- Update the per-example README's Setup step to point at .env instead
  of exporting variables on the command line.

.env (without the .example suffix) is already covered by the repo's
top-level .gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 26208 bytes
Compressed size limit: 29000
Uncompressed size: 128789 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 179498 bytes
Compressed size limit: 200000
Uncompressed size: 830837 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 31906 bytes
Compressed size limit: 34000
Uncompressed size: 113658 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 38487 bytes
Compressed size limit: 39000
Uncompressed size: 211236 bytes

@jsonbailey jsonbailey force-pushed the jb/aic-2383/align-server-ai-examples branch from f94b0a9 to 6f0cf2e Compare May 13, 2026 16:59
…ples

The three "Build <provider> example" steps referenced the old
@launchdarkly/hello-* workspace names and called lint + build scripts
that no longer exist on the examples (we stripped them when migrating
to tsx). Replace them with a single step that iterates every example
under getting-started/ and features/, focuses its workspace deps,
builds them, then runs `npx tsc --noEmit`.

The build invocation mirrors the bootstrap script in each example's
package.json: it co-builds @launchdarkly/node-server-sdk-otel because
observability-node depends on it but it isn't transitively reachable
from any example workspace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jsonbailey jsonbailey marked this pull request as ready for review May 13, 2026 17:43
@jsonbailey jsonbailey requested a review from a team as a code owner May 13, 2026 17:43
Comment thread packages/sdk/server-ai/examples/features/create-judge/src/index.ts

@andrewklatzke andrewklatzke left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit that may not be valid in these examples but LGTM

jsonbailey and others added 3 commits May 13, 2026 13:30
… example env files

Optional LaunchDarkly config-key env vars previously shipped blank in the
`.env.example` files, with a "# Optional - defaults to X" comment. After
`cp .env.example .env` and dotenv loading, those vars are present in
`process.env` as the empty string. The `||` fallback in the source masks
this today, but it's a footgun.

Set each optional LD config-key to the same default the source uses so
the example file is usable as-is once SDK and provider keys are filled
in. Same treatment for AWS_DEFAULT_REGION in the bedrock example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…amples

Provider error responses can echo back credentials (OpenAI has been
known to include the API key in the body of some error responses).
The examples keep their raw `console.error('Error:', err)` so users
can diagnose what went wrong without modifying code, but a short
comment above each catch block tells anyone copying this pattern into
production code to sanitize errors first.

Applied to every example's top-level catch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collapse the three-line caveat above each catch block into a single
line, and move it inside the catch directly above `console.error`,
where it sits next to the line a reader is actually copying.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jsonbailey jsonbailey merged commit 6d120af into main May 14, 2026
43 checks passed
@jsonbailey jsonbailey deleted the jb/aic-2383/align-server-ai-examples branch May 14, 2026 13:41
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.

3 participants