InjectedToolCallId Injection Fails When LLM Generates Parameter

### Checked other resources

- [x] This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
- [x] I added a clear and descriptive title that summarizes this issue.
- [x] I used the GitHub search to find a similar question and didn't find it.
- [x] I am sure that this is a bug in LangChain rather than my code.
- [x] The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
- [x] I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
- [x] I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.


# BUG REPORT: InjectedToolCallId Injection Fails When LLM Generates Parameter

## Issue Summary
When an LLM generates a parameter that should be automatically injected by LangChain (marked with `InjectedToolCallId`), the injection mechanism fails. The tool receives the LLM-generated value instead of the real tool call ID.

## Root Cause
In `langchain_core/tools/base.py` [around line 660](https://github.com/langchain-ai/langchain/blob/ec2b34a02ddf3b6ac7a9ce4b632d3c7b2d61657c/libs/core/langchain_core/tools/base.py#L660), the injection logic checks:
```python
# Current buggy code in LangChain
for k, v in get_all_basemodel_annotations(input_args).items():
    if (
        _is_injected_arg_type(v, injected_type=InjectedToolCallId)
        and k not in tool_input  # ❌ BUG: Only inject if not already present
    ):
        tool_input[k] = self.handle_tool_error(
            get_function_first_arg_dict_keys(self.func, input_args)[k]
        )
```
When an LLM generates the parameter (often because it's mentioned in docstrings), it's already in `tool_input`, so the condition `k not in tool_input` is false and the real value doesn't get injected.

## Expected Behavior
- Tool should always receive the actual tool call ID from the `ToolCall.id` field
- The `InjectedToolCallId` annotation should override any LLM-generated values

## Actual Behavior
- Tool receives the LLM-generated fake ID instead of the real tool call ID
- Breaks tool functionality that depends on correct tool call tracking

## Reproduction Test Case

```python
"""
Simple test to reproduce the InjectedToolCallId bug from LangChain issue #32729.
"""

from typing import Annotated
from langchain_core.tools import InjectedToolCallId, tool


@tool
def simple_tool(
    user_input: str,
    current_tool_call_id: Annotated[str, InjectedToolCallId],
) -> str:
    """Simple tool that returns the injected tool call ID."""
    return current_tool_call_id


def test_normal_case_injection_works():
    """Test normal case: LLM doesn't generate the injected parameter."""
    tool_call = {
        "name": "simple_tool",
        "args": {"user_input": "test"},
        "id": "real_id_123",
        "type": "tool_call",
    }

    result = simple_tool.invoke(tool_call)
    assert result.content == "real_id_123"  # ✅ This passes


def test_bug_case_injection_fails():
    """Test bug case: LLM generates the injected parameter."""
    tool_call = {
        "name": "simple_tool",
        "args": {
            "user_input": "test",
            "current_tool_call_id": "fake_llm_id"  # LLM generated this
        },
        "id": "real_id_456",  # This should be used instead
        "type": "tool_call",
    }

    result = simple_tool.invoke(tool_call)
    assert result.content == "real_id_456"  # ❌ This fails with the bug
```

## Test Results
When running the bug reproduction test, you get:
```
AssertionError: assert 'fake_llm_id' == 'real_id_456'
  - real_id_456    (expected: real tool call ID)
  + fake_llm_id    (actual: LLM-generated fake ID)
```

This clearly shows:
- **Expected**: `real_id_456` (the actual tool call ID from `ToolCall.id`)
- **Actual**: `fake_llm_id` (the LLM-generated fake ID that was used instead)

## Impact
- Tools cannot reliably track their execution context
- ToolMessage responses have incorrect tool_call_id values
- Breaks tool chaining and state management
- Makes it impossible to correlate tool calls with their responses

## When This Happens
This bug occurs when:
1. A tool parameter is annotated with `InjectedToolCallId`
2. **The parameter name appears in the tool's docstring**
3. An LLM sees the parameter and includes it in the tool call arguments (despite the bound schema)
4. LangChain skips injection because the parameter is "already provided"

## Suggested Fix
The injection logic should always override user-provided values for injected parameters, not skip injection when the parameter is already present.

Change from:
```python
# Current buggy code
for k, v in get_all_basemodel_annotations(input_args).items():
    if (
        _is_injected_arg_type(v, injected_type=InjectedToolCallId)
        and k not in tool_input  # ❌ BUG: Skip if already present
    ):
        tool_input[k] = self.handle_tool_error(
            get_function_first_arg_dict_keys(self.func, input_args)[k]
        )
```

To:
```python
# Fixed code - always inject
for k, v in get_all_basemodel_annotations(input_args).items():
    if _is_injected_arg_type(v, injected_type=InjectedToolCallId):
        # ✅ Always inject, override any LLM-provided value
        tool_input[k] = self.handle_tool_error(
            get_function_first_arg_dict_keys(self.func, input_args)[k]
        )
```

## Reference
- [Source code](https://github.com/langchain-ai/langchain/blob/ec2b34a02ddf3b6ac7a9ce4b632d3c7b2d61657c/libs/core/langchain_core/tools/base.py#L660): `libs/core/langchain_core/tools/base.py` line ~660


### Error Message and Stack Trace (if applicable)

_No response_

### Description

This bug occurs when:
1. A tool parameter is annotated with `InjectedToolCallId`
2. The parameter name appears in the tool's docstring or schema
3. An LLM sees the parameter and includes it in the tool call arguments (despite the bound schema)
4. LangChain skips injection because the parameter is "already provided"

### System Info


System Information
------------------
> OS:  Darwin
> OS Version:  Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
> Python Version:  3.12.9 (main, Mar 17 2025, 21:36:21) [Clang 20.1.0 ]

Package Information
-------------------
> langchain_core: 0.3.68
> langchain: 0.3.26
> langchain_community: 0.3.27
> langsmith: 0.4.5
> langchain_anthropic: 0.3.17
> langchain_cohere: 0.4.4
> langchain_openai: 0.3.28
> langchain_text_splitters: 0.3.8
> langgraph_sdk: 0.2.3

Optional packages not installed
-------------------------------
> langserve

Other Dependencies
------------------
> aiohttp<4.0.0,>=3.8.3: Installed. No version info available.
> anthropic<1,>=0.57.0: Installed. No version info available.
> async-timeout<5.0.0,>=4.0.0;: Installed. No version info available.
> cohere: 5.16.1
> dataclasses-json<0.7,>=0.5.7: Installed. No version info available.
> httpx: 0.28.1
> httpx-sse<1.0.0,>=0.4.0: Installed. No version info available.
> httpx>=0.25.2: Installed. No version info available.
> jsonpatch<2.0,>=1.33: Installed. No version info available.
> langchain-anthropic;: Installed. No version info available.
> langchain-aws;: Installed. No version info available.
> langchain-azure-ai;: Installed. No version info available.
> langchain-cohere;: Installed. No version info available.
> langchain-community;: Installed. No version info available.
> langchain-core<1.0.0,>=0.3.51: Installed. No version info available.
> langchain-core<1.0.0,>=0.3.66: Installed. No version info available.
> langchain-core<1.0.0,>=0.3.68: Installed. No version info available.
> langchain-deepseek;: Installed. No version info available.
> langchain-fireworks;: Installed. No version info available.
> langchain-google-genai;: Installed. No version info available.
> langchain-google-vertexai;: Installed. No version info available.
> langchain-groq;: Installed. No version info available.
> langchain-huggingface;: Installed. No version info available.
> langchain-mistralai;: Installed. No version info available.
> langchain-ollama;: Installed. No version info available.
> langchain-openai;: Installed. No version info available.
> langchain-perplexity;: Installed. No version info available.
> langchain-text-splitters<1.0.0,>=0.3.8: Installed. No version info available.
> langchain-together;: Installed. No version info available.
> langchain-xai;: Installed. No version info available.
> langchain<1.0.0,>=0.3.26: Installed. No version info available.
> langsmith-pyo3: Installed. No version info available.
> langsmith>=0.1.125: Installed. No version info available.
> langsmith>=0.1.17: Installed. No version info available.
> langsmith>=0.3.45: Installed. No version info available.
> numpy>=1.26.2;: Installed. No version info available.
> numpy>=2.1.0;: Installed. No version info available.
> openai-agents: Installed. No version info available.
> openai<2.0.0,>=1.86.0: Installed. No version info available.
> opentelemetry-api: 1.35.0
> opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
> opentelemetry-sdk: 1.35.0
> orjson: 3.10.18
> orjson>=3.10.1: Installed. No version info available.
> packaging: 24.2
> packaging<25,>=23.2: Installed. No version info available.
> pydantic: 2.11.7
> pydantic-settings<3.0.0,>=2.4.0: Installed. No version info available.
> pydantic<3.0.0,>=2.7.4: Installed. No version info available.
> pydantic>=2.7.4: Installed. No version info available.
> pytest: 8.4.1
> PyYAML>=5.3: Installed. No version info available.
> requests: 2.32.4
> requests-toolbelt: 1.0.0
> requests<3,>=2: Installed. No version info available.
> rich: 14.1.0
> SQLAlchemy<3,>=1.4: Installed. No version info available.
> tenacity!=8.4.0,<10,>=8.1.0: Installed. No version info available.
> tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
> tiktoken<1,>=0.7: Installed. No version info available.
> types-pyyaml: 6.0.12.20250516
> typing-extensions>=4.7: Installed. No version info available.
> zstandard: 0.23.0

Labels: bug
State: closed