Add LaunchDarkly AI Configs integration sample for Strands#264
Open
sattensil wants to merge 4 commits into
Open
Add LaunchDarkly AI Configs integration sample for Strands#264sattensil wants to merge 4 commits into
sattensil wants to merge 4 commits into
Conversation
A new sample under python/03-integrate/runtime-control/launchdarkly demonstrating how to drive a Strands agent entirely from LaunchDarkly AI Configs: model, instructions, parameters, tool list, and multi-agent graph topology all live in LaunchDarkly. Provider, tools, and graph shape can be changed from the LaunchDarkly UI with no code change. The notebook is self-contained: it creates the LaunchDarkly project, two AI Configs (triage + specialist), three triage variations (OpenAI gpt-5, Anthropic Claude Sonnet 4.6, Bedrock Claude Sonnet 4.6), a governed get_order_status tool attached per-variation, default targeting, and an Agent Graph wiring triage -> specialist with handoff metadata. Highlights: - create_strands_model maps an AIAgentConfig to the matching Strands model class (OpenAIModel / AnthropicModel / BedrockModel) by reading config.provider.name with a Bedrock model-id fallback. - The agent's tool list comes from config.model.parameters['tools'], resolved against a local TOOL_REGISTRY at runtime. Detach a tool in the LaunchDarkly UI and the next invocation has no tools. - Per-config tracking via config.create_tracker().track_metrics_of_async + an LDAIMetrics extractor fires duration / success / tokens atomically for async Strands invocations; tool-call counts come from the @tool body. - execute_graph walks node.get_edges() at runtime, builds a Strands Agent per node generically from node.get_config(), and routes between agents based on edge.handoff.route values that the LLM selects from the valid set. Graph-level handoff success/failure + final path are tracked via graph.create_tracker(). - The routing protocol (JSON envelope, when to hand off) lives in each AI Config's instructions field in LaunchDarkly; the builder only injects the runtime list of available routes derived from edges. - Section 9 demos both branches: a status-only query terminates at the triage agent; an analysis query hands off to the specialist. Adding a node + edge in the LaunchDarkly UI changes which agents fire on the next run with no code change — GRAPH_KEY is the only key the dispatcher hardcodes.
If a prior cleanup cell closed the LDClient, re-running section 7 or section 9 alone evaluated against a closed client and got stale 'last known values' from the in-memory feature store — new nodes added in the LD UI weren't visible because the cache predated them. Both run_turn and execute_graph now check ldclient.get().is_initialized() at entry. If not, they reinit via ldclient.set_config + rebuild the LDAIClient/agent_config wrappers. Once initialized, the SDK streaming connection keeps state live within ~1s of UI changes.
Two bugs kept the LDClient stuck on stale state across re-runs: 1. is_initialized() is a one-way latch — it stays True after close(), so the prior self-heal check skipped reinit and agent_graph served from the in-memory snapshot frozen at close() time. 2. The cleanup cell called close() at all. flush() is enough; kernel shutdown handles connection release. Fix: - Drop close() from the cleanup cell. - Harden self-heal in run_turn + execute_graph to also probe the private _closed flag.
Brief operational tip pointing users at the self-heal behavior and the 'Restart Kernel + Run All' fallback after editing the graph in the LD UI.
3 tasks
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
Adds a new sample under
python/03-integrate/runtime-control/launchdarklythat drives a Strands agent entirely from LaunchDarkly AI Configs: model, instructions, parameters, tool list, and the multi-agent graph topology all live in LaunchDarkly.The notebook is self-contained — it creates the project, AI Configs, variations, governed tool, default targeting, and an Agent Graph via the LaunchDarkly API on first run; re-running is idempotent.
Highlights:
create_strands_modelmaps anAIAgentConfigto the right Strands model class (OpenAIModel/AnthropicModel/BedrockModel) by readingconfig.provider.namewith a Bedrock model-id fallback — no per-provider branching in the sample.gpt-5, Anthropic Claude Sonnet 4.6, Bedrock Claude Sonnet 4.6) demonstrate provider swap via the LaunchDarkly UI.config.model.parameters['tools'], resolved at runtime against a localTOOL_REGISTRY. Detaching a tool in LaunchDarkly takes effect on the next invocation with no code change.tracker.track_metrics_of_async+ anLDAIMetricsextractor fires duration / success / tokens atomically for async Strands invocations;track_tool_callfires from the@toolbody.execute_graphwalksnode.get_edges()at runtime, builds a StrandsAgentgenerically per node fromnode.get_config(), and routes between agents based onedge.handoff.routevalues the LLM emits. Graph-level handoff success/failure + the final path are tracked viagraph.create_tracker().instructionsin LaunchDarkly; the builder only injects the runtime route list from edges. Adding a node + edge in the LaunchDarkly UI changes which agents fire on the next run.strands-specialist-agent.Test plan
pip install -r python/03-integrate/runtime-control/launchdarkly/requirements.txt.envwithLAUNCHDARKLY_API_TOKEN,OPENAI_API_KEY,ANTHROPIC_API_KEY(per README)strands-agentbetweengpt-5-agent,claude-sonnet-agent,bedrock-claude-agentin the LaunchDarkly UI and re-run section 9 — same code, different provider