The agent should only make a single call to update the todo list at a
time. A parallel call doesn't make sense, but also cannot work as
there's no obvious reducer to use.
On parallel calls of the todo tool, we return ToolMessage containing to
guide the LLM to not call the tool in parallel.
---------
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Fixes#34517
Supersedes #34557, #34570
Fixes token inflation in `SummarizationMiddleware` that caused context
window overflow during summarization.
**Root cause:** When formatting messages for the summary prompt,
`str(messages)` was implicitly called, which includes all Pydantic
metadata fields (`usage_metadata`, `response_metadata`,
`additional_kwargs`, etc.). This caused the stringified representation
to use ~2.5x more tokens than `count_tokens_approximately` estimates.
**Problem:**
- Summarization triggers at 85% of context window based on
`count_tokens_approximately`
- But `str(messages)` in the prompt uses 2.5x more tokens
- Results in `ContextLengthExceeded`
**Fix:** Use `get_buffer_string()` to format messages, which produces
compact output:
```
Human: What's the weather?
AI: Let me check...[tool_calls]
Tool: 72°F and sunny
```
Instead of verbose Pydantic repr:
```python
[HumanMessage(content='What's the weather?', additional_kwargs={}, response_metadata={}), ...]
```
Addresses a flaky test
When executing `exit 1` as a startup command, the shell process
terminates immediately. The code then tries to write a marker command
(`printf '...'`) to stdin, but the pipe is already broken because the
shell has exited, causing `BrokenPipeError`.
## Summary
Enhances the `init_chat_model` function with comprehensive input
validation, improved model inference patterns, and better error handling
to provide a significantly improved user experience.
## Changes Made
- ✅ **Input Validation**: Added comprehensive type and value checking
for all parameters
- ✅ **Enhanced Model Inference**: Improved pattern matching with
case-insensitive support and new model patterns
- ✅ **Better Error Messages**: Detailed error messages with examples and
documentation links
- ✅ **Comprehensive Tests**: Added extensive test coverage for all new
functionality
- ✅ **Documentation**: Enhanced docstrings and examples
## Backward Compatibility
All changes are fully backward compatible. No breaking changes
introduced.
## Testing
- Added 6 new test functions covering input validation, model inference,
and error handling
- All existing tests continue to pass
- Comprehensive parametrized testing for various model patterns
## User Experience Improvements
- Better error messages help users quickly resolve configuration issues
- Enhanced model inference reduces the need to specify providers
explicitly
- Comprehensive input validation catches issues early with helpful
guidance
---------
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
If the `stdout` "done marker" arrives before the `stderr` output is
enqueued, the method returns early without capturing the `stderr` line.
The two reader threads run independently with no synchronization
guaranteeing `stderr` arrives before the done marker.
In environments with Python 3.10, timing differences can cause the
`stdout` marker to win the race, resulting in `<no output>` instead of
`[stderr]` error.
Observed as a flaky test on `test_stderr_output_labeling` in CI:
```shell
FAILED tests/unit_tests/agents/middleware/implementations/test_shell_tool.py::test_stderr_output_labeling - AssertionError: assert '[stderr] error' in '<no output>'
```
Use of the fixture `_base_vcr_config` is deprecated with alternative
function `base_vcr_config()`
This way:
* we don't need to import `_base_vcr_config` seen as unused (which leads
to ruff violations PLC0414 and F811)
* we don't need to make a copy since a new dict is created at each
function invocation
Co-authored-by: Mason Daugherty <mason@langchain.dev>
With this we get the correct types for `_runnable_support` annotated
functions.
* return list[BaseMessage] when messages is not None
* return Runnable when messages is None
* typing of function args