Skip to content

Commit c17ac2d

Browse files
jsonbaileyclaude
andcommitted
feat!: Make AI config factory methods synchronous
The create_model, create_agent, and create_agent_graph methods on LDAIClient performed no async work — they only invoked sync helpers (_client.track, _completion_config, RunnerFactory.create_*, and the Managed* constructors). Marking them async forced callers into needless coroutine plumbing. Convert the three factories to plain def. Update docstring examples and provider READMEs to drop the now-incorrect await on the factory call (run() on the returned Managed* is still async). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a3ac7a1 commit c17ac2d

6 files changed

Lines changed: 24 additions & 27 deletions

File tree

packages/ai-providers/server-ai-langchain/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ context = Context.builder("user-123").build()
4848

4949
async def main():
5050
# Create a ManagedModel backed by the LangChain provider
51-
model = await ai_client.create_model(
51+
model = ai_client.create_model(
5252
"ai-config-key",
5353
context,
5454
AICompletionConfigDefault(
@@ -74,7 +74,7 @@ LaunchDarkly AI config flag, selects the LangChain runner automatically, and
7474
returns a `ManagedModel` that wraps the runner:
7575

7676
```python
77-
model = await ai_client.create_model("ai-config-key", context)
77+
model = ai_client.create_model("ai-config-key", context)
7878

7979
if model:
8080
result = await model.run("What is feature flagging?")
@@ -121,7 +121,7 @@ print(result.parsed) # {"sentiment": "positive", "confidence": 0.95}
121121
`LDAIConfigTracker`. For manual tracking, use the tracker directly:
122122

123123
```python
124-
model = await ai_client.create_model("ai-config-key", context)
124+
model = ai_client.create_model("ai-config-key", context)
125125

126126
if model:
127127
result = await model.run("Explain feature flags.")

packages/ai-providers/server-ai-openai/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ context = Context.builder("user-123").build()
3535

3636
async def main():
3737
# Create a ManagedModel backed by the OpenAI provider
38-
model = await ai_client.create_model(
38+
model = ai_client.create_model(
3939
"ai-config-key",
4040
context,
4141
AICompletionConfigDefault(
@@ -61,7 +61,7 @@ LaunchDarkly AI config flag, selects the OpenAI runner automatically, and
6161
returns a `ManagedModel` that wraps the runner:
6262

6363
```python
64-
model = await ai_client.create_model("ai-config-key", context)
64+
model = ai_client.create_model("ai-config-key", context)
6565

6666
if model:
6767
result = await model.run("What is feature flagging?")
@@ -107,7 +107,7 @@ print(result.parsed) # {"sentiment": "positive", "confidence": 0.95}
107107
`LDAIConfigTracker`. For manual tracking, use the tracker directly:
108108

109109
```python
110-
model = await ai_client.create_model("ai-config-key", context)
110+
model = ai_client.create_model("ai-config-key", context)
111111

112112
if model:
113113
result = await model.run("Explain feature flags.")

packages/sdk/server-ai/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ from ldai import LDAIClient, AICompletionConfigDefault, ModelConfig, LDMessage
115115
# Use the same default_config from the retrieval section above
116116
async def main():
117117
context = Context.create("user-123")
118-
model = await ai_client.create_model(
118+
model = ai_client.create_model(
119119
'customer-support-chat',
120120
context,
121121
default_config,

packages/sdk/server-ai/src/ldai/client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def _build_evaluator(
383383
judge_instances.append(judge)
384384
return Evaluator(judge_instances)
385385

386-
async def create_model(
386+
def create_model(
387387
self,
388388
key: str,
389389
context: Context,
@@ -404,7 +404,7 @@ async def create_model(
404404
405405
Example::
406406
407-
model = await client.create_model(
407+
model = client.create_model(
408408
"customer-support-chat",
409409
context,
410410
AICompletionConfigDefault(
@@ -435,7 +435,7 @@ async def create_model(
435435

436436
return ManagedModel(config, runner)
437437

438-
async def create_agent(
438+
def create_agent(
439439
self,
440440
key: str,
441441
context: Context,
@@ -463,7 +463,7 @@ async def create_agent(
463463
464464
Example::
465465
466-
agent = await client.create_agent(
466+
agent = client.create_agent(
467467
"customer-support-agent",
468468
context,
469469
tools={"get-order": fetch_order_fn},
@@ -722,7 +722,7 @@ def graph_tracker_factory() -> AIGraphTracker:
722722
create_tracker=graph_tracker_factory,
723723
)
724724

725-
async def create_agent_graph(
725+
def create_agent_graph(
726726
self,
727727
key: str,
728728
context: Context,
@@ -748,7 +748,7 @@ async def create_agent_graph(
748748
749749
Example::
750750
751-
graph = await client.create_agent_graph(
751+
graph = client.create_agent_graph(
752752
"travel-assistant-graph",
753753
context,
754754
tools={

packages/sdk/server-ai/tests/test_managed_agent.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -310,30 +310,27 @@ async def _evaluate_coro(input_text: str, output_text: str) -> List[JudgeResult]
310310
class TestLDAIClientCreateAgent:
311311
"""Tests for LDAIClient.create_agent."""
312312

313-
@pytest.mark.asyncio
314-
async def test_returns_none_when_agent_is_disabled(self, ldai_client: LDAIClient):
313+
def test_returns_none_when_agent_is_disabled(self, ldai_client: LDAIClient):
315314
"""Should return None when agent config is disabled."""
316315
context = Context.create('user-key')
317-
result = await ldai_client.create_agent('disabled-agent', context)
316+
result = ldai_client.create_agent('disabled-agent', context)
318317

319318
assert result is None
320319

321-
@pytest.mark.asyncio
322-
async def test_returns_none_when_provider_unavailable(self, ldai_client: LDAIClient):
320+
def test_returns_none_when_provider_unavailable(self, ldai_client: LDAIClient):
323321
"""Should return None when no AI provider is available."""
324322
import ldai.providers.runner_factory as rf
325323
context = Context.create('user-key')
326324

327325
original = rf.RunnerFactory.create_agent
328326
rf.RunnerFactory.create_agent = MagicMock(return_value=None)
329327
try:
330-
result = await ldai_client.create_agent('customer-support-agent', context)
328+
result = ldai_client.create_agent('customer-support-agent', context)
331329
assert result is None
332330
finally:
333331
rf.RunnerFactory.create_agent = original
334332

335-
@pytest.mark.asyncio
336-
async def test_returns_managed_agent_when_runner_available(self, ldai_client: LDAIClient):
333+
def test_returns_managed_agent_when_runner_available(self, ldai_client: LDAIClient):
337334
"""Should return ManagedAgent when runner is successfully created."""
338335
import ldai.providers.runner_factory as rf
339336
context = Context.create('user-key')
@@ -346,7 +343,7 @@ async def test_returns_managed_agent_when_runner_available(self, ldai_client: LD
346343
original = rf.RunnerFactory.create_agent
347344
rf.RunnerFactory.create_agent = MagicMock(return_value=mock_runner)
348345
try:
349-
result = await ldai_client.create_agent('customer-support-agent', context)
346+
result = ldai_client.create_agent('customer-support-agent', context)
350347
assert isinstance(result, ManagedAgent)
351348
assert result.get_agent_runner() is mock_runner
352349
finally:

packages/sdk/server-ai/tests/test_managed_agent_graph.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ async def test_create_agent_graph_returns_managed_agent_graph(ldai_client: LDAIC
303303
'ldai.providers.runner_factory.RunnerFactory.create_agent_graph',
304304
new=MagicMock(return_value=stub_runner),
305305
):
306-
managed = await ldai_client.create_agent_graph('travel-graph', context)
306+
managed = ldai_client.create_agent_graph('travel-graph', context)
307307

308308
assert managed is not None
309309
assert isinstance(managed, ManagedAgentGraph)
@@ -313,7 +313,7 @@ async def test_create_agent_graph_returns_managed_agent_graph(ldai_client: LDAIC
313313
@pytest.mark.asyncio
314314
async def test_create_agent_graph_returns_none_when_disabled(ldai_client: LDAIClient):
315315
context = Context.create('user-key')
316-
managed = await ldai_client.create_agent_graph('disabled-graph', context)
316+
managed = ldai_client.create_agent_graph('disabled-graph', context)
317317
assert managed is None
318318

319319

@@ -325,7 +325,7 @@ async def test_create_agent_graph_returns_none_when_runner_factory_fails(ldai_cl
325325
'ldai.providers.runner_factory.RunnerFactory.create_agent_graph',
326326
new=MagicMock(return_value=None),
327327
):
328-
managed = await ldai_client.create_agent_graph('travel-graph', context)
328+
managed = ldai_client.create_agent_graph('travel-graph', context)
329329

330330
assert managed is None
331331

@@ -344,7 +344,7 @@ def fake_create_agent_graph(graph_def, tools_arg, default_ai_provider=None):
344344
'ldai.providers.runner_factory.RunnerFactory.create_agent_graph',
345345
new=fake_create_agent_graph,
346346
):
347-
await ldai_client.create_agent_graph('travel-graph', context, tools=tools)
347+
ldai_client.create_agent_graph('travel-graph', context, tools=tools)
348348

349349
assert captured['tools'] is tools
350350

@@ -357,7 +357,7 @@ async def test_create_agent_graph_run_produces_result(ldai_client: LDAIClient):
357357
'ldai.providers.runner_factory.RunnerFactory.create_agent_graph',
358358
new=MagicMock(return_value=StubAgentGraphRunner("final answer")),
359359
):
360-
managed = await ldai_client.create_agent_graph('travel-graph', context)
360+
managed = ldai_client.create_agent_graph('travel-graph', context)
361361

362362
assert managed is not None
363363
result = await managed.run("find restaurants")

0 commit comments

Comments
 (0)