# LD imports
from ldai_optimization import (
OptimizationClient,
OptimizationOptions,
OptimizationJudge,
OptimizationResponse,
LLMCallConfig,
LLMCallContext,
)
from ldai import LDAIClient
from ldai.tracker import TokenUsage
from ldclient import Context
# anthropic imports
from claude_agent_sdk import query, ClaudeAgentOptions
from claude_agent_sdk.types import ResultMessage
acceptance_statement_prompt = """\
The orchestrator should appropriately fetch the user preferences and \
route to the correct sub-agent, \
carrying through any relevant information from the users' query.
The orchestrator should not provide any answers itself, \
just pass to the correct sub-agent.
Inability to fetch user preferences or mentions of missing data should \
be automatic failures.
If preferences are not included, that should be an automatic failure.
If the orchestrator does not mention the sub-agent it will hand off to, \
that is an automatic failure."""
default_fallback_model = "claude-opus-4-5-20251101"
async def handle_agent_call(
key: str,
config: LLMCallConfig,
context: LLMCallContext,
is_evaluation: bool = False,
) -> OptimizationResponse:
model = config.model.name if config.model else default_fallback_model
final_message = None
async for message in query(
prompt=context.user_input or "",
options=ClaudeAgentOptions(
system_prompt=config.instructions or "",
model=model,
),
):
final_message = message
if not isinstance(final_message, ResultMessage):
raise ValueError(f"Unexpected final message type: {type(final_message)}")
u = final_message.usage or {}
input_tokens = u.get("input_tokens", 0)
output_tokens = u.get("output_tokens", 0)
return OptimizationResponse(
output=final_message.result or "",
usage=TokenUsage(
total=input_tokens + output_tokens,
input=input_tokens,
output=output_tokens,
),
)
options = OptimizationOptions(
judges={
"acceptance": OptimizationJudge(
acceptance_statement=acceptance_statement_prompt,
threshold=0.95,
),
"accuracy": OptimizationJudge(
judge_key="my-accuracy-judge",
threshold=0.8,
),
},
context_choices=[
Context.builder("user-123").set("user_id", "user-123").build(),
],
max_attempts=25,
model_choices=["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5"],
judge_model="claude-haiku-4-5",
variable_choices=[
{
"user_id": "user-123",
"trip_purpose": "business",
},
{
"user_id": "user-125",
"trip_purpose": "personal",
},
],
user_input_options=[
"I'm going to tokyo next week, where should I stay near Shinjuku?",
"where to eat in anchorage",
"airbnbs near tahoe",
"what are some food options in sf near the airport"
],
handle_agent_call=handle_agent_call,
handle_judge_call=handle_agent_call,
)
client = OptimizationClient(ld_ai_client)
result = await client.optimize_from_options("travel-agent-orchestrator", options)