Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions examples/langchain_thinking.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""
Example: langchain_messages() against a Claude model with extended thinking turned on.

With thinking on, Anthropic returns ``content`` as a list of blocks — a ``thinking`` block followed
by a ``text`` block — instead of a plain string. A handler that only reads string content reports
an empty response for these runs while the tokens are still spent, so this example fails loudly
when no text comes back.
Point this at a flag whose ``model.parameters`` enable thinking (and whose ``max_tokens``
exceeds the thinking budget). Anthropic then returns ``content`` as a list of blocks — a
``thinking`` block followed by a ``text`` block — instead of a plain string. A handler that
only reads string content reports an empty response for these runs while the tokens are still
spent, so this example fails loudly when no text comes back.

Anthropic omits thinking from the turn that follows a tool result, so give this a prompt the model
can answer on its own — a run that goes through the tool loop ends on a plain string and never
Expand All @@ -28,26 +29,16 @@
from launchdarkly_ai_langchain_messages import create_langchain_messages_handler
from launchdarkly_ai_server import config

# Anthropic requires max_tokens to exceed the thinking budget.
_THINKING_BUDGET_TOKENS = 1024
_MAX_TOKENS = 4096


async def run(key: str, user_input: str) -> None:
from langchain_anthropic import ChatAnthropic

def build_model(ai_config: Any) -> Any:
model = ai_config.get("model") or {}
raw = model.get("parameters")
parameters: dict[str, Any] = dict(raw) if isinstance(raw, dict) else {}
return ChatAnthropic(
timeout=None,
stop=None,
**parameters,
model_name=str(model.get("name") or "claude-sonnet-4-5"),
thinking={"type": "enabled", "budget_tokens": _THINKING_BUDGET_TOKENS},
max_tokens_to_sample=_MAX_TOKENS,
)
kwargs: dict[str, Any] = dict(raw) if isinstance(raw, dict) else {}
kwargs["model"] = str(model.get("name") or "claude-sonnet-4-5")
return ChatAnthropic(**kwargs)

response = await config(
key=key,
Expand Down
6 changes: 4 additions & 2 deletions packages/langchain-agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ be built after evaluation:
```python
handler = create_langchain_agents_handler(
lambda config: ChatAnthropic(
model=config["model"]["name"],
**(config["model"].get("parameters") or {}),
**{
**(config["model"].get("parameters") or {}),
"model": config["model"]["name"],
}
)
)
```
Expand Down
6 changes: 4 additions & 2 deletions packages/langchain-messages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ be built after evaluation:
```python
handler = create_langchain_messages_handler(
lambda config: ChatAnthropic(
model=config["model"]["name"],
**(config["model"].get("parameters") or {}),
**{
**(config["model"].get("parameters") or {}),
"model": config["model"]["name"],
}
)
)
```
Expand Down
16 changes: 8 additions & 8 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading